teuton 2.3.5 → 2.3.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +4 -5
- data/bin/teuton +1 -1
- data/docs/CHANGELOG.md +8 -0
- data/docs/changelog/v2.4.md +16 -0
- data/docs/dsl/definition/expect.md +11 -7
- data/docs/dsl/definition/result.md +7 -6
- data/docs/dsl/definition/run_local.md +0 -1
- data/docs/dsl/definition/target.md +1 -1
- data/docs/dsl/execution/export.md +14 -16
- data/docs/dsl/execution/send.md +12 -12
- data/docs/dsl/setting/get.md +5 -5
- data/docs/es/exit_code.md +59 -0
- data/docs/es/guess_os.md +28 -0
- data/docs/{Challenge-Server-Project.md → ideas/Challenge-Server-Project.md} +0 -0
- data/docs/{changelog → ideas}/contributions.md +0 -0
- data/docs/{changelog → ideas}/ideas.md +0 -0
- data/docs/{changelog → ideas}/servidor-de-retos.md +0 -0
- data/docs/learn/{example-01-target.md → 01-target.md} +1 -3
- data/docs/learn/{example-02-config.md → 02-config.md} +1 -3
- data/docs/learn/{example-03-remote-hosts.md → 03-remote_hosts.md} +10 -10
- data/docs/learn/{example-04-new-test.md → 04-new_test.md} +8 -16
- data/docs/learn/{example-05-use.md → 05-use.md} +1 -3
- data/docs/learn/{example-06-debug.md → 06-debug.md} +1 -3
- data/docs/learn/{example-07-log.md → 07-log.md} +1 -3
- data/docs/learn/{example-08-readme.md → 08-readme.md} +1 -3
- data/docs/learn/{example-09-preserve.md → 09-preserve.md} +7 -4
- data/docs/learn/10-result.md +36 -0
- data/docs/learn/11-moodle_id.md +19 -0
- data/docs/learn/12-get_vars.md +37 -0
- data/docs/learn/13-include.md +59 -0
- data/docs/learn/16-exit_codes.md +24 -0
- data/docs/learn/README.md +19 -17
- data/lib/teuton/application.rb +24 -17
- data/lib/teuton/case_manager/case/builtin/main.rb +2 -3
- data/lib/teuton/case_manager/case/builtin/package.rb +2 -3
- data/lib/teuton/case_manager/case/builtin/service.rb +4 -5
- data/lib/teuton/case_manager/case/builtin/teuton_file.rb +3 -4
- data/lib/teuton/case_manager/case/builtin/teuton_host.rb +5 -6
- data/lib/teuton/case_manager/case/builtin/user.rb +1 -2
- data/lib/teuton/case_manager/case/case.rb +27 -27
- data/lib/teuton/case_manager/case/close.rb +2 -2
- data/lib/teuton/case_manager/case/config.rb +14 -14
- data/lib/teuton/case_manager/case/dsl/expect.rb +46 -39
- data/lib/teuton/case_manager/case/dsl/goto.rb +2 -2
- data/lib/teuton/case_manager/case/dsl/log.rb +5 -6
- data/lib/teuton/case_manager/case/dsl/macro.rb +11 -7
- data/lib/teuton/case_manager/case/dsl/main.rb +8 -8
- data/lib/teuton/case_manager/case/dsl/send.rb +12 -14
- data/lib/teuton/case_manager/case/dsl/unique.rb +1 -3
- data/lib/teuton/case_manager/case/main.rb +5 -5
- data/lib/teuton/case_manager/case/play.rb +1 -1
- data/lib/teuton/case_manager/case/result/ext_array.rb +9 -9
- data/lib/teuton/case_manager/case/result/ext_compare.rb +44 -58
- data/lib/teuton/case_manager/case/result/ext_filter.rb +20 -8
- data/lib/teuton/case_manager/case/result/result.rb +19 -18
- data/lib/teuton/case_manager/case/runner.rb +53 -60
- data/lib/teuton/case_manager/case_manager.rb +15 -15
- data/lib/teuton/case_manager/check_cases.rb +1 -4
- data/lib/teuton/case_manager/dsl.rb +5 -5
- data/lib/teuton/case_manager/export_manager.rb +8 -19
- data/lib/teuton/case_manager/hall_of_fame.rb +4 -6
- data/lib/teuton/case_manager/main.rb +4 -5
- data/lib/teuton/case_manager/report.rb +21 -16
- data/lib/teuton/case_manager/show.rb +2 -2
- data/lib/teuton/case_manager/utils.rb +13 -14
- data/lib/teuton/check/builtin.rb +5 -1
- data/lib/teuton/check/dsl.rb +10 -11
- data/lib/teuton/check/laboratory.rb +13 -15
- data/lib/teuton/check/show.rb +33 -35
- data/lib/teuton/cli.rb +31 -35
- data/lib/teuton/files/start.rb +3 -6
- data/lib/teuton/readme/dsl.rb +12 -6
- data/lib/teuton/readme/lang.rb +20 -21
- data/lib/teuton/readme/readme.rb +40 -42
- data/lib/teuton/report/close.rb +1 -8
- data/lib/teuton/report/formatter/array_formatter.rb +28 -39
- data/lib/teuton/report/formatter/base_formatter.rb +2 -13
- data/lib/teuton/report/formatter/csv_formatter.rb +12 -18
- data/lib/teuton/report/formatter/formatter_factory.rb +31 -29
- data/lib/teuton/report/formatter/html_formatter.rb +37 -21
- data/lib/teuton/report/formatter/json_formatter.rb +2 -8
- data/lib/teuton/report/formatter/list_formatter.rb +6 -12
- data/lib/teuton/report/formatter/moodle_csv_formatter.rb +3 -6
- data/lib/teuton/report/formatter/resume_array_formatter.rb +1 -1
- data/lib/teuton/report/formatter/resume_html_formatter.rb +29 -19
- data/lib/teuton/report/formatter/resume_json_formatter.rb +2 -3
- data/lib/teuton/report/formatter/resume_list_formatter.rb +4 -4
- data/lib/teuton/report/formatter/resume_txt_formatter.rb +14 -18
- data/lib/teuton/report/formatter/resume_yaml_formatter.rb +1 -9
- data/lib/teuton/report/formatter/txt_formatter.rb +19 -22
- data/lib/teuton/report/formatter/xml_formatter.rb +29 -37
- data/lib/teuton/report/formatter/yaml_formatter.rb +2 -12
- data/lib/teuton/report/report.rb +10 -10
- data/lib/teuton/report/show.rb +14 -33
- data/lib/teuton/skeleton.rb +6 -14
- data/lib/teuton/utils/configfile_reader.rb +22 -21
- data/lib/teuton/utils/name_file_finder.rb +21 -26
- data/lib/teuton/utils/verbose.rb +1 -2
- data/lib/teuton/version.rb +3 -4
- data/lib/teuton.rb +5 -6
- metadata +60 -86
- data/bin/check_teuton +0 -41
@@ -1,43 +1,33 @@
|
|
1
|
+
require "net/ssh"
|
2
|
+
require "net/sftp"
|
3
|
+
require "net/telnet"
|
4
|
+
require_relative "dsl/log"
|
1
5
|
|
2
|
-
require 'net/ssh'
|
3
|
-
require 'net/sftp'
|
4
|
-
require 'net/telnet'
|
5
|
-
require_relative 'dsl/log'
|
6
|
-
|
7
|
-
# Class Case
|
8
|
-
# * run_local_cmd
|
9
|
-
# * run_remote_cmd
|
10
|
-
# * run_remote_cmd_ssh
|
11
|
-
# * reconfigure_command_with_gateway
|
12
|
-
# * run_remote_cmd_telnet
|
13
6
|
class Case
|
14
|
-
|
15
7
|
private
|
16
8
|
|
17
9
|
def run_cmd_on(host)
|
18
10
|
protocol = @config.get("#{host}_protocol".to_sym)
|
19
11
|
ip = @config.get("#{host}_ip".to_sym)
|
20
12
|
|
21
|
-
if
|
22
|
-
run_cmd_localhost
|
23
|
-
elsif protocol.to_s.downcase ==
|
13
|
+
if protocol.to_s.downcase == "local" || host.to_s == "localhost"
|
14
|
+
run_cmd_localhost # Protocol force => local
|
15
|
+
elsif protocol.to_s.downcase == "ssh"
|
24
16
|
run_cmd_remote_ssh(host) # Protocol force => ssh
|
25
|
-
elsif protocol.to_s.downcase ==
|
26
|
-
|
27
|
-
elsif
|
28
|
-
run_cmd_localhost
|
29
|
-
elsif ip ==
|
17
|
+
elsif protocol.to_s.downcase == "telnet"
|
18
|
+
run_cmd_remote_telnet(host) # Protocol force => telnet
|
19
|
+
elsif ip.to_s.downcase == "localhost" || ip.to_s.include?("127.0.0.")
|
20
|
+
run_cmd_localhost
|
21
|
+
elsif ip == "NODATA"
|
30
22
|
log("#{host} IP not found!", :error)
|
31
23
|
else
|
32
24
|
run_cmd_remote_ssh host
|
33
25
|
end
|
34
26
|
end
|
35
27
|
|
36
|
-
|
37
|
-
# Run command on local machine
|
38
|
-
def run_cmd_localhost()
|
28
|
+
def run_cmd_localhost
|
39
29
|
@action[:conn_type] = :local
|
40
|
-
i = my_execute(
|
30
|
+
i = my_execute(@action[:command], @action[:encoding])
|
41
31
|
@result.exitstatus = i[:exitstatus]
|
42
32
|
@result.content = i[:content]
|
43
33
|
end
|
@@ -47,9 +37,9 @@ class Case
|
|
47
37
|
# @param input_hostname (Symbol or String)
|
48
38
|
def run_cmd_remote(input_hostname)
|
49
39
|
hostname = input_hostname.to_s
|
50
|
-
i = (hostname +
|
40
|
+
i = (hostname + "_protocol").to_sym
|
51
41
|
protocol = @config.get(i) if @config.get(i)
|
52
|
-
protocol = :ssh if protocol.nil? || protocol ==
|
42
|
+
protocol = :ssh if protocol.nil? || protocol == "NODATA"
|
53
43
|
protocol = protocol.to_sym
|
54
44
|
case protocol
|
55
45
|
when :ssh
|
@@ -57,7 +47,7 @@ class Case
|
|
57
47
|
when :telnet
|
58
48
|
run_cmd_remote_telnet(input_hostname)
|
59
49
|
when :local
|
60
|
-
run_cmd_localhost
|
50
|
+
run_cmd_localhost
|
61
51
|
else
|
62
52
|
log("Protocol #{protocol} unknown! Use ssh or telnet.", :error)
|
63
53
|
end
|
@@ -72,9 +62,9 @@ class Case
|
|
72
62
|
port = @config.get("#{hostname}_port".to_sym).to_i
|
73
63
|
port = 22 if port.zero?
|
74
64
|
|
75
|
-
unless @config.get("#{hostname}_route".to_sym) ==
|
65
|
+
unless @config.get("#{hostname}_route".to_sym) == "NODATA"
|
76
66
|
# Reconfigure command with gateway. Example host1_route: IP.
|
77
|
-
hostname2 = hostname
|
67
|
+
# hostname2 = hostname ¿not used?
|
78
68
|
ip2 = ip
|
79
69
|
username2 = username
|
80
70
|
password2 = password
|
@@ -85,26 +75,27 @@ class Case
|
|
85
75
|
password = @config.get("#{hostname}_password".to_sym).to_s
|
86
76
|
ostype = @config.get("#{hostname}_ostype".to_sym).to_s
|
87
77
|
|
88
|
-
if ostype.downcase.start_with?
|
89
|
-
|
90
|
-
@action[:command] = "echo y | plink #{username2}@#{ip2} -ssh -pw #{password2} \"#{command2}\""
|
78
|
+
@action[:command] = if ostype.downcase.start_with? "win"
|
79
|
+
"echo y | plink #{username2}@#{ip2} -ssh -pw #{password2} \"#{command2}\""
|
91
80
|
else
|
92
|
-
|
81
|
+
"sshpass -p #{password2} #{username2}@#{ip2} #{command2}"
|
93
82
|
end
|
94
83
|
end
|
95
84
|
|
96
|
-
text =
|
85
|
+
text = ""
|
97
86
|
begin
|
98
87
|
if @sessions[hostname].nil?
|
99
|
-
@sessions[hostname] = Net::SSH.start(
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
88
|
+
@sessions[hostname] = Net::SSH.start(
|
89
|
+
ip,
|
90
|
+
username,
|
91
|
+
port: port,
|
92
|
+
password: password,
|
93
|
+
keepalive: true,
|
94
|
+
timeout: 30,
|
95
|
+
non_interactive: true
|
96
|
+
)
|
106
97
|
end
|
107
|
-
if @sessions[hostname].
|
98
|
+
if @sessions[hostname].instance_of? Net::SSH::Connection::Session
|
108
99
|
text = @sessions[hostname].exec!(@action[:command])
|
109
100
|
end
|
110
101
|
rescue Errno::EHOSTUNREACH
|
@@ -116,18 +107,18 @@ class Case
|
|
116
107
|
@sessions[hostname] = :nosession
|
117
108
|
@conn_status[hostname] = :error_authentication_failed
|
118
109
|
verbose Rainbow(Application.instance.letter[:error]).red.bright
|
119
|
-
log(
|
110
|
+
log("SSH::AuthenticationFailed!", :error)
|
120
111
|
rescue Net::SSH::HostKeyMismatch
|
121
112
|
@sessions[hostname] = :nosession
|
122
113
|
@conn_status[hostname] = :host_key_mismatch
|
123
114
|
verbose Rainbow(Application.instance.letter[:error]).red.bright
|
124
|
-
log(
|
115
|
+
log("SSH::HostKeyMismatch!", :error)
|
125
116
|
log("* The destination server's fingerprint is not matching " \
|
126
|
-
|
127
|
-
log(
|
117
|
+
"what is in your local known_hosts file.", :error)
|
118
|
+
log("* Remove the existing entry in your local known_hosts file", :error)
|
128
119
|
log("* Try this => ssh-keygen -f '/home/USERNAME/.ssh/known_hosts' " \
|
129
120
|
"-R #{ip}", :error)
|
130
|
-
rescue
|
121
|
+
rescue => e
|
131
122
|
@sessions[hostname] = :nosession
|
132
123
|
@conn_status[hostname] = :error
|
133
124
|
verbose Rainbow(Application.instance.letter[:error]).red.bright
|
@@ -142,21 +133,23 @@ class Case
|
|
142
133
|
|
143
134
|
def run_cmd_remote_telnet(input_hostname)
|
144
135
|
@action[:conn_type] = :telnet
|
145
|
-
app = Application.instance
|
136
|
+
# app = Application.instance ¿not used?
|
146
137
|
hostname = input_hostname.to_s
|
147
|
-
ip = @config.get((hostname +
|
148
|
-
username = @config.get((hostname +
|
149
|
-
password = @config.get((hostname +
|
150
|
-
text =
|
138
|
+
ip = @config.get((hostname + "_ip").to_sym)
|
139
|
+
username = @config.get((hostname + "_username").to_sym).to_s
|
140
|
+
password = @config.get((hostname + "_password").to_sym).to_s
|
141
|
+
text = ""
|
151
142
|
begin
|
152
143
|
if @sessions[hostname].nil? || @sessions[hostname] == :ok
|
153
|
-
h = Net::Telnet.new(
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
144
|
+
h = Net::Telnet.new(
|
145
|
+
"Host" => ip,
|
146
|
+
"Timeout" => 30,
|
147
|
+
"Prompt" => /login|teuton|[$%#>]/
|
148
|
+
)
|
149
|
+
# "Prompt" => Regexp.new(username[1, 40]))
|
150
|
+
# "Prompt" => /[$%#>] \z/n)
|
158
151
|
h.login(username, password)
|
159
|
-
text =
|
152
|
+
text = ""
|
160
153
|
h.cmd(@action[:command]) { |i| text << i }
|
161
154
|
h.close
|
162
155
|
@sessions[hostname] = :ok
|
@@ -166,13 +159,13 @@ class Case
|
|
166
159
|
@conn_status[hostname] = :open_timeout
|
167
160
|
verbose Rainbow(Application.instance.letter[:error]).red.bright
|
168
161
|
log(" ExceptionType=<Net::OpenTimeout> doing <telnet #{ip}>", :error)
|
169
|
-
log(
|
162
|
+
log(" └── Revise host IP!", :warn)
|
170
163
|
rescue Net::ReadTimeout
|
171
164
|
@sessions[hostname] = :nosession
|
172
165
|
@conn_status[hostname] = :read_timeout
|
173
166
|
verbose Rainbow(Application.instance.letter[:error]).red.bright
|
174
167
|
log(" ExceptionType=<Net::ReadTimeout> doing <telnet #{ip}>", :error)
|
175
|
-
rescue
|
168
|
+
rescue => e
|
176
169
|
@sessions[hostname] = :nosession
|
177
170
|
@conn_status[hostname] = :error
|
178
171
|
verbose Rainbow(Application.instance.letter[:error]).red.bright
|
@@ -1,13 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require_relative
|
5
|
-
require_relative
|
6
|
-
require_relative
|
7
|
-
require_relative
|
8
|
-
require_relative
|
9
|
-
require_relative
|
10
|
-
require_relative
|
3
|
+
require "singleton"
|
4
|
+
require_relative "../application"
|
5
|
+
require_relative "../report/report"
|
6
|
+
require_relative "../utils/configfile_reader"
|
7
|
+
require_relative "case/case"
|
8
|
+
require_relative "export_manager"
|
9
|
+
require_relative "main"
|
10
|
+
require_relative "utils"
|
11
11
|
|
12
12
|
# This class does all the job
|
13
13
|
# Organize the hole job, sending orders to others classes
|
@@ -28,7 +28,7 @@ class CaseManager
|
|
28
28
|
def initialize
|
29
29
|
@cases = []
|
30
30
|
@report = Report.new(0)
|
31
|
-
@report.filename =
|
31
|
+
@report.filename = "resume"
|
32
32
|
end
|
33
33
|
|
34
34
|
##
|
@@ -38,10 +38,10 @@ class CaseManager
|
|
38
38
|
check_cases!
|
39
39
|
instance_eval(&block)
|
40
40
|
# Run export if user pass option command "--export=json"
|
41
|
-
i = Application.instance.options[
|
41
|
+
i = Application.instance.options["export"]
|
42
42
|
export(format: i.to_sym) unless i.nil?
|
43
43
|
# Accept "configfile" param REVISE There exists?
|
44
|
-
i = Application.instance.options[
|
44
|
+
i = Application.instance.options["configfile"]
|
45
45
|
export(format: i.to_sym) unless i.nil?
|
46
46
|
end
|
47
47
|
|
@@ -52,8 +52,8 @@ class CaseManager
|
|
52
52
|
if args.class != Hash
|
53
53
|
puts "[ERROR] CaseManager#export: Argument = <#{args}>, " \
|
54
54
|
"class = #{args.class}"
|
55
|
-
puts
|
56
|
-
raise
|
55
|
+
puts " Usage: export :format => :colored_text"
|
56
|
+
raise "[ERROR] CaseManager#export: Argument error!"
|
57
57
|
end
|
58
58
|
# Export report files
|
59
59
|
ExportManager.run(@report, @cases, args)
|
@@ -64,8 +64,8 @@ class CaseManager
|
|
64
64
|
# @param args (Hash) Send options
|
65
65
|
def send(args = {})
|
66
66
|
threads = []
|
67
|
-
puts
|
68
|
-
puts "[INFO] Sending files...#{args
|
67
|
+
puts ""
|
68
|
+
puts "[INFO] Sending files...#{args}"
|
69
69
|
@cases.each { |c| threads << Thread.new { c.send(args) } }
|
70
70
|
threads.each(&:join)
|
71
71
|
end
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
##
|
4
|
-
# CaseManager: check_cases!
|
5
3
|
class CaseManager
|
6
4
|
private
|
7
5
|
|
@@ -18,8 +16,7 @@ class CaseManager
|
|
18
16
|
app.global[:tt_sequence] = false if app.global[:tt_sequence].nil?
|
19
17
|
|
20
18
|
# Create out dir
|
21
|
-
outdir = app.global[:tt_outdir] ||
|
22
|
-
File.join('var', app.global[:tt_testname])
|
19
|
+
outdir = app.global[:tt_outdir] || File.join("var", app.global[:tt_testname])
|
23
20
|
ensure_dir outdir
|
24
21
|
@report.output_dir = outdir
|
25
22
|
|
@@ -1,10 +1,10 @@
|
|
1
|
-
require_relative
|
2
|
-
require_relative
|
1
|
+
require_relative "../application"
|
2
|
+
require_relative "case_manager"
|
3
3
|
|
4
4
|
# Define filename to be used into our test
|
5
5
|
# @param filename (String) Filename to be required
|
6
6
|
def use(filename)
|
7
|
-
filename +=
|
7
|
+
filename += ".rb"
|
8
8
|
app = Application.instance
|
9
9
|
rbfiles = File.join(app.project_path, "**", filename)
|
10
10
|
files = Dir.glob(rbfiles)
|
@@ -18,7 +18,7 @@ end
|
|
18
18
|
# @param name (String) macro name
|
19
19
|
# @param block (Block) macro code
|
20
20
|
def define_macro(name, *args, &block)
|
21
|
-
Application.instance.macros[name] = {
|
21
|
+
Application.instance.macros[name] = {args: args, block: block}
|
22
22
|
end
|
23
23
|
alias def_macro define_macro
|
24
24
|
alias defmacro define_macro
|
@@ -27,7 +27,7 @@ alias defmacro define_macro
|
|
27
27
|
# @param name (String) Group name
|
28
28
|
# @param block (Block) Tests code
|
29
29
|
def group(name, &block)
|
30
|
-
Application.instance.groups << {
|
30
|
+
Application.instance.groups << {name: name, block: block}
|
31
31
|
end
|
32
32
|
alias task group
|
33
33
|
|
@@ -1,17 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
3
|
+
require_relative "../application"
|
4
4
|
|
5
|
-
##
|
6
|
-
# ExportManager is used by CaseManager to export output reports
|
7
5
|
module ExportManager
|
8
6
|
##
|
9
7
|
# Run export function
|
10
8
|
# @param main_report (Report)
|
11
9
|
# @param cases (Array)
|
12
10
|
# @param input (Hash) Selected export options
|
13
|
-
# rubocop:disable Metrics/AbcSize
|
14
|
-
# rubocop:disable Metrics/CyclomaticComplexity
|
15
11
|
def self.run(main_report, cases, input)
|
16
12
|
args = strings2symbols(input)
|
17
13
|
|
@@ -29,42 +25,35 @@ module ExportManager
|
|
29
25
|
# Step 3: Preserve files if required
|
30
26
|
preserve_files if args[:preserve] == true
|
31
27
|
end
|
32
|
-
# rubocop:enable Metrics/AbcSize
|
33
|
-
# rubocop:enable Metrics/CyclomaticComplexity
|
34
28
|
|
35
29
|
##
|
36
30
|
# Convert Hash String values into Symbol values
|
37
31
|
# @param input (Hash)
|
38
|
-
# rubocop:disable Style/ConditionalAssignment
|
39
32
|
private_class_method def self.strings2symbols(input)
|
40
33
|
args = {}
|
41
34
|
input.each_pair do |key, value|
|
42
|
-
if value.
|
43
|
-
|
35
|
+
args[key] = if value.instance_of? String
|
36
|
+
value.to_sym
|
44
37
|
else
|
45
|
-
|
38
|
+
value
|
46
39
|
end
|
47
40
|
end
|
48
41
|
args
|
49
42
|
end
|
50
|
-
# rubocop:enable Style/ConditionalAssignment
|
51
43
|
|
52
44
|
##
|
53
45
|
# Preserve output files for current project
|
54
|
-
# rubocop:disable Metrics/AbcSize
|
55
|
-
# rubocop:disable Metrics/MethodLength
|
56
46
|
private_class_method def self.preserve_files
|
57
47
|
app = Application.instance
|
58
48
|
t = Time.now
|
59
|
-
data = {
|
60
|
-
|
61
|
-
|
62
|
-
'%<hour>02d%<min>02d%<sec>02d', data)
|
49
|
+
data = {year: t.year, month: t.month, day: t.day, hour: t.hour, min: t.min, sec: t.sec}
|
50
|
+
subdir = format("%<year>s%<month>02d%<day>02d-" \
|
51
|
+
"%<hour>02d%<min>02d%<sec>02d", data)
|
63
52
|
logdir = File.join(app.output_basedir, app.global[:tt_testname], subdir)
|
64
53
|
srcdir = File.join(app.output_basedir, app.global[:tt_testname])
|
65
54
|
puts "[INFO] Preserving files => #{logdir}"
|
66
55
|
FileUtils.mkdir(logdir)
|
67
|
-
Dir.glob(File.join(srcdir,
|
56
|
+
Dir.glob(File.join(srcdir, "**.*")).each { |file| FileUtils.cp(file, logdir) }
|
68
57
|
end
|
69
58
|
# rubocop:enable Metrics/AbcSize
|
70
59
|
# rubocop:enable Metrics/MethodLength
|
@@ -1,8 +1,6 @@
|
|
1
|
-
|
2
|
-
require_relative '../application'
|
1
|
+
require_relative "../application"
|
3
2
|
|
4
3
|
class CaseManager
|
5
|
-
|
6
4
|
private
|
7
5
|
|
8
6
|
def build_hall_of_fame
|
@@ -10,10 +8,10 @@ class CaseManager
|
|
10
8
|
|
11
9
|
@cases.each do |c|
|
12
10
|
grade = c.grade # report.tail[:grade]
|
13
|
-
if celebrities[grade]
|
14
|
-
|
11
|
+
label = if celebrities[grade]
|
12
|
+
celebrities[grade] + "*"
|
15
13
|
else
|
16
|
-
|
14
|
+
"*"
|
17
15
|
end
|
18
16
|
celebrities[grade] = label unless c.skip
|
19
17
|
end
|
@@ -1,5 +1,4 @@
|
|
1
|
-
|
2
|
-
require_relative
|
3
|
-
require_relative
|
4
|
-
require_relative
|
5
|
-
require_relative 'show'
|
1
|
+
require_relative "check_cases"
|
2
|
+
require_relative "hall_of_fame"
|
3
|
+
require_relative "report"
|
4
|
+
require_relative "show"
|
@@ -1,9 +1,6 @@
|
|
1
|
-
require
|
2
|
-
##
|
3
|
-
# Class CaseManager
|
4
|
-
# Methods related with report
|
5
|
-
class CaseManager
|
1
|
+
require "rainbow"
|
6
2
|
|
3
|
+
class CaseManager
|
7
4
|
private
|
8
5
|
|
9
6
|
##
|
@@ -27,22 +24,32 @@ class CaseManager
|
|
27
24
|
@report.tail[:finish_time] = finish_time
|
28
25
|
@report.tail[:duration] = finish_time - start_time
|
29
26
|
|
30
|
-
|
27
|
+
duration = format("%3.3f", (finish_time - start_time))
|
28
|
+
verbose Rainbow("\n==> Teuton: Duration=#{duration}").yellow.bright
|
31
29
|
verboseln Rainbow(" (#{finish_time})").yellow.bright
|
32
|
-
verboseln
|
30
|
+
verboseln " "
|
33
31
|
|
34
32
|
app = Application.instance
|
35
33
|
@cases.each do |c|
|
36
34
|
line = {}
|
37
35
|
if c.skip?
|
38
|
-
line = {
|
39
|
-
|
40
|
-
|
36
|
+
line = {
|
37
|
+
skip: true,
|
38
|
+
id: "-",
|
39
|
+
grade: 0.0,
|
40
|
+
letter: "",
|
41
|
+
members: "-",
|
42
|
+
conn_status: {},
|
43
|
+
moodle_id: "",
|
44
|
+
moodle_feedback: ""
|
45
|
+
}
|
41
46
|
else
|
42
47
|
line[:skip] = false
|
43
|
-
line[:id] = format(
|
48
|
+
line[:id] = format("%<id>02d", {id: c.id.to_i})
|
49
|
+
line[:letter] = app.letter[:cross] if c.grade.zero?
|
44
50
|
line[:letter] = app.letter[:error] if c.grade < 50.0
|
45
|
-
line[:
|
51
|
+
line[:letter] = app.letter[:ok] if c.grade.to_i == 100
|
52
|
+
line[:grade] = c.grade.to_f
|
46
53
|
line[:members] = c.members
|
47
54
|
line[:conn_status] = c.conn_status
|
48
55
|
line[:moodle_id] = c.get(:tt_moodle_id)
|
@@ -60,9 +67,7 @@ class CaseManager
|
|
60
67
|
return input unless input.to_s.start_with? Dir.pwd.to_s
|
61
68
|
return input if input == Dir.pwd.to_s
|
62
69
|
|
63
|
-
|
64
|
-
offset
|
65
|
-
output = "#{input[offset, input.size]}"
|
66
|
-
output.to_s
|
70
|
+
offset = Dir.pwd.length + 1
|
71
|
+
input[offset, input.size].to_s
|
67
72
|
end
|
68
73
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
3
|
+
require_relative "../application"
|
4
4
|
|
5
5
|
# CaseManager show method
|
6
6
|
class CaseManager
|
@@ -17,7 +17,7 @@ class CaseManager
|
|
17
17
|
return if mode == :resume
|
18
18
|
|
19
19
|
@cases.each do |c|
|
20
|
-
puts
|
20
|
+
puts "=" * 40
|
21
21
|
c.show
|
22
22
|
end
|
23
23
|
end
|
@@ -1,10 +1,9 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require 'fileutils'
|
1
|
+
require_relative "../application"
|
2
|
+
require "fileutils"
|
4
3
|
|
5
4
|
module Utils
|
6
|
-
# Create the directory if it dosn't exist.
|
7
5
|
def ensure_dir(dirname)
|
6
|
+
# Create the directory if it dosn't exist.
|
8
7
|
unless Dir.exist?(dirname)
|
9
8
|
FileUtils.mkdir_p(dirname)
|
10
9
|
return false
|
@@ -14,15 +13,15 @@ module Utils
|
|
14
13
|
|
15
14
|
def encode_and_split(encoding, text)
|
16
15
|
# Convert text to UTF-8 deleting unknown chars
|
17
|
-
text ||=
|
18
|
-
flag = [:default,
|
19
|
-
return text.encode(
|
16
|
+
text ||= "" # Ensure text is not nil
|
17
|
+
flag = [:default, "UTF-8"].include? encoding
|
18
|
+
return text.encode("UTF-8", invalid: :replace).split("\n") if flag
|
20
19
|
|
21
20
|
# Convert text from input ENCODING to UTF-8
|
22
|
-
ec = Encoding::Converter.new(encoding.to_s,
|
21
|
+
ec = Encoding::Converter.new(encoding.to_s, "UTF-8")
|
23
22
|
begin
|
24
23
|
text = ec.convert(text)
|
25
|
-
rescue
|
24
|
+
rescue => e
|
26
25
|
puts "[ERROR] #{e}: Declare text encoding..."
|
27
26
|
puts " run 'command', on: :host, :encoding => 'ISO-8859-1'"
|
28
27
|
end
|
@@ -30,18 +29,18 @@ module Utils
|
|
30
29
|
text.split("\n")
|
31
30
|
end
|
32
31
|
|
33
|
-
def my_execute(cmd, encoding =
|
34
|
-
return {
|
32
|
+
def my_execute(cmd, encoding = "UTF-8")
|
33
|
+
return {exitstatus: 0, content: ""} if Application.instance.debug
|
35
34
|
|
36
35
|
begin
|
37
36
|
text = `#{cmd}`
|
38
37
|
exitstatus = $CHILD_STATUS.exitstatus
|
39
|
-
rescue
|
40
|
-
verbose
|
38
|
+
rescue => e
|
39
|
+
verbose "!"
|
41
40
|
puts("[ERROR] #{e}: Local exec: #{cmd}")
|
42
41
|
end
|
43
42
|
content = encode_and_split(encoding, text)
|
44
|
-
{
|
43
|
+
{exitstatus: exitstatus, content: content}
|
45
44
|
end
|
46
45
|
|
47
46
|
def verboseln(text)
|
data/lib/teuton/check/builtin.rb
CHANGED
@@ -10,6 +10,10 @@ class Builtin
|
|
10
10
|
def method_missing(method)
|
11
11
|
@parent.log "BUILTIN #{method}"
|
12
12
|
end
|
13
|
+
|
14
|
+
def respond_to_missing?(_method, *)
|
15
|
+
true
|
16
|
+
end
|
13
17
|
end
|
14
18
|
|
15
19
|
# Laboratory
|
@@ -17,7 +21,7 @@ end
|
|
17
21
|
class Laboratory
|
18
22
|
def service(param)
|
19
23
|
log "BUILTIN service(#{param})"
|
20
|
-
@builtin
|
24
|
+
@builtin ||= Builtin.new(self)
|
21
25
|
@builtin.param = param
|
22
26
|
@builtin
|
23
27
|
end
|
data/lib/teuton/check/dsl.rb
CHANGED
@@ -15,7 +15,7 @@ class Laboratory
|
|
15
15
|
@stats[:targets] += 1
|
16
16
|
@targetid += 1
|
17
17
|
weight = args[:weight] || 1.0
|
18
|
-
verboseln format(
|
18
|
+
verboseln format("(%03<targetid>d) target %<desc>s", targetid: @targetid, desc: desc)
|
19
19
|
verboseln " weight #{weight}"
|
20
20
|
end
|
21
21
|
alias goal target
|
@@ -48,7 +48,7 @@ class Laboratory
|
|
48
48
|
def expect(cond)
|
49
49
|
verboseln " alter #{result.alterations}" unless result.alterations.empty?
|
50
50
|
verboseln " expect #{cond} (#{cond.class})"
|
51
|
-
verboseln
|
51
|
+
verboseln ""
|
52
52
|
end
|
53
53
|
|
54
54
|
##
|
@@ -56,7 +56,7 @@ class Laboratory
|
|
56
56
|
def expect_one(cond)
|
57
57
|
verboseln " alter #{result.alterations}" unless result.alterations.empty?
|
58
58
|
verboseln " expect_one #{cond} (#{cond.class})"
|
59
|
-
verboseln
|
59
|
+
verboseln ""
|
60
60
|
end
|
61
61
|
|
62
62
|
##
|
@@ -64,7 +64,7 @@ class Laboratory
|
|
64
64
|
def expect_none(cond)
|
65
65
|
verboseln " alter #{result.alterations}" unless result.alterations.empty?
|
66
66
|
verboseln " expect_none #{cond} (#{cond.class})"
|
67
|
-
verboseln
|
67
|
+
verboseln ""
|
68
68
|
end
|
69
69
|
|
70
70
|
##
|
@@ -85,7 +85,7 @@ class Laboratory
|
|
85
85
|
# rubocop:disable Style/MissingRespondToMissing
|
86
86
|
def method_missing(method)
|
87
87
|
a = method.to_s
|
88
|
-
instance_eval("get(:#{a[0, a.size - 1]})", __FILE__, __LINE__) if a[a.size - 1] ==
|
88
|
+
instance_eval("get(:#{a[0, a.size - 1]})", __FILE__, __LINE__) if a[a.size - 1] == "?"
|
89
89
|
end
|
90
90
|
# rubocop:enable Style/MissingRespondToMissing
|
91
91
|
|
@@ -93,8 +93,7 @@ class Laboratory
|
|
93
93
|
# Execute Teuton DSL gett keyword
|
94
94
|
# Same as get keyword, but show pretty output when used by readme command.
|
95
95
|
def gett(option)
|
96
|
-
|
97
|
-
value
|
96
|
+
get(option)
|
98
97
|
end
|
99
98
|
|
100
99
|
##
|
@@ -103,12 +102,12 @@ class Laboratory
|
|
103
102
|
@stats[:uniques] += 1
|
104
103
|
|
105
104
|
verboseln " ! Unique value for <#{key}>"
|
106
|
-
verboseln
|
105
|
+
verboseln ""
|
107
106
|
end
|
108
107
|
|
109
108
|
##
|
110
109
|
# Execute Teuton DSL log keyword
|
111
|
-
def log(text =
|
110
|
+
def log(text = "", type = :info)
|
112
111
|
@stats[:logs] += 1
|
113
112
|
verboseln " log [#{type}]: " + text.to_s
|
114
113
|
end
|
@@ -118,8 +117,8 @@ class Laboratory
|
|
118
117
|
def set(key, value)
|
119
118
|
@stats[:sets] += 1
|
120
119
|
|
121
|
-
key =
|
122
|
-
value =
|
120
|
+
key = ":" + key.to_s if key.instance_of? Symbol
|
121
|
+
value = ":" + value.to_s if value.instance_of? Symbol
|
123
122
|
|
124
123
|
@sets[key] = value
|
125
124
|
"set(#{key},#{value})"
|