teuton 2.5.0 → 2.7.0
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.
- checksums.yaml +4 -4
- data/docs/CHANGELOG.md +2 -0
- data/docs/changelog/todo.md +4 -6
- data/docs/changelog/v2.6.md +4 -0
- data/docs/changelog/v2.7.md +11 -0
- data/docs/diagram.md +55 -0
- data/docs/learn/02-target.md +37 -12
- data/docs/learn/03-remote_hosts.md +1 -1
- data/docs/learn/04-config.md +1 -1
- data/docs/learn/06-cmd_check.md +4 -6
- data/docs/learn/07-target_weight.md +1 -3
- data/docs/learn/21-exit_codes.md +9 -16
- data/docs/learn/README.md +1 -1
- data/lib/teuton/case/case.rb +95 -0
- data/lib/teuton/{case_manager/case → case}/close.rb +2 -0
- data/lib/teuton/{case_manager/case → case}/config.rb +3 -3
- data/lib/teuton/{case_manager/case → case/deprecated}/runner.rb +14 -10
- data/lib/teuton/case/deprecated/utils.rb +40 -0
- data/lib/teuton/{case_manager/case/dsl/main.rb → case/dsl/all.rb} +0 -2
- data/lib/teuton/{case_manager/case → case}/dsl/expect.rb +25 -9
- data/lib/teuton/{case_manager/case → case}/dsl/goto.rb +10 -9
- data/lib/teuton/{case_manager/case → case}/dsl/log.rb +1 -2
- data/lib/teuton/{case_manager/case → case}/dsl/macro.rb +2 -2
- data/lib/teuton/{case_manager/case → case}/dsl/send.rb +3 -8
- data/lib/teuton/case/execute/execute_base.rb +55 -0
- data/lib/teuton/case/execute/execute_local.rb +29 -0
- data/lib/teuton/case/execute/execute_manager.rb +56 -0
- data/lib/teuton/case/execute/execute_ssh.rb +90 -0
- data/lib/teuton/case/execute/execute_telnet.rb +56 -0
- data/lib/teuton/{case_manager/case → case}/play.rb +11 -14
- data/lib/teuton/case_manager/case_manager.rb +20 -39
- data/lib/teuton/case_manager/check_cases.rb +14 -12
- data/lib/teuton/case_manager/dsl.rb +7 -9
- data/lib/teuton/case_manager/export_manager.rb +19 -6
- data/lib/teuton/case_manager/hall_of_fame.rb +9 -10
- data/lib/teuton/case_manager/report.rb +11 -9
- data/lib/teuton/case_manager/send_manager.rb +17 -0
- data/lib/teuton/{report/show.rb → case_manager/show_report.rb} +4 -6
- data/lib/teuton/case_manager/utils.rb +2 -43
- data/lib/teuton/check/dsl.rb +1 -2
- data/lib/teuton/check/laboratory.rb +7 -7
- data/lib/teuton/check/show.rb +5 -8
- data/lib/teuton/cli.rb +10 -0
- data/lib/teuton/readme/dsl.rb +5 -7
- data/lib/teuton/readme/lang.rb +3 -2
- data/lib/teuton/readme/readme.rb +15 -18
- data/lib/teuton/report/formatter/default/array.rb +6 -5
- data/lib/teuton/report/formatter/default/txt.rb +1 -0
- data/lib/teuton/report/formatter/resume/array.rb +3 -3
- data/lib/teuton/report/formatter/resume/html.rb +2 -2
- data/lib/teuton/report/report.rb +6 -5
- data/lib/teuton/skeleton.rb +8 -10
- data/lib/teuton/{application.rb → utils/application.rb} +13 -5
- data/lib/teuton/utils/name_file_finder.rb +40 -45
- data/lib/teuton/utils/project.rb +73 -0
- data/lib/teuton/{case_manager/case → utils}/result/ext_array.rb +5 -5
- data/lib/teuton/{case_manager/case → utils}/result/result.rb +10 -8
- data/lib/teuton/utils/settings.rb +12 -0
- data/lib/teuton/utils/verbose.rb +2 -2
- data/lib/teuton/version.rb +1 -1
- data/lib/teuton.rb +28 -27
- metadata +43 -30
- data/lib/teuton/case_manager/case/case.rb +0 -117
- data/lib/teuton/case_manager/case/main.rb +0 -7
- data/lib/teuton/case_manager/main.rb +0 -3
- /data/lib/teuton/{case_manager/case → case}/builtin/main.rb +0 -0
- /data/lib/teuton/{case_manager/case → case}/builtin/package.rb +0 -0
- /data/lib/teuton/{case_manager/case → case}/builtin/service.rb +0 -0
- /data/lib/teuton/{case_manager/case → case}/builtin/teuton_file.rb +0 -0
- /data/lib/teuton/{case_manager/case → case}/builtin/teuton_host.rb +0 -0
- /data/lib/teuton/{case_manager/case → case}/builtin/user.rb +0 -0
- /data/lib/teuton/{case_manager/case → case}/dsl/getset.rb +0 -0
- /data/lib/teuton/{case_manager/case → case}/dsl/target.rb +0 -0
- /data/lib/teuton/{case_manager/case → case}/dsl/unique.rb +0 -0
- /data/lib/teuton/{case_manager/case → utils}/result/ext_compare.rb +0 -0
- /data/lib/teuton/{case_manager/case → utils}/result/ext_filter.rb +0 -0
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative "../
|
|
3
|
+
require_relative "../execute/execute_manager"
|
|
4
4
|
|
|
5
|
-
# Case class -> DSL module:
|
|
6
|
-
# * goto
|
|
7
|
-
# * run
|
|
8
5
|
module DSL
|
|
9
6
|
##
|
|
10
|
-
#
|
|
7
|
+
# DSL run and goto
|
|
8
|
+
# run: It's the same as goto :localhost
|
|
11
9
|
# @param command (String)
|
|
12
10
|
# @param args (Hash)
|
|
13
11
|
def run(command, args = {})
|
|
@@ -17,7 +15,7 @@ module DSL
|
|
|
17
15
|
goto(host, args)
|
|
18
16
|
end
|
|
19
17
|
|
|
20
|
-
# Run command from the host identify as
|
|
18
|
+
# Run command from the host identify as "host"
|
|
21
19
|
# goto :host1, :execute => "command"
|
|
22
20
|
def goto(host = :localhost, args = {})
|
|
23
21
|
@result.reset
|
|
@@ -27,9 +25,12 @@ module DSL
|
|
|
27
25
|
tempfile(args[:tempfile]) if args[:tempfile]
|
|
28
26
|
@action[:encoding] = args[:encoding] || "UTF-8"
|
|
29
27
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
ExecuteManager.new(self).call(host)
|
|
29
|
+
@action[:output] = if @result.content.size < 2
|
|
30
|
+
@result.value.clone
|
|
31
|
+
else
|
|
32
|
+
"(#{@result.content.size} lines)"
|
|
33
|
+
end
|
|
33
34
|
end
|
|
34
35
|
alias_method :on, :goto
|
|
35
36
|
end
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative "
|
|
3
|
+
require_relative "../../utils/project"
|
|
4
4
|
|
|
5
5
|
# DSL module methods: assert, missing_method
|
|
6
6
|
module DSL
|
|
@@ -9,7 +9,7 @@ module DSL
|
|
|
9
9
|
# @param name (String) Macro name
|
|
10
10
|
# @param input (Hash) Macro params
|
|
11
11
|
def macro(name, input = {})
|
|
12
|
-
macros =
|
|
12
|
+
macros = Project.value[:macros]
|
|
13
13
|
unless macros[name]
|
|
14
14
|
log("Macro #{name} not found!", :error)
|
|
15
15
|
return
|
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# Case->DSL#
|
|
4
|
-
# * send
|
|
5
|
-
# * tempfile
|
|
6
|
-
# * tempdir
|
|
7
|
-
# * remote_tempdir
|
|
8
|
-
# * remote_tempfile
|
|
9
3
|
module DSL
|
|
4
|
+
# * send, tempfile, tempdir, remote_tempdir, remote_tempfile
|
|
10
5
|
def send(args = {})
|
|
11
6
|
return if skip?
|
|
12
7
|
|
|
@@ -52,7 +47,7 @@ module DSL
|
|
|
52
47
|
name = "teuton.tmp" if input == :default
|
|
53
48
|
|
|
54
49
|
@action[:tempfile] = File.join(@tmpdir, name)
|
|
55
|
-
@action[:remote_tempfile] = File.join(
|
|
50
|
+
@action[:remote_tempfile] = File.join(remote_tempdir, name)
|
|
56
51
|
|
|
57
52
|
@action[:tempfile]
|
|
58
53
|
end
|
|
@@ -66,6 +61,6 @@ module DSL
|
|
|
66
61
|
end
|
|
67
62
|
|
|
68
63
|
def remote_tempdir
|
|
69
|
-
|
|
64
|
+
File.join("/", "tmp") # TODO: Remove this?
|
|
70
65
|
end
|
|
71
66
|
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
require_relative "../../utils/verbose"
|
|
2
|
+
|
|
3
|
+
class ExecuteBase
|
|
4
|
+
include Verbose
|
|
5
|
+
|
|
6
|
+
def initialize(parent)
|
|
7
|
+
@parent = parent
|
|
8
|
+
# READ: @config, cmd = action[:command]
|
|
9
|
+
# WRITE: @action, @result, @session
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
def config
|
|
15
|
+
@parent.config
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def action
|
|
19
|
+
@parent.action
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def result
|
|
23
|
+
@parent.result
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def sessions
|
|
27
|
+
@parent.sessions
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def log(...)
|
|
31
|
+
@parent.log(...)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def conn_status
|
|
35
|
+
@parent.conn_status
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def encode_and_split(encoding, text)
|
|
39
|
+
# Convert text to UTF-8 deleting unknown chars
|
|
40
|
+
text ||= "" # Ensure text is not nil
|
|
41
|
+
flag = [:default, "UTF-8"].include? encoding
|
|
42
|
+
return text.encode("UTF-8", invalid: :replace).split("\n") if flag
|
|
43
|
+
|
|
44
|
+
# Convert text from input ENCODING to UTF-8
|
|
45
|
+
ec = Encoding::Converter.new(encoding.to_s, "UTF-8")
|
|
46
|
+
begin
|
|
47
|
+
text = ec.convert(text)
|
|
48
|
+
rescue => e
|
|
49
|
+
puts "[ERROR] #{e}: Declare text encoding..."
|
|
50
|
+
puts " run 'command', on: :host, :encoding => 'ISO-8859-1'"
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
text.split("\n")
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
require "open3"
|
|
2
|
+
require "rainbow"
|
|
3
|
+
require_relative "../../utils/project"
|
|
4
|
+
require_relative "../../utils/verbose"
|
|
5
|
+
require_relative "execute_base"
|
|
6
|
+
|
|
7
|
+
class ExecuteLocal < ExecuteBase
|
|
8
|
+
def call
|
|
9
|
+
action[:conn_type] = :local
|
|
10
|
+
response = my_execute(action[:command], action[:encoding])
|
|
11
|
+
result.exitcode = response[:exitcode]
|
|
12
|
+
result.content = response[:content]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def my_execute(cmd, encoding = "UTF-8")
|
|
16
|
+
return {exitcode: 0, content: ""} if Project.debug?
|
|
17
|
+
|
|
18
|
+
begin
|
|
19
|
+
text, status = Open3.capture2e(cmd)
|
|
20
|
+
exitcode = status.exitstatus
|
|
21
|
+
rescue => e
|
|
22
|
+
verbose Rainbow("!").green
|
|
23
|
+
text = e.to_s
|
|
24
|
+
exitcode = 1
|
|
25
|
+
end
|
|
26
|
+
content = encode_and_split(encoding, text)
|
|
27
|
+
{exitcode: exitcode, content: content}
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
require_relative "execute_local"
|
|
2
|
+
require_relative "execute_ssh"
|
|
3
|
+
require_relative "execute_telnet"
|
|
4
|
+
|
|
5
|
+
class ExecuteManager
|
|
6
|
+
def initialize(parent)
|
|
7
|
+
@parent = parent
|
|
8
|
+
# READ: @config, cmd = action[:command]
|
|
9
|
+
# WRITE: @action, @result, @session
|
|
10
|
+
# my_execute, encode_and_split methods?
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def call(host)
|
|
14
|
+
start_time = Time.now
|
|
15
|
+
run_on(host)
|
|
16
|
+
action[:duration] = (Time.now - start_time).round(3)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def action
|
|
22
|
+
@parent.action
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def config
|
|
26
|
+
@parent.config
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def log
|
|
30
|
+
@parent.log
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def run_on(host)
|
|
34
|
+
protocol = config.get("#{host}_protocol".to_sym)
|
|
35
|
+
ip = config.get("#{host}_ip".to_sym)
|
|
36
|
+
|
|
37
|
+
if protocol.to_s.downcase == "local" || host.to_s == "localhost"
|
|
38
|
+
# Protocol force => local
|
|
39
|
+
ExecuteLocal.new(@parent).call
|
|
40
|
+
elsif protocol.to_s.downcase == "ssh"
|
|
41
|
+
# Protocol force => ssh
|
|
42
|
+
ExecuteSSH.new(@parent).call(host)
|
|
43
|
+
elsif protocol.to_s.downcase == "telnet"
|
|
44
|
+
# Protocol force => telnet
|
|
45
|
+
ExecuteTelnet.new(@parent).call(host)
|
|
46
|
+
elsif ip.to_s.downcase == "localhost" || ip.to_s.include?("127.0.0.")
|
|
47
|
+
# run_cmd_localhost
|
|
48
|
+
ExecuteLocal.new(@parent).call
|
|
49
|
+
elsif ip == "NODATA"
|
|
50
|
+
log("#{host} IP not found!", :error)
|
|
51
|
+
else
|
|
52
|
+
# run_cmd_remote_ssh host
|
|
53
|
+
ExecuteSSH.new(@parent).call(host)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
require "net/ssh"
|
|
2
|
+
require "net/sftp"
|
|
3
|
+
require "rainbow"
|
|
4
|
+
require_relative "../../utils/project"
|
|
5
|
+
require_relative "../../utils/verbose"
|
|
6
|
+
require_relative "execute_base"
|
|
7
|
+
|
|
8
|
+
class ExecuteSSH < ExecuteBase
|
|
9
|
+
def call(input_hostname)
|
|
10
|
+
action[:conn_type] = :ssh
|
|
11
|
+
hostname = input_hostname.to_s
|
|
12
|
+
ip = config.get("#{hostname}_ip".to_sym).to_s
|
|
13
|
+
username = config.get("#{hostname}_username".to_sym).to_s
|
|
14
|
+
password = config.get("#{hostname}_password".to_sym).to_s
|
|
15
|
+
port = config.get("#{hostname}_port".to_sym).to_i
|
|
16
|
+
port = 22 if port.zero?
|
|
17
|
+
|
|
18
|
+
unless config.get("#{hostname}_route".to_sym) == "NODATA"
|
|
19
|
+
# Reconfigure command with gateway. Example host1_route: IP.
|
|
20
|
+
# hostname2 = hostname ¿not used?
|
|
21
|
+
ip2 = ip
|
|
22
|
+
username2 = username
|
|
23
|
+
password2 = password
|
|
24
|
+
command2 = action[:command]
|
|
25
|
+
hostname = config.get("#{hostname}_route".to_sym)
|
|
26
|
+
ip = config.get("#{hostname}_ip".to_sym).to_s
|
|
27
|
+
username = config.get("#{hostname}_username".to_sym).to_s
|
|
28
|
+
password = config.get("#{hostname}_password".to_sym).to_s
|
|
29
|
+
ostype = config.get("#{hostname}_ostype".to_sym).to_s
|
|
30
|
+
|
|
31
|
+
action[:command] = if ostype.downcase.start_with? "win"
|
|
32
|
+
"echo y | plink #{username2}@#{ip2} -ssh -pw #{password2} \"#{command2}\""
|
|
33
|
+
else
|
|
34
|
+
"sshpass -p #{password2} #{username2}@#{ip2} #{command2}"
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
text = ""
|
|
39
|
+
exitcode = 0
|
|
40
|
+
begin
|
|
41
|
+
if sessions[hostname].nil?
|
|
42
|
+
sessions[hostname] = Net::SSH.start(
|
|
43
|
+
ip,
|
|
44
|
+
username,
|
|
45
|
+
port: port,
|
|
46
|
+
password: password,
|
|
47
|
+
keepalive: true,
|
|
48
|
+
timeout: 30,
|
|
49
|
+
non_interactive: true
|
|
50
|
+
)
|
|
51
|
+
end
|
|
52
|
+
text = if sessions[hostname].instance_of? Net::SSH::Connection::Session
|
|
53
|
+
sessions[hostname].exec!(action[:command])
|
|
54
|
+
else
|
|
55
|
+
"SSH: NO CONNECTION!"
|
|
56
|
+
end
|
|
57
|
+
exitcode = text.exitstatus
|
|
58
|
+
rescue Errno::EHOSTUNREACH
|
|
59
|
+
sessions[hostname] = :nosession
|
|
60
|
+
conn_status[hostname] = :host_unreachable
|
|
61
|
+
exitcode = -1
|
|
62
|
+
log("Host #{ip} unreachable!", :error)
|
|
63
|
+
rescue Net::SSH::AuthenticationFailed
|
|
64
|
+
sessions[hostname] = :nosession
|
|
65
|
+
conn_status[hostname] = :error_authentication_failed
|
|
66
|
+
exitcode = -1
|
|
67
|
+
log("SSH::AuthenticationFailed!", :error)
|
|
68
|
+
rescue Net::SSH::HostKeyMismatch
|
|
69
|
+
sessions[hostname] = :nosession
|
|
70
|
+
conn_status[hostname] = :host_key_mismatch
|
|
71
|
+
exitcode = -1
|
|
72
|
+
log("SSH::HostKeyMismatch!", :error)
|
|
73
|
+
log("* The destination server's fingerprint is not matching " \
|
|
74
|
+
"what is in your local known_hosts file.", :error)
|
|
75
|
+
log("* Remove the existing entry in your local known_hosts file", :error)
|
|
76
|
+
log("* Try this => ssh-keygen -f '/home/USERNAME/.ssh/known_hosts' " \
|
|
77
|
+
"-R #{ip}", :error)
|
|
78
|
+
rescue => e
|
|
79
|
+
sessions[hostname] = :nosession
|
|
80
|
+
conn_status[hostname] = :error
|
|
81
|
+
exitcode = -1
|
|
82
|
+
log("[#{e.class}] SSH on <#{username}@#{ip}>" \
|
|
83
|
+
" exec: #{action[:command]}", :error)
|
|
84
|
+
end
|
|
85
|
+
output = encode_and_split(action[:encoding], text)
|
|
86
|
+
result.exitcode = exitcode
|
|
87
|
+
result.content = output
|
|
88
|
+
result.content.compact!
|
|
89
|
+
end
|
|
90
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
require "net/telnet"
|
|
2
|
+
require "rainbow"
|
|
3
|
+
require_relative "../../utils/project"
|
|
4
|
+
require_relative "../../utils/verbose"
|
|
5
|
+
require_relative "execute_base"
|
|
6
|
+
|
|
7
|
+
class ExecuteTelnet < ExecuteBase
|
|
8
|
+
def call(input_hostname)
|
|
9
|
+
action[:conn_type] = :telnet
|
|
10
|
+
hostname = input_hostname.to_s
|
|
11
|
+
ip = config.get((hostname + "_ip").to_sym)
|
|
12
|
+
username = config.get((hostname + "_username").to_sym).to_s
|
|
13
|
+
password = config.get((hostname + "_password").to_sym).to_s
|
|
14
|
+
text = ""
|
|
15
|
+
begin
|
|
16
|
+
if sessions[hostname].nil? || sessions[hostname] == :ok
|
|
17
|
+
h = Net::Telnet.new(
|
|
18
|
+
"Host" => ip,
|
|
19
|
+
"Timeout" => 30,
|
|
20
|
+
"Prompt" => /login|teuton|[$%#>]/
|
|
21
|
+
)
|
|
22
|
+
# "Prompt" => Regexp.new(username[1, 40]))
|
|
23
|
+
# "Prompt" => /[$%#>] \z/n)
|
|
24
|
+
h.login(username, password)
|
|
25
|
+
h.cmd(action[:command]) { |i| text << i }
|
|
26
|
+
h.close
|
|
27
|
+
sessions[hostname] = :ok
|
|
28
|
+
else
|
|
29
|
+
text = "TELNET: NO CONNECTION!"
|
|
30
|
+
end
|
|
31
|
+
rescue Net::OpenTimeout
|
|
32
|
+
sessions[hostname] = :nosession
|
|
33
|
+
conn_status[hostname] = :open_timeout
|
|
34
|
+
verbose Rainbow(Application.instance.letter[:error]).red.bright
|
|
35
|
+
log(" ExceptionType=<Net::OpenTimeout> doing <telnet #{ip}>", :error)
|
|
36
|
+
log(" └── Revise host IP!", :warn)
|
|
37
|
+
rescue Net::ReadTimeout
|
|
38
|
+
sessions[hostname] = :nosession
|
|
39
|
+
conn_status[hostname] = :read_timeout
|
|
40
|
+
verbose Rainbow(Application.instance.letter[:error]).red.bright
|
|
41
|
+
log(" ExceptionType=<Net::ReadTimeout> doing <telnet #{ip}>", :error)
|
|
42
|
+
rescue => e
|
|
43
|
+
sessions[hostname] = :nosession
|
|
44
|
+
conn_status[hostname] = :error
|
|
45
|
+
verbose Rainbow(Application.instance.letter[:error]).red.bright
|
|
46
|
+
log(" ExceptionType=<#{e.class}> doing telnet on <#{username}@#{ip}>" \
|
|
47
|
+
" exec: #{action[:command]}", :error)
|
|
48
|
+
log(" └── username=<#{username}>, password=<#{password}>," \
|
|
49
|
+
" ip=<#{ip}>, HOSTID=<#{hostname}>", :warn)
|
|
50
|
+
end
|
|
51
|
+
output = encode_and_split(action[:encoding], text)
|
|
52
|
+
result.exitcode = -1
|
|
53
|
+
result.content = output
|
|
54
|
+
result.content.compact!
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -1,27 +1,22 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# Case class:
|
|
4
|
-
# * play
|
|
5
|
-
# * play_in_parallel
|
|
6
|
-
# * play_in_sequence
|
|
7
|
-
# * fill_report
|
|
8
|
-
# * close_opened_sessions
|
|
9
3
|
class Case
|
|
4
|
+
# Case class: play
|
|
5
|
+
# TODO: Encapsulate code into PlayManager class
|
|
6
|
+
# * play_in_parallel, play_in_sequence, fill_report, close_opened_sessions
|
|
7
|
+
# READ: sessions, config, groups, action, report
|
|
8
|
+
# TODO: groups from Project or from Case???
|
|
10
9
|
def play
|
|
11
10
|
if skip?
|
|
12
11
|
verbose Rainbow("S").green
|
|
13
12
|
return false
|
|
14
13
|
end
|
|
15
14
|
start_time = Time.now
|
|
16
|
-
|
|
17
|
-
play_in_sequence
|
|
18
|
-
else
|
|
19
|
-
play_in_parallel
|
|
20
|
-
end
|
|
15
|
+
play_groups_in_sequence
|
|
21
16
|
fill_report(start_time, Time.now)
|
|
22
17
|
close_opened_sessions
|
|
23
18
|
end
|
|
24
|
-
|
|
19
|
+
alias_method :start, :play
|
|
25
20
|
|
|
26
21
|
def close_opened_sessions
|
|
27
22
|
@sessions.each_value do |s|
|
|
@@ -31,14 +26,16 @@ class Case
|
|
|
31
26
|
|
|
32
27
|
private
|
|
33
28
|
|
|
34
|
-
def
|
|
29
|
+
def play_groups_in_sequence
|
|
30
|
+
verboseln "\n=> Starting case [#{@config.get(:tt_members)}]" if get(:tt_sequence) == true
|
|
35
31
|
@groups.each do |t|
|
|
36
32
|
@action[:groupname] = t[:name]
|
|
33
|
+
# TODO: @parent(case).instance_eval(&t[:block])
|
|
37
34
|
instance_eval(&t[:block])
|
|
38
35
|
end
|
|
39
36
|
end
|
|
40
37
|
|
|
41
|
-
def
|
|
38
|
+
def play_groups_in_parallel
|
|
42
39
|
verboseln "Starting case [#{@config.get(:tt_members)}]"
|
|
43
40
|
@groups.each do |t|
|
|
44
41
|
verbose "* Processing [#{t[:name]}] "
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
require "singleton"
|
|
3
|
-
require_relative "../application"
|
|
1
|
+
require_relative "../case/case"
|
|
4
2
|
require_relative "../report/report"
|
|
5
|
-
require_relative "../
|
|
3
|
+
require_relative "../utils/project"
|
|
4
|
+
require_relative "../utils/verbose"
|
|
6
5
|
require_relative "../utils/configfile_reader"
|
|
7
|
-
require_relative "case/case"
|
|
8
6
|
require_relative "export_manager"
|
|
9
|
-
require_relative "
|
|
7
|
+
require_relative "send_manager"
|
|
8
|
+
require_relative "show_report"
|
|
9
|
+
require_relative "check_cases"
|
|
10
|
+
require_relative "report"
|
|
11
|
+
require_relative "utils"
|
|
10
12
|
|
|
11
|
-
# This class does all the job
|
|
12
|
-
# Organize the hole job, sending orders to others classes
|
|
13
13
|
# * initialize
|
|
14
14
|
# * play
|
|
15
15
|
# Split into several files:
|
|
@@ -18,8 +18,8 @@ require_relative "main"
|
|
|
18
18
|
# * case_manager/hall_of_fame
|
|
19
19
|
# * case_manager/report
|
|
20
20
|
class CaseManager
|
|
21
|
-
include Singleton
|
|
22
21
|
include Utils
|
|
22
|
+
include Verbose
|
|
23
23
|
attr_reader :report, :cases
|
|
24
24
|
|
|
25
25
|
def initialize
|
|
@@ -28,51 +28,32 @@ class CaseManager
|
|
|
28
28
|
@report.filename = "resume"
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
-
##
|
|
32
|
-
# Execute "play" order: Start every single case test
|
|
33
|
-
# @param block (Block)
|
|
34
31
|
def play(&block)
|
|
32
|
+
# Execute "play" order: Start every single case test
|
|
35
33
|
check_cases!
|
|
36
34
|
instance_eval(&block)
|
|
37
35
|
# Run export if user pass option command "--export=json"
|
|
38
|
-
i =
|
|
36
|
+
i = Project.value[:options]["export"]
|
|
39
37
|
export(format: i.to_sym) unless i.nil?
|
|
40
38
|
# Accept "configfile" param REVISE There exists?
|
|
41
|
-
i =
|
|
39
|
+
i = Project.value[:options]["configfile"]
|
|
42
40
|
export(format: i.to_sym) unless i.nil?
|
|
43
41
|
end
|
|
44
42
|
|
|
45
|
-
##
|
|
46
|
-
# Execute "export" order: Export every case report
|
|
47
|
-
# @param args (Hash) Export options
|
|
48
43
|
def export(args = {})
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
exit 1
|
|
56
|
-
end
|
|
57
|
-
ExportManager.run(@report, @cases, args)
|
|
44
|
+
ExportManager.new.call(
|
|
45
|
+
@report,
|
|
46
|
+
@cases,
|
|
47
|
+
args,
|
|
48
|
+
Project.value[:format]
|
|
49
|
+
)
|
|
58
50
|
end
|
|
59
51
|
|
|
60
|
-
##
|
|
61
|
-
# Execute "send" order: Send every case report
|
|
62
|
-
# @param args (Hash) Send options
|
|
63
52
|
def send(args = {})
|
|
64
|
-
|
|
65
|
-
puts ""
|
|
66
|
-
puts Rainbow("-" * 50).green
|
|
67
|
-
puts Rainbow("Sending files...#{args}").color(:green)
|
|
68
|
-
@cases.each { |c| threads << Thread.new { c.send(args) } }
|
|
69
|
-
threads.each(&:join)
|
|
70
|
-
puts Rainbow("Sending finished!").color(:green)
|
|
71
|
-
puts Rainbow("-" * 50).green
|
|
53
|
+
SendManager.new.call(@cases, args)
|
|
72
54
|
end
|
|
73
55
|
|
|
74
56
|
def show(options = {verbose: 1})
|
|
75
|
-
|
|
76
|
-
ShowReport.new(@report).call(verbose)
|
|
57
|
+
ShowReport.new(@report).call(options[:verbose])
|
|
77
58
|
end
|
|
78
59
|
end
|
|
@@ -1,32 +1,33 @@
|
|
|
1
1
|
require_relative "hall_of_fame"
|
|
2
|
+
require_relative "../utils/project"
|
|
2
3
|
|
|
3
4
|
class CaseManager
|
|
4
5
|
private
|
|
5
6
|
|
|
6
|
-
##
|
|
7
|
-
# Start checking every single case
|
|
8
7
|
def check_cases!
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
# Start checking every single case
|
|
9
|
+
app = Project.value
|
|
11
10
|
# Load configurations from config file
|
|
12
|
-
configdata = ConfigFileReader.read(
|
|
13
|
-
app
|
|
14
|
-
app
|
|
15
|
-
app
|
|
16
|
-
app
|
|
11
|
+
configdata = ConfigFileReader.read(Project.value[: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?
|
|
17
16
|
|
|
18
17
|
# Create out dir
|
|
19
|
-
outdir = app
|
|
18
|
+
outdir = app[:global][:tt_outdir] || File.join("var", app[:global][:tt_testname])
|
|
20
19
|
ensure_dir outdir
|
|
21
20
|
@report.output_dir = outdir
|
|
22
21
|
|
|
23
22
|
# Fill report head
|
|
24
|
-
open_main_report(app
|
|
23
|
+
open_main_report(app[:config_path])
|
|
25
24
|
|
|
26
25
|
# create cases and run
|
|
27
26
|
configdata[:cases].each { |config| @cases << Case.new(config) }
|
|
28
27
|
start_time = run_all_cases # run cases
|
|
29
28
|
|
|
29
|
+
# TODO: merge these 2 methdos
|
|
30
|
+
# TODO: CloseManager.call ???
|
|
30
31
|
uniques = collect_uniques_for_all_cases
|
|
31
32
|
close_reports_for_all_cases(uniques)
|
|
32
33
|
close_main_report(start_time)
|
|
@@ -36,7 +37,8 @@ class CaseManager
|
|
|
36
37
|
start_time = Time.now
|
|
37
38
|
verboseln Rainbow("-" * 36).green
|
|
38
39
|
verboseln Rainbow("Started at #{start_time}").green
|
|
39
|
-
if Application.instance.global[:tt_sequence] == true
|
|
40
|
+
# if Application.instance.global[:tt_sequence] == true
|
|
41
|
+
if Project.value[:global][:tt_sequence] == true
|
|
40
42
|
# Run every case in sequence
|
|
41
43
|
@cases.each(&:play)
|
|
42
44
|
else
|
|
@@ -1,16 +1,15 @@
|
|
|
1
|
-
require_relative "../
|
|
1
|
+
require_relative "../utils/project"
|
|
2
2
|
require_relative "case_manager"
|
|
3
3
|
|
|
4
4
|
def use(filename)
|
|
5
5
|
filename += ".rb"
|
|
6
|
-
|
|
7
|
-
rbfiles = File.join(app.project_path, "**", filename)
|
|
6
|
+
rbfiles = File.join(Project.value[:project_path], "**", filename)
|
|
8
7
|
files = Dir.glob(rbfiles)
|
|
9
8
|
findfiles = []
|
|
10
9
|
files.sort.each { |f| findfiles << f if f.include?(filename) }
|
|
11
10
|
begin
|
|
12
11
|
require_relative findfiles.first
|
|
13
|
-
|
|
12
|
+
Project.value[:uses] << File.basename(findfiles.first)
|
|
14
13
|
rescue
|
|
15
14
|
puts "[ERROR] Unknown file : #{filename}"
|
|
16
15
|
puts " Check line : use '#{filename}'"
|
|
@@ -19,7 +18,7 @@ def use(filename)
|
|
|
19
18
|
end
|
|
20
19
|
|
|
21
20
|
def define_macro(name, *args, &block)
|
|
22
|
-
|
|
21
|
+
Project.value[:macros][name] = {args: args, block: block}
|
|
23
22
|
end
|
|
24
23
|
alias def_macro define_macro
|
|
25
24
|
alias defmacro define_macro
|
|
@@ -28,13 +27,12 @@ alias defmacro define_macro
|
|
|
28
27
|
# @param name (String) Group name
|
|
29
28
|
# @param block (Block) Tests code
|
|
30
29
|
def group(name, &block)
|
|
31
|
-
|
|
30
|
+
Project.value[:groups] << {name: name, block: block}
|
|
32
31
|
end
|
|
33
32
|
alias task group
|
|
34
33
|
|
|
35
|
-
# Start test
|
|
36
|
-
# @param block (Block) Extra code executed at the end.
|
|
37
34
|
def play(&block)
|
|
38
|
-
|
|
35
|
+
# Start test
|
|
36
|
+
CaseManager.new.play(&block)
|
|
39
37
|
end
|
|
40
38
|
alias start play
|