teuton 3.2.1 → 3.4.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/README.md +18 -20
- data/docs/commands/README.md +12 -10
- data/docs/commands/check.md +17 -15
- data/docs/commands/{readme.md → doc.md} +3 -5
- data/docs/commands/help.md +23 -13
- data/docs/devel/todo.md +2 -8
- data/docs/dsl/README.md +9 -8
- data/docs/dsl/event.md +172 -0
- data/docs/dsl/target.md +0 -14
- data/docs/install/t-node.md +10 -21
- data/docs/learn/01-cmd_new.md +1 -1
- data/docs/learn/02-target.md +52 -50
- data/docs/learn/03-remote_hosts.md +15 -16
- data/docs/learn/04-config.md +70 -69
- data/docs/learn/05-use.md +1 -1
- data/docs/learn/06-cmd_check.md +28 -26
- data/docs/learn/07-target_weight.md +7 -5
- data/docs/learn/08-unique_values.md +32 -30
- data/docs/learn/09-send.md +2 -2
- data/docs/learn/10-debug.md +38 -1
- data/docs/learn/11-export.md +1 -1
- data/docs/learn/12-preserve.md +4 -4
- data/docs/learn/13-feedback.md +12 -11
- data/docs/learn/14-moodle_id.md +3 -3
- data/docs/learn/15-readme.md +12 -12
- data/docs/learn/16-include.md +9 -9
- data/docs/learn/17-alias.md +2 -2
- data/docs/learn/18-log.md +46 -44
- data/docs/learn/19-read_vars.md +1 -1
- data/docs/learn/20-macros.md +1 -1
- data/docs/learn/21-exit_codes.md +1 -1
- data/docs/learn/22-result.md +1 -1
- data/docs/learn/23-test-code.md +14 -11
- data/docs/learn/24-test-sql.md +6 -6
- data/docs/learn/25-expect-result.md +1 -1
- data/docs/learn/26-expect_sequence.md +2 -2
- data/docs/learn/27-run_script.md +9 -6
- data/docs/learn/28-upload.md +3 -1
- data/docs/learn/31-event-stop.md +134 -0
- data/docs/learn/32-event-zero.md +127 -0
- data/docs/more.md +4 -1
- data/lib/teuton/case/{action.rb → action/action.rb} +18 -10
- data/lib/teuton/case/action/manager.rb +198 -0
- data/lib/teuton/case/case.rb +15 -13
- data/lib/teuton/case/close.rb +7 -7
- data/lib/teuton/case/dsl/all.rb +1 -0
- data/lib/teuton/case/dsl/event.rb +5 -0
- data/lib/teuton/case/dsl/expect.rb +6 -4
- data/lib/teuton/case/dsl/log.rb +10 -9
- data/lib/teuton/case/dsl/macro.rb +1 -1
- data/lib/teuton/case/dsl/run.rb +10 -15
- data/lib/teuton/case/dsl/target.rb +10 -3
- data/lib/teuton/case/play.rb +1 -1
- data/lib/teuton/case/result/ext_compare.rb +10 -10
- data/lib/teuton/case_manager/dsl.rb +6 -2
- data/lib/teuton/case_manager/ext/report.rb +0 -4
- data/lib/teuton/case_manager/show_resume_report.rb +29 -30
- data/lib/teuton/check/checker.rb +19 -8
- data/lib/teuton/check/dsl/all.rb +10 -16
- data/lib/teuton/check/dsl/event.rb +10 -0
- data/lib/teuton/check/dsl/expect.rb +21 -45
- data/lib/teuton/check/dsl/getset.rb +2 -2
- data/lib/teuton/check/dsl/run.rb +2 -2
- data/lib/teuton/check/dsl/target.rb +17 -0
- data/lib/teuton/check/show.rb +35 -41
- data/lib/teuton/cli/app.rb +16 -8
- data/lib/teuton/readme/dsl/all.rb +16 -2
- data/lib/teuton/readme/main.rb +2 -2
- data/lib/teuton/report/formatter/default/array.rb +15 -29
- data/lib/teuton/report/formatter/default/txt.rb +42 -30
- data/lib/teuton/report/formatter/resume/txt.rb +27 -26
- data/lib/teuton/report/formatter/resume/xml.rb +4 -4
- data/lib/teuton/report/report.rb +5 -36
- data/lib/teuton/utils/project.rb +4 -3
- data/lib/teuton/version.rb +1 -1
- metadata +14 -7
- data/docs/tutorial/es/nginx/README.md +0 -546
- data/lib/teuton/deprecated/utils.rb +0 -14
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
[<<back](../../README.md)
|
|
2
|
+
|
|
3
|
+
# Event: scores to zero
|
|
4
|
+
|
|
5
|
+
We are going to create an event that triggers when the last target fails, and which sets all the scores for the targets already evaluated to zero.
|
|
6
|
+
|
|
7
|
+
```ruby
|
|
8
|
+
event on: :last_target, when: failed do
|
|
9
|
+
scores_to_zero
|
|
10
|
+
end
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Example
|
|
14
|
+
|
|
15
|
+
In this example, we have 4 targets, all of which will function correctly except for target 3.
|
|
16
|
+
|
|
17
|
+
```ruby
|
|
18
|
+
group "Events: scores_to_zero" do
|
|
19
|
+
target "Target 1: ok"
|
|
20
|
+
run "id root"
|
|
21
|
+
expect_ok
|
|
22
|
+
|
|
23
|
+
target "Target 2: ok"
|
|
24
|
+
run "id root"
|
|
25
|
+
expect_ok
|
|
26
|
+
|
|
27
|
+
target "Target 3: fail"
|
|
28
|
+
run "id vader"
|
|
29
|
+
expect_ok
|
|
30
|
+
|
|
31
|
+
event on: :last_target, when: :failed do
|
|
32
|
+
scores_to_zero
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
target "Target 4: ok"
|
|
36
|
+
run "id root"
|
|
37
|
+
expect_ok
|
|
38
|
+
end
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
The event, before target 3, is defined to trigger the `scores_to_zero` action when target fails.
|
|
42
|
+
|
|
43
|
+
The action resets the values of all already-evaluated targets to zero.
|
|
44
|
+
|
|
45
|
+
## Report output
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
$ teuton examples/32-event-zero
|
|
49
|
+
|
|
50
|
+
☰ CASE RESULTS
|
|
51
|
+
┌──────┬──────────┬───────┬───────┐
|
|
52
|
+
│ CASE │ MEMBERS │ GRADE │ STATE │
|
|
53
|
+
│ 01 │ TOCHANGE │ 25.0 │ ? │
|
|
54
|
+
└──────┴──────────┴───────┴───────┘
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Process:
|
|
58
|
+
* target 1 is Ok.
|
|
59
|
+
* target 2 is Ok.
|
|
60
|
+
* target 3 fails so the `scores_to_zero` action is triggered. Targets 1 and 2 are reset to zero.
|
|
61
|
+
* target 4 is Ok.
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
$ cat var/32-event-zero/case-01.txt
|
|
65
|
+
|
|
66
|
+
⚒ CONFIGURATION
|
|
67
|
+
┌────────────────┬────────────────────────────────────┐
|
|
68
|
+
│ tt_config_path │ examples/32-event-zero/config.yaml │
|
|
69
|
+
│ tt_members │ TOCHANGE │
|
|
70
|
+
│ tt_script_path │ examples/32-event-zero/start.rb │
|
|
71
|
+
│ tt_sequence │ false │
|
|
72
|
+
│ tt_skip │ false │
|
|
73
|
+
└────────────────┴────────────────────────────────────┘
|
|
74
|
+
|
|
75
|
+
🛈 LOGS
|
|
76
|
+
[16:27:47] INFO| Event[0] triggered because target[3] failed
|
|
77
|
+
[16:27:47] INFO| Scores READJUSTED!
|
|
78
|
+
|
|
79
|
+
☰ GROUPS
|
|
80
|
+
▶ Events: scores_to_zero
|
|
81
|
+
✔ 01 (0.0/1.0) ┌──
|
|
82
|
+
Description │ Target 1: ok (SCORE TO ZERO)
|
|
83
|
+
Command │ id root
|
|
84
|
+
Output │ uid=0(root) gid=0(root) grupos=0(root)
|
|
85
|
+
Duration │ 0.002 (local)
|
|
86
|
+
Alterations │ Read exit code
|
|
87
|
+
Expected │ 0
|
|
88
|
+
Result │ 0
|
|
89
|
+
✔ 02 (0.0/1.0) ├──
|
|
90
|
+
Description │ Target 2: ok (SCORE TO ZERO)
|
|
91
|
+
Command │ id root
|
|
92
|
+
Output │ uid=0(root) gid=0(root) grupos=0(root)
|
|
93
|
+
Duration │ 0.001 (local)
|
|
94
|
+
Alterations │ Read exit code
|
|
95
|
+
Expected │ 0
|
|
96
|
+
Result │ 0
|
|
97
|
+
✖ 03 (0.0/1.0) ├──
|
|
98
|
+
Description │ Target 3: fail (SCORE TO ZERO)
|
|
99
|
+
Command │ id vader
|
|
100
|
+
Output │ id: «vader»: no existe ese usuario
|
|
101
|
+
Duration │ 0.002 (local)
|
|
102
|
+
Alterations │ Read exit code
|
|
103
|
+
Expected │ 0
|
|
104
|
+
Result │ 1
|
|
105
|
+
✔ 04 (1.0/1.0) ├──
|
|
106
|
+
Description │ Target 4: ok
|
|
107
|
+
Command │ id root
|
|
108
|
+
Output │ uid=0(root) gid=0(root) grupos=0(root)
|
|
109
|
+
Duration │ 0.001 (local)
|
|
110
|
+
Alterations │ Read exit code
|
|
111
|
+
Expected │ 0
|
|
112
|
+
Result │ 0
|
|
113
|
+
└──
|
|
114
|
+
🗹 RESULTS
|
|
115
|
+
┌──────────────┬───────────────────────────┐
|
|
116
|
+
│ unique_fault │ 0 │
|
|
117
|
+
│ case_id │ 01 │
|
|
118
|
+
│ start_time │ 2026-10-30 16:27:47 +0000 │
|
|
119
|
+
│ finish_time │ 2026-10-30 16:27:47 +0000 │
|
|
120
|
+
│ duration │ 0.006894103 │
|
|
121
|
+
│ max_weight │ 4.0 │
|
|
122
|
+
│ good_weight │ 3.0 │
|
|
123
|
+
│ fail_weight │ 1.0 │
|
|
124
|
+
│ fail_counter │ 1 │
|
|
125
|
+
│ grade │ 25 │
|
|
126
|
+
└──────────────┴───────────────────────────┘
|
|
127
|
+
```
|
data/docs/more.md
CHANGED
|
@@ -9,7 +9,10 @@
|
|
|
9
9
|
|
|
10
10
|
# Videos
|
|
11
11
|
|
|
12
|
-
> By now there are no English videos.
|
|
12
|
+
> By now there are no English videos. Sorry!
|
|
13
|
+
|
|
14
|
+
Teuton v3.0:
|
|
15
|
+
* [RubySur Agosto 2026 - Test de Infraestructura Teuton](https://www.youtube.com/live/JW4T3cTyG5A?si=bt356lypKlrr_YLK)
|
|
13
16
|
|
|
14
17
|
Teuton v2.1:
|
|
15
18
|
* [Apuntes FP Informática - I Congreso Virtual - Mayo 2020](https://youtu.be/RxIV26BAoGo)
|
|
@@ -1,30 +1,38 @@
|
|
|
1
1
|
class Case
|
|
2
2
|
class Action
|
|
3
3
|
attr_reader :id
|
|
4
|
-
attr_accessor :groupname, :description, :weight,
|
|
5
|
-
:command, :encoding, :host, :exec,
|
|
6
|
-
:
|
|
4
|
+
attr_accessor :groupname, :description, :weight,
|
|
5
|
+
:command, :encoding, :host, :exec,
|
|
6
|
+
:conn_type, :duration,
|
|
7
|
+
:result, :output,
|
|
8
|
+
:alterations, :expected, :check
|
|
9
|
+
attr_writer :score
|
|
7
10
|
|
|
8
|
-
def initialize
|
|
9
|
-
@id =
|
|
11
|
+
def initialize(id = 1)
|
|
12
|
+
@id = id
|
|
10
13
|
@groupname = nil
|
|
11
14
|
@description = "No description!"
|
|
12
15
|
@weight = 1.0
|
|
16
|
+
@check = false
|
|
17
|
+
@score = nil
|
|
13
18
|
end
|
|
14
19
|
|
|
15
|
-
def
|
|
16
|
-
@
|
|
17
|
-
|
|
20
|
+
def score
|
|
21
|
+
return @score unless @score.nil?
|
|
22
|
+
return 0.0 if @check == false
|
|
23
|
+
|
|
24
|
+
@weight
|
|
18
25
|
end
|
|
19
26
|
|
|
20
27
|
def to_h
|
|
21
28
|
{
|
|
22
29
|
id: id,
|
|
23
|
-
groupname: groupname, description: description, weight: weight,
|
|
30
|
+
groupname: groupname, description: description, weight: weight,
|
|
24
31
|
command: command, encoding: encoding, host: host, exec: exec,
|
|
25
32
|
conn_type: conn_type, duration: duration,
|
|
26
33
|
result: result, output: output,
|
|
27
|
-
alterations: alterations, expected: expected, check: check
|
|
34
|
+
alterations: alterations, expected: expected, check: check,
|
|
35
|
+
score: score
|
|
28
36
|
}
|
|
29
37
|
end
|
|
30
38
|
end
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
require_relative "action"
|
|
2
|
+
|
|
3
|
+
class Case
|
|
4
|
+
class ActionManager
|
|
5
|
+
AVAILABLE = [
|
|
6
|
+
%i[last_target failed now],
|
|
7
|
+
%i[last_target passed now],
|
|
8
|
+
%i[every_target failed eachtime],
|
|
9
|
+
%i[every_target passed eachtime],
|
|
10
|
+
%i[all_targets failed atend],
|
|
11
|
+
%i[all_targets passed atend]
|
|
12
|
+
].freeze
|
|
13
|
+
attr_reader :actions, :events, :current_action
|
|
14
|
+
attr_writer :log
|
|
15
|
+
|
|
16
|
+
def initialize
|
|
17
|
+
@current_action = nil
|
|
18
|
+
@actions = []
|
|
19
|
+
@events = []
|
|
20
|
+
@stopped = false
|
|
21
|
+
@log = nil
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def check_event(args)
|
|
25
|
+
object = args[:on]
|
|
26
|
+
condition = args[:when]
|
|
27
|
+
options = AVAILABLE.select { |obj, cond| obj == object && cond == condition }
|
|
28
|
+
if options.empty?
|
|
29
|
+
Logger.warn "Unkown! Event on: #{object}, when: #{condition}"
|
|
30
|
+
return false
|
|
31
|
+
elsif options.count > 1
|
|
32
|
+
Logger.warn "More than one definition! Event on: #{object}, when: #{condition}"
|
|
33
|
+
end
|
|
34
|
+
true
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def add_event(args, block)
|
|
38
|
+
return unless check_event(args)
|
|
39
|
+
|
|
40
|
+
object = args[:on]
|
|
41
|
+
condition = args[:when]
|
|
42
|
+
if object == :last_target
|
|
43
|
+
trigger_on_last_target(args, block)
|
|
44
|
+
elsif object == :all_targets
|
|
45
|
+
trigger_on_all_targets(args, block)
|
|
46
|
+
else
|
|
47
|
+
id = events.count
|
|
48
|
+
events << {id: id, args: args, block: block, type: :eachtime}
|
|
49
|
+
log "Register (sinde target #{last_action.id}) event on: #{object} , when: #{condition}"
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def close(report)
|
|
54
|
+
trigger_events!
|
|
55
|
+
@current_action = nil
|
|
56
|
+
|
|
57
|
+
# Calculate final values
|
|
58
|
+
@grade = @max_weight = @good_weight = @fails_weight = @fail_counter = 0
|
|
59
|
+
@history = ""
|
|
60
|
+
|
|
61
|
+
@actions.each do |action|
|
|
62
|
+
@max_weight += action.weight if action.weight.positive?
|
|
63
|
+
|
|
64
|
+
if action.check
|
|
65
|
+
@good_weight += action.weight
|
|
66
|
+
@history += Settings.letter[:good]
|
|
67
|
+
else
|
|
68
|
+
@fails_weight += action.weight
|
|
69
|
+
@fail_counter += 1
|
|
70
|
+
@history += Settings.letter[:fail]
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
report.lines += @actions.map(&:to_h)
|
|
75
|
+
report.history = @history
|
|
76
|
+
|
|
77
|
+
report.tail[:max_weight] = @max_weight
|
|
78
|
+
report.tail[:good_weight] = @good_weight
|
|
79
|
+
report.tail[:fail_weight] = @fails_weight
|
|
80
|
+
report.tail[:fail_counter] = @fail_counter
|
|
81
|
+
report.tail[:grade] = calculate_grade(report)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def last_action
|
|
85
|
+
@actions.last
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def next_action
|
|
89
|
+
if @current_action.nil?
|
|
90
|
+
@current_action = Action.new(1)
|
|
91
|
+
return @current_action
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
@actions << @current_action
|
|
95
|
+
@current_action = Action.new(last_action.id + 1)
|
|
96
|
+
@current_action.groupname = last_action.groupname
|
|
97
|
+
@current_action.description = last_action.description
|
|
98
|
+
@current_action
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def current_score
|
|
102
|
+
current_good_weight = @actions.sum(&:score)
|
|
103
|
+
value = current_good_weight.to_f / @max_weight
|
|
104
|
+
value = 0.0 if value.nan?
|
|
105
|
+
value
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def stopped?
|
|
109
|
+
@stopped
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def scores_to_zero
|
|
113
|
+
@actions.each do |action|
|
|
114
|
+
action.score = 0.0
|
|
115
|
+
action.description << " (SCORE TO ZERO)"
|
|
116
|
+
end
|
|
117
|
+
log("Scores set to ZERO!")
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def stop
|
|
121
|
+
@stopped = true
|
|
122
|
+
log("Test STOPPED!")
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def to_h
|
|
126
|
+
@actions.map { _1.to_h }
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def trigger_events!
|
|
130
|
+
@events.each do |event|
|
|
131
|
+
# TODO: Do something if type == :eachtime
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
return unless @stopped
|
|
135
|
+
|
|
136
|
+
@current_action.description = "TEST STOPPED!"
|
|
137
|
+
@current_action.command = ""
|
|
138
|
+
@current_action.exec = ""
|
|
139
|
+
@current_action.conn_type = "?"
|
|
140
|
+
@current_action.duration = "?"
|
|
141
|
+
@current_action.result = ""
|
|
142
|
+
@current_action.output = ""
|
|
143
|
+
@current_action.alterations = ""
|
|
144
|
+
@current_action.expected = ""
|
|
145
|
+
@current_action.check = false
|
|
146
|
+
@current_action.score = 0.0
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
private
|
|
150
|
+
|
|
151
|
+
def log(...)
|
|
152
|
+
return if @log.nil?
|
|
153
|
+
|
|
154
|
+
@log.call(...)
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def calculate_grade(report)
|
|
158
|
+
current_good_weight = @actions.sum(&:score)
|
|
159
|
+
current_score = current_good_weight.to_f / @max_weight
|
|
160
|
+
current_score = 0.0 if current_score.nan?
|
|
161
|
+
|
|
162
|
+
@grade = (100.0 * current_score).round
|
|
163
|
+
|
|
164
|
+
@grade = 0.0 if report.tail[:unique_fault].positive?
|
|
165
|
+
@grade
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def trigger_on_last_target(args, block)
|
|
169
|
+
do_ok = last_action.check && args[:when] == :is_ok
|
|
170
|
+
do_failed = !last_action.check && args[:when] == :failed
|
|
171
|
+
unless do_ok || do_failed
|
|
172
|
+
id = events.count
|
|
173
|
+
events << {id: id, args: args, block: block, status: :cancelled}
|
|
174
|
+
log "Event[#{id}] cancelled because target[#{last_action.id}] #{args[:when]}"
|
|
175
|
+
end
|
|
176
|
+
id = events.count
|
|
177
|
+
events << {id: id, args: args, block: block, status: :triggered}
|
|
178
|
+
log "Event[#{id}] triggered because target[#{last_action.id}] #{args[:when]}"
|
|
179
|
+
instance_exec(**args, &block) if block
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def trigger_on_all_targets(args, block)
|
|
183
|
+
all_targets_passed = @actions.map { _1.check }.all?
|
|
184
|
+
do_all_passed = all_targets_passed && args[:when] == :is_ok
|
|
185
|
+
all_targets_failed = @actions.map { !_1.check }.all?
|
|
186
|
+
do_all_failed = all_targets_failed && args[:when] == :failed
|
|
187
|
+
unless do_all_passed || do_all_failed
|
|
188
|
+
id = events.count
|
|
189
|
+
events << {id: id, args: args, block: block, status: :cancelled}
|
|
190
|
+
log "Event[#{id}] cancelled. Not all_targets[1, #{last_action.id}] #{args[:when]}"
|
|
191
|
+
end
|
|
192
|
+
id = events.count
|
|
193
|
+
events << {id: id, args: args, block: block, status: :triggered}
|
|
194
|
+
log "Event[#{id}] triggered. All_targets[1, #{last_action.id}] #{args[:when]}"
|
|
195
|
+
instance_exec(**args, &block) if block
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
end
|
data/lib/teuton/case/case.rb
CHANGED
|
@@ -4,7 +4,8 @@ require_relative "../utils/project"
|
|
|
4
4
|
require_relative "../utils/verbose"
|
|
5
5
|
require_relative "../report/report"
|
|
6
6
|
require_relative "dsl/all"
|
|
7
|
-
require_relative "action"
|
|
7
|
+
# require_relative "action/action"
|
|
8
|
+
require_relative "action/manager"
|
|
8
9
|
require_relative "config"
|
|
9
10
|
require_relative "close"
|
|
10
11
|
# require_relative "builtin/main"
|
|
@@ -16,12 +17,11 @@ class Case
|
|
|
16
17
|
include DSL
|
|
17
18
|
include Verbose
|
|
18
19
|
|
|
19
|
-
#
|
|
20
|
+
# INFO: Used by ExecuteManager
|
|
20
21
|
attr_accessor :action, :result, :sessions, :conn_status
|
|
21
|
-
|
|
22
|
-
attr_reader :id, :config, :uniques, :skip
|
|
22
|
+
attr_reader :id, :config, :uniques, :skip, :action_manager
|
|
23
23
|
|
|
24
|
-
@current_case_id =
|
|
24
|
+
@current_case_id = Project.value[:base_case_id]
|
|
25
25
|
|
|
26
26
|
def self.next_id
|
|
27
27
|
@current_case_id = @current_case_id.next
|
|
@@ -32,12 +32,9 @@ class Case
|
|
|
32
32
|
local: config,
|
|
33
33
|
global: Project.value[:global]
|
|
34
34
|
)
|
|
35
|
-
@groups = Project.value[:groups]
|
|
36
35
|
@id = Case.next_id
|
|
37
|
-
|
|
38
|
-
# Define Case Report
|
|
36
|
+
@groups = Project.value[:groups]
|
|
39
37
|
@report = Report.new(@id)
|
|
40
|
-
@report.output_dir = Project.value[:output_dir]
|
|
41
38
|
|
|
42
39
|
# Default configuration
|
|
43
40
|
@skip = false
|
|
@@ -46,13 +43,14 @@ class Case
|
|
|
46
43
|
@skip = true
|
|
47
44
|
@skip = false if Project.value[:options]["case"].include? @id.to_i
|
|
48
45
|
end
|
|
49
|
-
@verbose = Project.value[:verbose]
|
|
50
|
-
|
|
51
46
|
@tempdir = File.join(Project.value[:output_dir], "tmp", @id.to_s)
|
|
47
|
+
@verbose = Project.value[:verbose]
|
|
52
48
|
|
|
53
49
|
@unique_values = {}
|
|
54
50
|
@result = Result.new
|
|
55
|
-
@
|
|
51
|
+
@action_manager = ActionManager.new
|
|
52
|
+
@action_manager.log = method(:log)
|
|
53
|
+
@action = @action_manager.next_action
|
|
56
54
|
@uniques = []
|
|
57
55
|
@sessions = {} # Store opened sessions for this case
|
|
58
56
|
@conn_status = {}
|
|
@@ -65,7 +63,6 @@ class Case
|
|
|
65
63
|
end
|
|
66
64
|
|
|
67
65
|
def filename
|
|
68
|
-
# called from: close_main_report
|
|
69
66
|
@report.filename
|
|
70
67
|
end
|
|
71
68
|
|
|
@@ -73,6 +70,11 @@ class Case
|
|
|
73
70
|
return 0.0 if skip
|
|
74
71
|
|
|
75
72
|
@report.tail[:grade]
|
|
73
|
+
# @action_manager.score
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def last_action
|
|
77
|
+
@action_manager.actions.last
|
|
76
78
|
end
|
|
77
79
|
|
|
78
80
|
def members
|
data/lib/teuton/case/close.rb
CHANGED
|
@@ -3,25 +3,25 @@
|
|
|
3
3
|
class Case
|
|
4
4
|
def close(uniques)
|
|
5
5
|
# Invoked from check_cases!
|
|
6
|
+
@action_manager.close(@report)
|
|
6
7
|
|
|
7
8
|
fails = 0
|
|
8
|
-
uniques.
|
|
9
|
-
next unless
|
|
9
|
+
uniques.each_pair do |key, values|
|
|
10
|
+
next unless values&.include?(id) && (values&.count&.> 1)
|
|
10
11
|
|
|
11
12
|
fails += 1
|
|
12
|
-
log_unique_message(key,
|
|
13
|
+
log_unique_message(key, values)
|
|
13
14
|
end
|
|
14
15
|
@report.tail[:unique_fault] = fails
|
|
15
|
-
@report.close
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
private
|
|
19
19
|
|
|
20
20
|
def log_unique_message(key, value)
|
|
21
|
-
log("UNIQUE:", :
|
|
21
|
+
log("UNIQUE:", :warn)
|
|
22
22
|
begin
|
|
23
|
-
log("
|
|
24
|
-
log("
|
|
23
|
+
log(" ├── Value => #{key}", :warn)
|
|
24
|
+
log(" └── Conflicts => #{value}", :warn)
|
|
25
25
|
rescue => e
|
|
26
26
|
log(key, :error)
|
|
27
27
|
log(e.to_s, :error)
|
data/lib/teuton/case/dsl/all.rb
CHANGED
|
@@ -15,12 +15,11 @@ module DSL
|
|
|
15
15
|
elsif input.instance_of?(String) || input.instance_of?(Regexp) || input.instance_of?(Array)
|
|
16
16
|
expect_any input
|
|
17
17
|
else
|
|
18
|
-
|
|
18
|
+
Logger.warn "Case expect TypeError: <expect #{input} (#{input.class})>"
|
|
19
19
|
end
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
def expect2(cond, args = {})
|
|
23
|
-
@action.next
|
|
24
23
|
if @result.exitcode.negative?
|
|
25
24
|
# When exitcode is less than zero, it is because there has been
|
|
26
25
|
# an error in the remote connection (SSH or Telnet)
|
|
@@ -33,8 +32,11 @@ module DSL
|
|
|
33
32
|
|
|
34
33
|
@action.alterations = @result.alterations
|
|
35
34
|
@action.expected = (args[:expected] || @result.expected)
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
|
|
36
|
+
@action_manager.trigger_events!
|
|
37
|
+
## @report.lines << @action.to_h
|
|
38
|
+
@action = @action_manager.next_action
|
|
39
|
+
# TODO: weight(1.0)
|
|
38
40
|
|
|
39
41
|
c = Settings.letter[:fail]
|
|
40
42
|
c = Settings.letter[:good] if cond
|
data/lib/teuton/case/dsl/log.rb
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
require "rainbow"
|
|
2
2
|
|
|
3
3
|
module DSL
|
|
4
|
-
|
|
5
|
-
# Record log message
|
|
6
|
-
# @param text (String)
|
|
7
|
-
# @param type (Symbol) Values :info, :warn or :error
|
|
4
|
+
# type => :info, :warn or :error
|
|
8
5
|
def log(text = "", type = :info)
|
|
9
6
|
s = " INFO"
|
|
10
|
-
s =
|
|
11
|
-
s =
|
|
7
|
+
s = " WARN" if type == :warn
|
|
8
|
+
s = "ERROR" if type == :error
|
|
12
9
|
t = Time.now
|
|
13
10
|
f = format("%<hour>02d:%<min>02d:%<sec>02d", {hour: t.hour, min: t.min, sec: t.sec})
|
|
14
|
-
msg = "[#{f}] #{s}
|
|
11
|
+
msg = "[#{f}] #{s}| #{text}"
|
|
15
12
|
msg = "[#{f}] #{text}" if s == ""
|
|
16
|
-
|
|
13
|
+
|
|
14
|
+
colored_msg = msg
|
|
15
|
+
colored_msg = Rainbow(msg).yellow.bright if type == :warn
|
|
16
|
+
colored_msg = Rainbow(msg).bg(:red) if type == :error
|
|
17
|
+
|
|
18
|
+
@report.lines << colored_msg
|
|
17
19
|
end
|
|
18
|
-
# alias_method :msg, :log
|
|
19
20
|
end
|
data/lib/teuton/case/dsl/run.rb
CHANGED
|
@@ -4,31 +4,26 @@ require_relative "../execute/execute_manager"
|
|
|
4
4
|
|
|
5
5
|
module DSL
|
|
6
6
|
##
|
|
7
|
-
# DSL run
|
|
8
|
-
# run: It's the same as goto :localhost
|
|
7
|
+
# DSL run
|
|
9
8
|
# @param command (String)
|
|
10
9
|
# @param args (Hash)
|
|
11
10
|
def run(command, args = {})
|
|
12
|
-
|
|
13
|
-
host = args[:on] || :localhost
|
|
14
|
-
|
|
15
|
-
end
|
|
11
|
+
@action.command = command.to_s
|
|
12
|
+
@action.host = args[:on] || :localhost
|
|
13
|
+
@action.encoding = args[:encoding] || "UTF-8"
|
|
16
14
|
|
|
17
|
-
# Run command from the host identify as "host"
|
|
18
|
-
# goto :host1, execute: "command"
|
|
19
|
-
def goto(host = :localhost, args = {})
|
|
20
15
|
@result.reset
|
|
21
|
-
args[:on] = host unless args[:on]
|
|
22
|
-
@action.command = args[:execute].to_s if args[:execute]
|
|
23
|
-
@action.command = args[:exec].to_s if args[:exec]
|
|
24
|
-
@action.encoding = args[:encoding] || "UTF-8"
|
|
25
16
|
|
|
26
|
-
ExecuteManager.new(self).call(host)
|
|
17
|
+
ExecuteManager.new(self).call(@action.host)
|
|
27
18
|
@action.output = if @result.content.size < 2
|
|
28
19
|
@result.value.clone
|
|
29
20
|
else
|
|
30
21
|
"(#{@result.content.size} lines)"
|
|
31
22
|
end
|
|
32
23
|
end
|
|
33
|
-
|
|
24
|
+
|
|
25
|
+
def goto(...)
|
|
26
|
+
Logger.warn "Keyword DSL deprecated! <goto>"
|
|
27
|
+
run(...)
|
|
28
|
+
end
|
|
34
29
|
end
|
|
@@ -2,17 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
# DSL#target
|
|
4
4
|
module DSL
|
|
5
|
-
def
|
|
5
|
+
def doc(_text)
|
|
6
6
|
# Usefull when running.
|
|
7
7
|
# It's works only with "teuton reamde" command action.
|
|
8
8
|
end
|
|
9
9
|
|
|
10
|
+
def readme(...)
|
|
11
|
+
Logger.warn("Keyword deprecated: Replace 'readme' by 'doc'.")
|
|
12
|
+
doc(...)
|
|
13
|
+
end
|
|
14
|
+
|
|
10
15
|
def target(desc, args = {})
|
|
11
16
|
@action.description = desc.to_s
|
|
12
|
-
@action.asset = args[:asset].to_s if args[:asset]
|
|
13
17
|
w = args[:weight] || 1.0
|
|
14
18
|
weight(w)
|
|
15
19
|
end
|
|
16
20
|
|
|
17
|
-
|
|
21
|
+
def goal(...)
|
|
22
|
+
Logger.warn("Keyword deprecated: Replace 'goal' by 'target'.")
|
|
23
|
+
target(...)
|
|
24
|
+
end
|
|
18
25
|
end
|