teuton 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. checksums.yaml +7 -0
  2. data/bin/teuton +4 -0
  3. data/lib/teuton/application.rb +53 -0
  4. data/lib/teuton/case_manager/case/builtin/main.rb +24 -0
  5. data/lib/teuton/case_manager/case/builtin/package.rb +20 -0
  6. data/lib/teuton/case_manager/case/builtin/service.rb +32 -0
  7. data/lib/teuton/case_manager/case/builtin/user.rb +20 -0
  8. data/lib/teuton/case_manager/case/case.rb +114 -0
  9. data/lib/teuton/case_manager/case/close.rb +29 -0
  10. data/lib/teuton/case_manager/case/config.rb +76 -0
  11. data/lib/teuton/case_manager/case/dsl/check.rb +24 -0
  12. data/lib/teuton/case_manager/case/dsl/deprecated.rb +14 -0
  13. data/lib/teuton/case_manager/case/dsl/expect.rb +78 -0
  14. data/lib/teuton/case_manager/case/dsl/getset.rb +22 -0
  15. data/lib/teuton/case_manager/case/dsl/goto.rb +35 -0
  16. data/lib/teuton/case_manager/case/dsl/log.rb +14 -0
  17. data/lib/teuton/case_manager/case/dsl/main.rb +11 -0
  18. data/lib/teuton/case_manager/case/dsl/missing.rb +12 -0
  19. data/lib/teuton/case_manager/case/dsl/send.rb +69 -0
  20. data/lib/teuton/case_manager/case/dsl/target.rb +16 -0
  21. data/lib/teuton/case_manager/case/dsl/unique.rb +11 -0
  22. data/lib/teuton/case_manager/case/main.rb +7 -0
  23. data/lib/teuton/case_manager/case/play.rb +59 -0
  24. data/lib/teuton/case_manager/case/result/ext_array.rb +43 -0
  25. data/lib/teuton/case_manager/case/result/ext_compare.rb +147 -0
  26. data/lib/teuton/case_manager/case/result/ext_filter.rb +68 -0
  27. data/lib/teuton/case_manager/case/result/result.rb +73 -0
  28. data/lib/teuton/case_manager/case/runner.rb +134 -0
  29. data/lib/teuton/case_manager/case_manager.rb +76 -0
  30. data/lib/teuton/case_manager/check_cases.rb +73 -0
  31. data/lib/teuton/case_manager/dsl.rb +31 -0
  32. data/lib/teuton/case_manager/export_manager.rb +20 -0
  33. data/lib/teuton/case_manager/hall_of_fame.rb +28 -0
  34. data/lib/teuton/case_manager/main.rb +6 -0
  35. data/lib/teuton/case_manager/report.rb +52 -0
  36. data/lib/teuton/case_manager/show.rb +19 -0
  37. data/lib/teuton/case_manager/utils.rb +57 -0
  38. data/lib/teuton/command/create.rb +20 -0
  39. data/lib/teuton/command/download.rb +26 -0
  40. data/lib/teuton/command/main.rb +9 -0
  41. data/lib/teuton/command/play.rb +34 -0
  42. data/lib/teuton/command/readme.rb +23 -0
  43. data/lib/teuton/command/test.rb +35 -0
  44. data/lib/teuton/command/update.rb +27 -0
  45. data/lib/teuton/command/version.rb +13 -0
  46. data/lib/teuton/files/start.rb +13 -0
  47. data/lib/teuton/project/configfile_reader.rb +49 -0
  48. data/lib/teuton/project/laboratory/builtin.rb +23 -0
  49. data/lib/teuton/project/laboratory/dsl.rb +117 -0
  50. data/lib/teuton/project/laboratory/laboratory.rb +55 -0
  51. data/lib/teuton/project/laboratory/show.rb +161 -0
  52. data/lib/teuton/project/name_file_finder.rb +129 -0
  53. data/lib/teuton/project/project.rb +62 -0
  54. data/lib/teuton/project/project_creator.rb +79 -0
  55. data/lib/teuton/project/readme/dsl.rb +109 -0
  56. data/lib/teuton/project/readme/lang.rb +30 -0
  57. data/lib/teuton/project/readme/readme.rb +156 -0
  58. data/lib/teuton/rake_function/check.rb +39 -0
  59. data/lib/teuton/rake_function/install.rb +36 -0
  60. data/lib/teuton/report/close.rb +34 -0
  61. data/lib/teuton/report/formatter/array_formatter.rb +84 -0
  62. data/lib/teuton/report/formatter/base_formatter.rb +33 -0
  63. data/lib/teuton/report/formatter/csv_formatter.rb +31 -0
  64. data/lib/teuton/report/formatter/formatter_factory.rb +73 -0
  65. data/lib/teuton/report/formatter/html_formatter.rb +81 -0
  66. data/lib/teuton/report/formatter/json_formatter.rb +17 -0
  67. data/lib/teuton/report/formatter/list_formatter.rb +71 -0
  68. data/lib/teuton/report/formatter/moodle_csv_formatter.rb +28 -0
  69. data/lib/teuton/report/formatter/resume_array_formatter.rb +49 -0
  70. data/lib/teuton/report/formatter/resume_json_formatter.rb +16 -0
  71. data/lib/teuton/report/formatter/resume_list_formatter.rb +62 -0
  72. data/lib/teuton/report/formatter/resume_txt_formatter.rb +102 -0
  73. data/lib/teuton/report/formatter/resume_yaml_formatter.rb +16 -0
  74. data/lib/teuton/report/formatter/txt_formatter.rb +102 -0
  75. data/lib/teuton/report/formatter/xml_formatter.rb +42 -0
  76. data/lib/teuton/report/formatter/yaml_formatter.rb +18 -0
  77. data/lib/teuton/report/report.rb +55 -0
  78. data/lib/teuton/report/show.rb +111 -0
  79. data/lib/teuton/utils/verbose.rb +15 -0
  80. data/lib/teuton.rb +17 -0
  81. metadata +263 -0
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Case#DSL#unique
4
+ module DSL
5
+ def unique(key, value)
6
+ return if value.nil?
7
+
8
+ k = (key.to_s + '=' + value.to_s).to_sym
9
+ @uniques << k
10
+ end
11
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'dsl/main'
4
+ require_relative 'config'
5
+ require_relative 'close'
6
+ require_relative 'play'
7
+ require_relative 'runner'
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Case class:
4
+ # * play
5
+ # * play_in_parallel
6
+ # * play_in_sequence
7
+ # * fill_report
8
+ # * close_opened_sessions
9
+ class Case
10
+ def play
11
+ if skip?
12
+ verbose "Skipping case <#{@config.get(:tt_members)}>\n"
13
+ return false
14
+ end
15
+ # TODO: Delete old reports???
16
+ start_time = Time.now
17
+ play_in_sequence if get(:tt_sequence) == true # Play in sequence
18
+ play_in_parallel if get(:tt_sequence) != true # Play in parallel
19
+ fill_report(start_time, Time.now)
20
+ close_opened_sessions
21
+ end
22
+ alias start play
23
+
24
+ def close_opened_sessions
25
+ @sessions.each_value do |s|
26
+ s.close if s.class == Net::SSH::Connection::Session
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ def play_in_parallel
33
+ @groups.each do |t|
34
+ @action[:groupname] = t[:name]
35
+ instance_eval(&t[:block])
36
+ end
37
+ end
38
+
39
+ def play_in_sequence
40
+ verboseln "Starting case <#{@config.get(:tt_members)}>"
41
+ @groups.each do |t|
42
+ verbose "* Processing <#{t[:name]}> "
43
+ @action[:groupname] = t[:name]
44
+ instance_eval(&t[:block])
45
+ verbose "\n"
46
+ end
47
+ verboseln "\n"
48
+ end
49
+
50
+ def fill_report(start_time, finish_time)
51
+ @report.head.merge! @config.global
52
+ @report.head.merge! @config.local
53
+ @report.head.merge! @config.running
54
+ @report.tail[:case_id] = @id
55
+ @report.tail[:start_time_] = start_time
56
+ @report.tail[:finish_time] = finish_time
57
+ @report.tail[:duration] = finish_time - start_time
58
+ end
59
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This is an extension of Result class
4
+ class Result
5
+ def count
6
+ @alterations << 'count'
7
+ if @content.class == Array
8
+ @content = [@content.count]
9
+ self
10
+ elsif @content.nil?
11
+ @content = ['0']
12
+ else
13
+ @content = [@content.to_i.to_s]
14
+ end
15
+ self
16
+ end
17
+
18
+ def include?(value)
19
+ @expected = "Include <#{value}> value"
20
+ @content[0].include?(value)
21
+ end
22
+
23
+ def not_include?(value)
24
+ @expected = "Not include <#{value}> value"
25
+ !@content[0].include?(value)
26
+ end
27
+
28
+ def contain?(value)
29
+ @expected = "Contain <#{value}> value"
30
+ @content.contain? value
31
+ end
32
+
33
+ def empty
34
+ @expected = 'Empty!'
35
+ @content.empty
36
+ end
37
+
38
+ alias count! count
39
+ alias length count
40
+ alias len count
41
+ alias size count
42
+ alias empty? empty
43
+ end
@@ -0,0 +1,147 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This is an extension of Result class
4
+ class Result
5
+ def eq(input)
6
+ @expected = input
7
+
8
+ case input.class.to_s
9
+ when 'Fixnum'
10
+ value = @content[0].to_i
11
+ puts '[WARN] Fixnum class is deprecated!'
12
+ puts ' Upgrade your Ruby version.'
13
+ when 'Float'
14
+ value = @content[0].to_f
15
+ when 'Integer'
16
+ value = @content[0].to_i
17
+ when 'String'
18
+ value = @content[0].to_s
19
+ else
20
+ value = @content[0]
21
+ end
22
+ value == input
23
+ end
24
+ alias eq? eq
25
+ alias equal eq
26
+ alias equal? eq
27
+ alias is_equal? eq
28
+
29
+ def neq(external)
30
+ @expected = "Not equal to #{external}"
31
+
32
+ case external.class.to_s
33
+ when 'Fixnum'
34
+ internal = @content[0].to_i
35
+ puts '[WARN] Fixnum class is deprecated!'
36
+ puts ' Upgrade your Ruby version.'
37
+ when 'Float'
38
+ internal = @content[0].to_f
39
+ when 'Integer'
40
+ internal = @content[0].to_i
41
+ else
42
+ internal = @content[0]
43
+ end
44
+ internal != external
45
+ end
46
+ alias neq? neq
47
+ alias not_equal neq
48
+ alias not_equal? neq
49
+
50
+ def ge(input)
51
+ @expected = "Greater or equal to #{input}"
52
+ return false if @content.nil? || @content[0].nil?
53
+
54
+ value = @content[0]
55
+ case input.class.to_s
56
+ when 'Fixnum'
57
+ value = @content[0].to_i
58
+ puts '[WARN] Fixnum class is deprecated!'
59
+ puts ' Upgrade your Ruby version.'
60
+ when 'Float'
61
+ value = @content[0].to_f
62
+ when 'Integer'
63
+ value = @content[0].to_i
64
+ end
65
+ value >= input
66
+ end
67
+ alias greater_or_equal ge
68
+ alias greater_or_equal? ge
69
+
70
+ def gt(input)
71
+ @expected = "Greater than #{input}"
72
+ return false if @content.nil? || @content[0].nil?
73
+
74
+ value = @content[0]
75
+ case input.class.to_s
76
+ when 'Fixnum'
77
+ value = @content[0].to_i
78
+ puts '[WARN] Fixnum class is deprecated!'
79
+ puts ' Upgrade your Ruby version.'
80
+ when 'Float'
81
+ value = @content[0].to_f
82
+ when 'Integer'
83
+ value = @content[0].to_i
84
+ end
85
+ value > input
86
+ end
87
+ alias greater gt
88
+ alias greater_than gt
89
+
90
+ def le(input)
91
+ @expected = "Lesser or equal to #{input}"
92
+
93
+ return false if @content.nil? || @content[0].nil?
94
+
95
+ value = @content[0]
96
+ case input.class.to_s
97
+ when 'Fixnum'
98
+ value = @content[0].to_i
99
+ puts '[WARN] Fixnum class is deprecated!'
100
+ puts ' Upgrade your Ruby version.'
101
+ when 'Float'
102
+ value = @content[0].to_f
103
+ when 'Integer'
104
+ value = @content[0].to_i
105
+ end
106
+ value <= input
107
+ end
108
+ alias lesser_or_equal le
109
+ alias lesser_or_equal? le
110
+
111
+ def lt(input)
112
+ @expected = "Lesser than #{input}"
113
+ return false if @content.nil? || @content[0].nil?
114
+
115
+ value = @content[0]
116
+ case input.class.to_s
117
+ when 'Fixnum'
118
+ value = @content[0].to_i
119
+ puts '[WARN] Fixnum class is deprecated!'
120
+ puts ' Upgrade your Ruby version.'
121
+ when 'Float'
122
+ value = @content[0].to_f
123
+ when 'Integer'
124
+ value = @content[0].to_i
125
+ end
126
+ value < input
127
+ end
128
+ alias lesser lt
129
+ alias smaller lt
130
+ alias lesser_than lt
131
+
132
+ # Return 'true' if the parameter value is near to the target value.
133
+ # To get this we consider a 10% desviation or less, as an acceptable result.
134
+ def near_to?(input)
135
+ @expected = "Is near to #{input}"
136
+ return false if @content.nil?
137
+
138
+ target = @content[0].to_f
139
+ desv = (target * 10.0) / 100.0
140
+ return true if (target - input.to_f).abs.to_f <= desv
141
+
142
+ false
143
+ end
144
+ alias near_to near_to?
145
+ alias near? near_to?
146
+ alias near near_to?
147
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This is an extension of Result class
4
+ class Result
5
+ # TODO: Error line 102 undefined include? method for 0 Fixnum...
6
+ def find(filter)
7
+ @alterations << "find(#{filter})"
8
+ case filter.class.to_s
9
+ when 'Array'
10
+ find_when_array(filter)
11
+ when 'String' || 'Integer'
12
+ @content.select! { |i| i.include?(filter.to_s) }
13
+ when 'Regexp'
14
+ @content.select! { |i| filter.match(i) }
15
+ end
16
+ self
17
+ end
18
+ alias grep find
19
+ alias grep! find
20
+ alias find! find
21
+
22
+ def not_find(p_filter)
23
+ @alterations << "not_find(#{p_filter})"
24
+ return self if @content.size.zero?
25
+
26
+ @content.reject! { |i| i.include?(p_filter) }
27
+ self
28
+ end
29
+ alias grep_v not_find
30
+
31
+ def since(filter)
32
+ @alterations << "since(#{filter})"
33
+ return self if @content.size.zero?
34
+
35
+ if filter.class == String
36
+ flag = false
37
+ @content.select! do |i|
38
+ flag = true if i.include?(filter.to_s)
39
+ flag
40
+ end
41
+ end
42
+ self
43
+ end
44
+
45
+ def until(filter)
46
+ @alterations << "until(#{filter})"
47
+ return self if @content.size.zero?
48
+
49
+ if filter.class == String
50
+ flag = true
51
+ @content.select! do |i|
52
+ flag = false if i.include?(filter.to_s)
53
+ flag
54
+ end
55
+ end
56
+ self
57
+ end
58
+
59
+ private
60
+
61
+ def find_when_array(filter)
62
+ @content.select! do |line|
63
+ flag = false
64
+ filter.each { |i| flag ||= line.include?(i) }
65
+ flag
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'ext_array'
4
+ require_relative 'ext_compare'
5
+ require_relative 'ext_filter'
6
+
7
+ # This object contains data returned by remote/local execution
8
+ # * initialize
9
+ # * alterations
10
+ # * content
11
+ # * debug
12
+ # * ok?
13
+ # * reset
14
+ # * restore
15
+ # * value
16
+ class Result
17
+ attr_reader :content
18
+ attr_accessor :exitstatus
19
+
20
+ def initialize
21
+ reset
22
+ end
23
+
24
+ def alterations
25
+ @alterations.join(' & ')
26
+ end
27
+
28
+ def content=(content)
29
+ @content_backup = content.clone
30
+ @content = content.clone
31
+ end
32
+
33
+ def reset
34
+ @content_backup = []
35
+ @content = []
36
+ @exitstatus = nil
37
+ @value = nil
38
+ @expected = nil
39
+ @alterations = []
40
+ end
41
+
42
+ def debug
43
+ print "\n" + '*' * 20
44
+ print " [DEBUG] count=#{@content.count} "
45
+ puts '*' * 20
46
+ @content.each_with_index do |item, index|
47
+ puts format('%2d: %s', index, item)
48
+ end
49
+ puts '*' * 57
50
+ end
51
+
52
+ def expected
53
+ @expected.to_s
54
+ end
55
+
56
+ def ok?
57
+ return false if @exitstatus.nil?
58
+
59
+ @exitstatus.zero?
60
+ end
61
+
62
+ def restore
63
+ temp = @content_backup.clone
64
+ reset
65
+ @content_backup = temp
66
+ @content = temp.clone
67
+ end
68
+ alias restore! restore
69
+
70
+ def value
71
+ @content[0]
72
+ end
73
+ end
@@ -0,0 +1,134 @@
1
+
2
+ require 'net/ssh'
3
+ require 'net/sftp'
4
+ require 'net/telnet'
5
+
6
+ # Class Case
7
+ # * run_local_cmd
8
+ # * run_remote_cmd
9
+ # * run_remote_cmd_ssh
10
+ # * run_remote_cmd_telnet
11
+ class Case
12
+
13
+ private
14
+
15
+ def run_local_cmd()
16
+ @action[:conn_type] = :local
17
+ i = my_execute( @action[:command], @action[:encoding] )
18
+ @result.exitstatus = i[:exitstatus]
19
+ @result.content = i[:content]
20
+ end
21
+
22
+ def run_remote_cmd(input_hostname)
23
+ hostname = input_hostname.to_s
24
+ i = (hostname + '_protocol').to_sym
25
+ protocol = @config.get(i) if @config.get(i)
26
+ protocol = :ssh if protocol.nil? || protocol == 'NODATA'
27
+ protocol = protocol.to_sym
28
+ case protocol
29
+ when :ssh
30
+ run_remote_cmd_ssh(input_hostname)
31
+ when :telnet
32
+ run_remote_cmd_telnet(input_hostname)
33
+ else
34
+ log("Protocol #{protocol} unknown! Use ssh or telnet.", :error)
35
+ end
36
+ end
37
+
38
+ def run_remote_cmd_ssh(input_hostname)
39
+ @action[:conn_type] = :ssh
40
+ hostname = input_hostname.to_s
41
+ ip = @config.get((hostname + '_ip').to_sym)
42
+ username = @config.get((hostname + '_username').to_sym).to_s
43
+ password = @config.get((hostname + '_password').to_sym).to_s
44
+ text = ''
45
+ begin
46
+ if @sessions[hostname].nil?
47
+ @sessions[hostname] = Net::SSH.start(ip,
48
+ username,
49
+ password: password,
50
+ keepalive: true,
51
+ timeout: 30,
52
+ non_interactive: true)
53
+ end
54
+ if @sessions[hostname].class == Net::SSH::Connection::Session
55
+ text = @sessions[hostname].exec!(@action[:command].to_s)
56
+ end
57
+ rescue Errno::EHOSTUNREACH
58
+ @sessions[hostname] = :nosession
59
+ @conn_status[hostname] = :host_unreachable
60
+ verbose Application.instance.letter[:error]
61
+ log("Host #{ip} unreachable!", :error)
62
+ rescue Net::SSH::AuthenticationFailed
63
+ @sessions[hostname] = :nosession
64
+ @conn_status[hostname] = :error_authentication_failed
65
+ verbose Application.instance.letter[:error]
66
+ log('SSH::AuthenticationFailed!', :error)
67
+ rescue Net::SSH::HostKeyMismatch
68
+ @sessions[hostname] = :nosession
69
+ @conn_status[hostname] = :host_key_mismatch
70
+ verbose Application.instance.letter[:error]
71
+ log('SSH::HostKeyMismatch!', :error)
72
+ log("* The destination server's fingerprint is not matching " \
73
+ 'what is in your local known_hosts file.', :error)
74
+ log('* Remove the existing entry in your local known_hosts file', :error)
75
+ log("* Try this => ssh-keygen -f '/home/USERNAME/.ssh/known_hosts' " \
76
+ "-R #{ip}", :error)
77
+ rescue StandardError => e
78
+ @sessions[hostname] = :nosession
79
+ @conn_status[hostname] = :error
80
+ verbose Application.instance.letter[:error]
81
+ log("[#{e.class}] SSH on <#{username}@#{ip}>" \
82
+ " exec: #{@action[:command]}", :error)
83
+ end
84
+ output = encode_and_split(@action[:encoding], text)
85
+ @result.content = output
86
+ @result.content.compact!
87
+ end
88
+
89
+ def run_remote_cmd_telnet(input_hostname)
90
+ @action[:conn_type] = :telnet
91
+ app = Application.instance
92
+ hostname = input_hostname.to_s
93
+ ip = @config.get((hostname + '_ip').to_sym)
94
+ username = @config.get((hostname + '_username').to_sym).to_s
95
+ password = @config.get((hostname + '_password').to_sym).to_s
96
+ text = ''
97
+ begin
98
+ if @sessions[hostname].nil? || @sessions[hostname] == :ok
99
+ h = Net::Telnet.new( 'Host' => ip,
100
+ 'Timeout' => 30,
101
+ 'Prompt' => /login|teuton|[$%#>]/ )
102
+ # 'Prompt' => Regexp.new(username[1, 40]))
103
+ # 'Prompt' => /[$%#>] \z/n)
104
+ h.login(username, password)
105
+ text = ''
106
+ h.cmd(@action[:command]) { |i| text << i }
107
+ h.close
108
+ @sessions[hostname] = :ok
109
+ end
110
+ rescue Net::OpenTimeout
111
+ @sessions[hostname] = :nosession
112
+ @conn_status[hostname] = :open_timeout
113
+ verbose Application.instance.letter[:error]
114
+ log(" ExceptionType=<Net::OpenTimeout> doing <telnet #{ip}>", :error)
115
+ log(' └── Revise host IP!', :warn)
116
+ rescue Net::ReadTimeout
117
+ @sessions[hostname] = :nosession
118
+ @conn_status[hostname] = :read_timeout
119
+ verbose Application.instance.letter[:error]
120
+ log(" ExceptionType=<Net::ReadTimeout> doing <telnet #{ip}>", :error)
121
+ rescue StandardError => e
122
+ @sessions[hostname] = :nosession
123
+ @conn_status[hostname] = :error
124
+ verbose Application.instance.letter[:error]
125
+ log(" ExceptionType=<#{e.class}> doing telnet on <#{username}@#{ip}>" \
126
+ " exec: #{@action[:command]}", :error)
127
+ log(" └── username=<#{username}>, password=<#{password}>," \
128
+ " ip=<#{ip}>, HOSTID=<#{hostname}>", :warn)
129
+ end
130
+ output = encode_and_split(@action[:encoding], text)
131
+ @result.content = output
132
+ @result.content.compact!
133
+ end
134
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'singleton'
4
+ require_relative '../application'
5
+ require_relative '../report/report'
6
+ require_relative '../project/configfile_reader'
7
+ require_relative 'case/case'
8
+ require_relative 'export_manager'
9
+ require_relative 'main'
10
+ require_relative 'utils'
11
+
12
+ # This class does all the job
13
+ # Organize the hole job, sending orders to others classes
14
+ # * initialize
15
+ # * play
16
+ # Split into several files:
17
+ # * case_manager/check_cases
18
+ # * case_manager/export
19
+ # * case_manager/hall_of_fame
20
+ # * case_manager/report
21
+ # * case_manager/show
22
+ class CaseManager
23
+ include Singleton
24
+ include Utils
25
+
26
+ def initialize
27
+ @cases = []
28
+ @report = Report.new(0)
29
+ @report.filename = 'resume'
30
+ end
31
+
32
+ def play(&block)
33
+ check_cases!
34
+ instance_eval(&block)
35
+ # Run export if user pass option command "--export=json"
36
+ i = Application.instance.options['export']
37
+ export(format: i.to_sym) unless i.nil?
38
+ # Accept "configfile" param REVISE There exists?
39
+ i = Application.instance.options['configfile']
40
+ export(format: i.to_sym) unless i.nil?
41
+ end
42
+
43
+ def export(args = {})
44
+ if args.class != Hash
45
+ puts "[ERROR] CaseManager#export: Argument = <#{args}>, " \
46
+ "class = #{args.class}"
47
+ puts ' Usage: export :format => :colored_text'
48
+ raise '[ERROR] CaseManager#export: Argument error!'
49
+ end
50
+ ExportManager.run(@report, @cases, args)
51
+ preserve_files if args[:preserve] == true
52
+ end
53
+
54
+ def preserve_files
55
+ app = Application.instance
56
+ t = Time.now
57
+ subdir = "#{t.year}#{format('%02d',t.month)}#{format('%02d',t.day)}-" \
58
+ "#{format('%02d',t.hour)}#{format('%02d',t.min)}" \
59
+ "#{format('%02d',t.sec)}"
60
+ logdir = File.join(app.output_basedir, app.global[:tt_testname], subdir)
61
+ srcdir = File.join(app.output_basedir, app.global[:tt_testname])
62
+ puts "[INFO] Preserving files => #{logdir}"
63
+ FileUtils.mkdir(logdir)
64
+ Dir.glob('var/learn-08-preserve/**.*').each do |file|
65
+ FileUtils.cp(file, logdir)
66
+ end
67
+ end
68
+
69
+ def send(args = {})
70
+ threads = []
71
+ puts ''
72
+ puts "[INFO] Sending files...#{args.to_s}"
73
+ @cases.each { |c| threads << Thread.new { c.send(args) } }
74
+ threads.each(&:join)
75
+ end
76
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ # CaseManager#check_cases!
4
+ class CaseManager
5
+ private
6
+
7
+ def check_cases!
8
+ app = Application.instance
9
+
10
+ # Load configurations from config file
11
+ configdata = ConfigFileReader.read(app.config_path)
12
+ app.ialias = configdata[:alias]
13
+ app.global = configdata[:global]
14
+ app.global[:tt_testname] = app.global[:tt_testname] || app.test_name
15
+ app.global[:tt_sequence] = false if app.global[:tt_sequence].nil?
16
+
17
+ # Create out dir
18
+ outdir = app.global[:tt_outdir] ||
19
+ File.join('var', app.global[:tt_testname])
20
+ ensure_dir outdir
21
+ @report.output_dir = outdir
22
+
23
+ # Fill report head
24
+ open_main_report(app.config_path)
25
+
26
+ # create cases and run
27
+ configdata[:cases].each { |config| @cases << Case.new(config) }
28
+ start_time = run_all_cases # run cases
29
+
30
+ uniques = collect_uniques_for_all_cases
31
+ close_reports_for_all_cases(uniques)
32
+ close_main_report(start_time)
33
+ end
34
+
35
+ def run_all_cases
36
+ start_time = Time.now
37
+ if Application.instance.global[:tt_sequence]
38
+ verboseln "[INFO] Running in sequence (#{start_time})"
39
+ # Run every case in sequence
40
+ @cases.each(&:play)
41
+ else
42
+ verboseln "[INFO] Running in parallel (#{start_time})"
43
+ threads = []
44
+ # Run all cases in parallel
45
+ @cases.each { |c| threads << Thread.new { c.play } }
46
+ threads.each(&:join)
47
+ end
48
+ start_time
49
+ end
50
+
51
+ def collect_uniques_for_all_cases
52
+ uniques = {} # Collect "unique" values from all cases
53
+ @cases.each do |c|
54
+ c.uniques.each do |key|
55
+ if uniques[key].nil?
56
+ uniques[key] = [c.id]
57
+ else
58
+ uniques[key] << c.id
59
+ end
60
+ end
61
+ end
62
+ uniques
63
+ end
64
+
65
+ def close_reports_for_all_cases(uniques)
66
+ threads = []
67
+ @cases.each { |c| threads << Thread.new { c.close uniques } }
68
+ threads.each(&:join)
69
+
70
+ # Build Hall of Fame
71
+ build_hall_of_fame
72
+ end
73
+ end