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
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7fa647498d568e303c8c02ea44277a595f3796a404a523daf6c1b0408110de97
|
|
4
|
+
data.tar.gz: b733858b7e97b373aca8477a359649b5e6614cdd60caffbdd052e450aa12dffa
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 60b94cd2ef2632e1fdbe81515909be71bce35d011f739ecc97806c1cfaa8115a7b743ee4369b54dffe366f1d7b06486fe451827c2fb4ce7fd37448fbf56b549b
|
|
7
|
+
data.tar.gz: 312bd19998b3ef68cc61780dda49cf1711033736a2593206501d5f428cd64780974a2adfc4198dd1097b178f6202637dcc10e11131c90495de553fc33547520f
|
data/docs/CHANGELOG.md
CHANGED
data/docs/changelog/todo.md
CHANGED
|
@@ -2,17 +2,15 @@
|
|
|
2
2
|
## TO-DO
|
|
3
3
|
|
|
4
4
|
New features:
|
|
5
|
-
-
|
|
6
|
-
-
|
|
7
|
-
-
|
|
5
|
+
- Teuton readme --lang=es and export files with other langs
|
|
6
|
+
- Snode Dockerfile with SSH server
|
|
7
|
+
- Auto Parse new input format, and detect parse errors
|
|
8
8
|
|
|
9
9
|
Revise:
|
|
10
10
|
* verify get(:key) and get('key') works fine!
|
|
11
|
-
* Formatter: xml
|
|
11
|
+
* Formatter: xml
|
|
12
12
|
|
|
13
13
|
Internal changes:
|
|
14
|
-
* Application to Settings
|
|
15
14
|
* Laboratory to Checker
|
|
16
15
|
* Unify messages ERROR, INFO, WARN. etc
|
|
17
|
-
* Create SendManager as ExportManager?
|
|
18
16
|
* Add tt_label as alias of tt_members
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
|
|
2
|
+
## [2.7.0]
|
|
3
|
+
|
|
4
|
+
New features:
|
|
5
|
+
- [ADD] "teuton config PROJECTPATH" will suggest suitable configuration for the project.
|
|
6
|
+
- [ADD] Every one line command output is registered into reports.
|
|
7
|
+
- [ADD] "expect_exit 1", check last command exit code is equal to 1.
|
|
8
|
+
|
|
9
|
+
Internal changes:
|
|
10
|
+
* Application class splited into Settings and Project classes
|
|
11
|
+
* Create SendManager similar to ExportManager
|
data/docs/diagram.md
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
[<<back](../README.md)
|
|
2
|
+
|
|
3
|
+
# Diagram
|
|
4
|
+
|
|
5
|
+
```mermaid
|
|
6
|
+
flowchart TB
|
|
7
|
+
|
|
8
|
+
subgraph user
|
|
9
|
+
CLI --> Teuton
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
subgraph "create\nnew\nproject"
|
|
13
|
+
Teuton -- create --> Skeleton("Sekeleton\nFiles")
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
subgraph "Check\nproject files"
|
|
17
|
+
Teuton -- check --> Laboratory("Laboratory\nDSL\nShow\nBuiltin!")
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
subgraph "Create readme\nfrom project"
|
|
21
|
+
Teuton -- readme --> Readme("Readme\nDSL\nLang!")
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
subgraph manager
|
|
25
|
+
Teuton -- run --> manager/DSL
|
|
26
|
+
manager/DSL -- play --> CaseManager("CaseManager\ncheck_cases\nExportManager\nSendManager\nShowReport")
|
|
27
|
+
ReportManager --> HallOfFame
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
subgraph "case folder"
|
|
31
|
+
CaseManager --> Case("Case\nConfig\nClose\nPlay\nRunner\ncase/DSL\ncase/builtin!")
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
subgraph utils
|
|
35
|
+
Verbose
|
|
36
|
+
|
|
37
|
+
Readme --> ConfigFileReader
|
|
38
|
+
Laboratory --> ConfigFileReader
|
|
39
|
+
CaseManager --> ConfigFileReader
|
|
40
|
+
|
|
41
|
+
Laboratory --> Result
|
|
42
|
+
Readme --> Result("Result\next_array\next_compare\next_filter")
|
|
43
|
+
Case --> Result
|
|
44
|
+
|
|
45
|
+
Laboratory --> Application
|
|
46
|
+
Readme --> Application
|
|
47
|
+
manager/DSL -- use/macros/groups --> Application("Application\nNameFileFinder")
|
|
48
|
+
Case --> Application
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
subgraph report
|
|
52
|
+
CaseManager --> Report("Report\nFormatter\nfiles/template")
|
|
53
|
+
Case --> Report
|
|
54
|
+
end
|
|
55
|
+
```
|
data/docs/learn/02-target.md
CHANGED
|
@@ -15,13 +15,31 @@ group "Learn about targets" do
|
|
|
15
15
|
|
|
16
16
|
target "Create user david"
|
|
17
17
|
run "id david"
|
|
18
|
-
expect "david"
|
|
18
|
+
expect ["uid=", "(david)", "gid="]
|
|
19
|
+
|
|
20
|
+
target "Delete user vader"
|
|
21
|
+
run "id vader"
|
|
22
|
+
expect ["id:", "vader", "no exist"]
|
|
19
23
|
|
|
20
24
|
end
|
|
21
25
|
```
|
|
22
26
|
|
|
23
27
|
> In this example, our localhost's OS is GNU/Linux (or any other compatible OS) because the command executed is `id david`.
|
|
24
28
|
|
|
29
|
+
When the user exists, we expect this words: `uid=, (david), gid=`.
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
❯ id david
|
|
33
|
+
uid=1000(david) gid=1000(david) grupos=1000(david)
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
But when user does not exist, we expect different words: `id:, vader, no exist`.
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
❯ id vader
|
|
40
|
+
id: «vader»: no existe ese usuario
|
|
41
|
+
```
|
|
42
|
+
|
|
25
43
|
## Execution section
|
|
26
44
|
|
|
27
45
|
When we run this teuton test, the execution section (`play`) is processed. This seccion now contains this:
|
|
@@ -41,7 +59,7 @@ end
|
|
|
41
59
|
Execute this command to run the test:
|
|
42
60
|
|
|
43
61
|
```console
|
|
44
|
-
> teuton run examples/
|
|
62
|
+
> teuton run examples/02-target
|
|
45
63
|
|
|
46
64
|
CASE RESULTS
|
|
47
65
|
+------+-----------+-------+-------+
|
|
@@ -54,7 +72,7 @@ Report files are created into `var/02-target/` folder:
|
|
|
54
72
|
|
|
55
73
|
```console
|
|
56
74
|
var
|
|
57
|
-
└──
|
|
75
|
+
└── 02-target
|
|
58
76
|
├── case-01.txt
|
|
59
77
|
├── moodle.csv
|
|
60
78
|
└── resume.txt
|
|
@@ -63,35 +81,42 @@ var
|
|
|
63
81
|
Let's see one report:
|
|
64
82
|
|
|
65
83
|
```
|
|
66
|
-
|
|
67
|
-
|
|
84
|
+
❯ cat var/02-target/case-01.txt
|
|
68
85
|
CONFIGURATION
|
|
69
86
|
+-------------+-----------+
|
|
70
87
|
| tt_members | anonymous |
|
|
71
88
|
| tt_sequence | false |
|
|
72
89
|
| tt_skip | false |
|
|
73
|
-
| tt_testname |
|
|
90
|
+
| tt_testname | 02-target |
|
|
74
91
|
+-------------+-----------+
|
|
75
92
|
|
|
93
|
+
|
|
76
94
|
GROUPS
|
|
77
95
|
- Learn about targets
|
|
78
96
|
01 (1.0/1.0)
|
|
79
97
|
Description : Create user david
|
|
80
98
|
Command : id david
|
|
81
99
|
Duration : 0.002 (local)
|
|
82
|
-
Alterations : find(david) & count
|
|
100
|
+
Alterations : find(uid=) & find((david)) & find(gid=) & count
|
|
101
|
+
Expected : Greater than 0 (String)
|
|
102
|
+
Result : 1 (Integer)
|
|
103
|
+
02 (1.0/1.0)
|
|
104
|
+
Description : Delete user vader
|
|
105
|
+
Command : id vader
|
|
106
|
+
Duration : 0.002 (local)
|
|
107
|
+
Alterations : find(id:) & find(vader) & find(no exist) & count
|
|
83
108
|
Expected : Greater than 0 (String)
|
|
84
109
|
Result : 1 (Integer)
|
|
85
110
|
|
|
86
111
|
RESULTS
|
|
87
112
|
+--------------+---------------------------+
|
|
88
113
|
| case_id | 01 |
|
|
89
|
-
| start_time |
|
|
90
|
-
| finish_time |
|
|
91
|
-
| duration | 0.
|
|
114
|
+
| start_time | 2023-04-10 09:09:30 +0100 |
|
|
115
|
+
| finish_time | 2023-04-10 09:09:30 +0100 |
|
|
116
|
+
| duration | 0.003863242 |
|
|
92
117
|
| unique_fault | 0 |
|
|
93
|
-
| max_weight |
|
|
94
|
-
| good_weight |
|
|
118
|
+
| max_weight | 2.0 |
|
|
119
|
+
| good_weight | 2.0 |
|
|
95
120
|
| fail_weight | 0.0 |
|
|
96
121
|
| fail_counter | 0 |
|
|
97
122
|
| grade | 100 |
|
data/docs/learn/04-config.md
CHANGED
data/docs/learn/06-cmd_check.md
CHANGED
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
|
|
4
4
|
# check test
|
|
5
5
|
|
|
6
|
-
Check Teuton
|
|
6
|
+
Check Teuton check syntax and show statistics.
|
|
7
7
|
|
|
8
8
|
```
|
|
9
|
-
❯ teuton check examples/05-use
|
|
9
|
+
❯ teuton check examples/05-use
|
|
10
10
|
|
|
11
11
|
+--------------------------+
|
|
12
12
|
| GROUP: Using file: users |
|
|
@@ -14,7 +14,7 @@ Check Teuton test syntax and show statistics.
|
|
|
14
14
|
(001) target Create user get(username)
|
|
15
15
|
weight 1.0
|
|
16
16
|
run 'id get(username)' on host1
|
|
17
|
-
expect get(username) (
|
|
17
|
+
expect ["uid=", "(get(username))", "gid="] (Array)
|
|
18
18
|
|
|
19
19
|
+----------------------------+
|
|
20
20
|
| GROUP: Using file: network |
|
|
@@ -32,6 +32,7 @@ Check Teuton test syntax and show statistics.
|
|
|
32
32
|
+-------------+-------+
|
|
33
33
|
| DSL Stats | Count |
|
|
34
34
|
+-------------+-------+
|
|
35
|
+
| Uses | 2 |
|
|
35
36
|
| Groups | 2 |
|
|
36
37
|
| Targets | 3 |
|
|
37
38
|
| Runs | 3 |
|
|
@@ -44,7 +45,4 @@ Check Teuton test syntax and show statistics.
|
|
|
44
45
|
| * hostname | 2 |
|
|
45
46
|
| Sets | 0 |
|
|
46
47
|
+-------------+-------+
|
|
47
|
-
+----------------------+
|
|
48
|
-
| Revising CONFIG file |
|
|
49
|
-
+----------------------+
|
|
50
48
|
```
|
|
@@ -19,15 +19,13 @@ end
|
|
|
19
19
|
```
|
|
20
20
|
|
|
21
21
|
```
|
|
22
|
-
❯ teuton check examples/07-target_weight
|
|
23
|
-
|
|
24
22
|
+--------------------------+
|
|
25
23
|
| GROUP: Using file: users |
|
|
26
24
|
+--------------------------+
|
|
27
25
|
(001) target Create user get(username)
|
|
28
26
|
weight 1.0
|
|
29
27
|
run 'id get(username)' on host1
|
|
30
|
-
expect get(username) (
|
|
28
|
+
expect ["uid=", "(get(username))", "gid="] (Array)
|
|
31
29
|
|
|
32
30
|
+----------------------------+
|
|
33
31
|
| GROUP: Using file: network |
|
data/docs/learn/21-exit_codes.md
CHANGED
|
@@ -1,24 +1,17 @@
|
|
|
1
1
|
[<< back](README.md)
|
|
2
2
|
|
|
3
|
-
# Example:
|
|
3
|
+
# Example: exit_codes
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
`result` stores information from the last command executed by a "run" action. [Offers many functions](../dsl/definition/result.md)) that transforms output data, and also exitcode is captured.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## Example
|
|
8
8
|
|
|
9
|
-
## Description
|
|
10
|
-
|
|
11
|
-
Take a look at this section:
|
|
12
9
|
```ruby
|
|
13
10
|
target "Exist user root"
|
|
14
|
-
run "id root
|
|
15
|
-
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
It is posible to invoke the execution of several commands in sequence "cmd1;cmd2". Keep in mind that the last one must show the exit code. In the case of GNU/Linux is "echo $?", but it is different on others OOSS.
|
|
11
|
+
run "id root"
|
|
12
|
+
expect_exit 0
|
|
19
13
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
> * [result](../dsl/execution/result.md) keyword.
|
|
14
|
+
target "No user vader"
|
|
15
|
+
run "id vader"
|
|
16
|
+
expect_exit 1
|
|
17
|
+
```
|
data/docs/learn/README.md
CHANGED
|
@@ -17,7 +17,7 @@ Learn how write your own Teuton tests:
|
|
|
17
17
|
1. [Export other FORMATS](11-export.md)
|
|
18
18
|
1. [PRESERVE old reports](12-preserve.md)
|
|
19
19
|
1. [Hide FEEDBACK from reports](13-feedback.md)
|
|
20
|
-
1. [MOODLE
|
|
20
|
+
1. [MOODLE](14-moodle_id.md)
|
|
21
21
|
1. [Build README from test](15-readme.md)
|
|
22
22
|
1. [INCLUDE more configuration files](16-include.md)
|
|
23
23
|
1. [ALIAS](17-alias.md)
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../utils/project"
|
|
4
|
+
require_relative "../utils/verbose"
|
|
5
|
+
require_relative "../utils/result/result"
|
|
6
|
+
require_relative "../report/report"
|
|
7
|
+
require_relative "dsl/all"
|
|
8
|
+
require_relative "config"
|
|
9
|
+
require_relative "close"
|
|
10
|
+
require_relative "play"
|
|
11
|
+
require_relative "builtin/main"
|
|
12
|
+
|
|
13
|
+
class Case
|
|
14
|
+
# Case: export, filename, grade, members,skip
|
|
15
|
+
include DSL
|
|
16
|
+
include Verbose
|
|
17
|
+
|
|
18
|
+
attr_accessor :action # Updated by ExecuteManager
|
|
19
|
+
attr_accessor :result # Updated by ExecuteManager
|
|
20
|
+
attr_accessor :sessions # Updated by ExecuteManager
|
|
21
|
+
attr_accessor :conn_status # Updated by ExecuteManager
|
|
22
|
+
|
|
23
|
+
attr_reader :id
|
|
24
|
+
attr_reader :config # Readed by ExecuteManager
|
|
25
|
+
attr_reader :uniques
|
|
26
|
+
attr_reader :skip
|
|
27
|
+
@@id = "01" # First case ID value
|
|
28
|
+
|
|
29
|
+
def initialize(config)
|
|
30
|
+
@config = Case::Config.new(
|
|
31
|
+
local: config,
|
|
32
|
+
global: Project.value[:global]
|
|
33
|
+
)
|
|
34
|
+
@groups = Project.value[:groups]
|
|
35
|
+
|
|
36
|
+
@id = @@id
|
|
37
|
+
@@id = @@id.next
|
|
38
|
+
|
|
39
|
+
# Define Case Report
|
|
40
|
+
@report = Report.new(@id)
|
|
41
|
+
@report.output_dir = File.join("var", @config.global[:tt_testname])
|
|
42
|
+
|
|
43
|
+
# Default configuration
|
|
44
|
+
@skip = false
|
|
45
|
+
@skip = get(:tt_skip) unless get(:tt_skip) == "NODATA"
|
|
46
|
+
unless Project.value[:options]["case"].nil?
|
|
47
|
+
@skip = true
|
|
48
|
+
@skip = false if Project.value[:options]["case"].include? @id.to_i
|
|
49
|
+
end
|
|
50
|
+
@debug = Project.debug?
|
|
51
|
+
@verbose = Project.value[:verbose]
|
|
52
|
+
|
|
53
|
+
@tmpdir = File.join("var", @config.get(:tt_testname), "tmp", @id.to_s)
|
|
54
|
+
# ensure_dir @tmpdir # REVISE: When we will need this? Samba?
|
|
55
|
+
|
|
56
|
+
@unique_values = {}
|
|
57
|
+
@result = Result.new
|
|
58
|
+
@action_counter = 0
|
|
59
|
+
@action = {
|
|
60
|
+
id: 0,
|
|
61
|
+
weight: 1.0,
|
|
62
|
+
description: "No description!",
|
|
63
|
+
groupname: nil
|
|
64
|
+
}
|
|
65
|
+
@uniques = []
|
|
66
|
+
@sessions = {} # Store opened sessions for this case
|
|
67
|
+
@conn_status = {}
|
|
68
|
+
tempfile :default
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def export(format)
|
|
72
|
+
return if skip?
|
|
73
|
+
|
|
74
|
+
@report.export format
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def filename
|
|
78
|
+
# called from: close_main_report
|
|
79
|
+
@report.filename
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def grade
|
|
83
|
+
return 0.0 if skip
|
|
84
|
+
|
|
85
|
+
@report.tail[:grade]
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def members
|
|
89
|
+
return "-" if skip
|
|
90
|
+
|
|
91
|
+
@report.head[:tt_members] || "noname"
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
alias_method :skip?, :skip
|
|
95
|
+
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
|
# Class Case::Config
|
|
6
6
|
# * get
|
|
@@ -13,8 +13,8 @@ class Case
|
|
|
13
13
|
attr_reader :ialias, :global, :local, :running
|
|
14
14
|
|
|
15
15
|
def initialize(args)
|
|
16
|
-
@ialias = args[:alias] ||
|
|
17
|
-
@global = args[:global] ||
|
|
16
|
+
@ialias = args[:alias] || Project.value[:ialias].clone
|
|
17
|
+
@global = args[:global] || Project.value[:global].clone
|
|
18
18
|
@local = args[:local] || {}
|
|
19
19
|
@running = {}
|
|
20
20
|
|
|
@@ -6,6 +6,8 @@ require_relative "dsl/log"
|
|
|
6
6
|
class Case
|
|
7
7
|
private
|
|
8
8
|
|
|
9
|
+
# READ: @config
|
|
10
|
+
# WRITE: @action, @result, @session
|
|
9
11
|
def run_cmd_on(host)
|
|
10
12
|
protocol = @config.get("#{host}_protocol".to_sym)
|
|
11
13
|
ip = @config.get("#{host}_ip".to_sym)
|
|
@@ -30,15 +32,13 @@ class Case
|
|
|
30
32
|
|
|
31
33
|
def run_cmd_localhost
|
|
32
34
|
@action[:conn_type] = :local
|
|
33
|
-
|
|
34
|
-
@result.
|
|
35
|
-
@result.content =
|
|
35
|
+
resp = my_execute(@action[:command], @action[:encoding])
|
|
36
|
+
@result.exitcode = resp[:exitcode]
|
|
37
|
+
@result.content = resp[:content]
|
|
36
38
|
end
|
|
37
39
|
|
|
38
|
-
##
|
|
39
|
-
# Run remote command
|
|
40
|
-
# @param input_hostname (Symbol or String)
|
|
41
40
|
def run_cmd_remote(input_hostname)
|
|
41
|
+
# @param input_hostname (Symbol or String)
|
|
42
42
|
hostname = input_hostname.to_s
|
|
43
43
|
i = (hostname + "_protocol").to_sym
|
|
44
44
|
protocol = @config.get(i) if @config.get(i)
|
|
@@ -86,6 +86,7 @@ class Case
|
|
|
86
86
|
end
|
|
87
87
|
|
|
88
88
|
text = ""
|
|
89
|
+
exitcode = 0
|
|
89
90
|
begin
|
|
90
91
|
if @sessions[hostname].nil?
|
|
91
92
|
@sessions[hostname] = Net::SSH.start(
|
|
@@ -100,23 +101,24 @@ class Case
|
|
|
100
101
|
end
|
|
101
102
|
text = if @sessions[hostname].instance_of? Net::SSH::Connection::Session
|
|
102
103
|
@sessions[hostname].exec!(@action[:command])
|
|
103
|
-
# ssh.exec!("ls -l /home/jamis") do |channel, stream, data|
|
|
104
|
-
# stdout << data if stream == :stdout
|
|
105
|
-
# end
|
|
106
104
|
else
|
|
107
105
|
"SSH: NO CONNECTION!"
|
|
108
106
|
end
|
|
107
|
+
exitcode = text.exitstatus
|
|
109
108
|
rescue Errno::EHOSTUNREACH
|
|
110
109
|
@sessions[hostname] = :nosession
|
|
111
110
|
@conn_status[hostname] = :host_unreachable
|
|
111
|
+
exitcode = -1
|
|
112
112
|
log("Host #{ip} unreachable!", :error)
|
|
113
113
|
rescue Net::SSH::AuthenticationFailed
|
|
114
114
|
@sessions[hostname] = :nosession
|
|
115
115
|
@conn_status[hostname] = :error_authentication_failed
|
|
116
|
+
exitcode = -1
|
|
116
117
|
log("SSH::AuthenticationFailed!", :error)
|
|
117
118
|
rescue Net::SSH::HostKeyMismatch
|
|
118
119
|
@sessions[hostname] = :nosession
|
|
119
120
|
@conn_status[hostname] = :host_key_mismatch
|
|
121
|
+
exitcode = -1
|
|
120
122
|
log("SSH::HostKeyMismatch!", :error)
|
|
121
123
|
log("* The destination server's fingerprint is not matching " \
|
|
122
124
|
"what is in your local known_hosts file.", :error)
|
|
@@ -126,11 +128,12 @@ class Case
|
|
|
126
128
|
rescue => e
|
|
127
129
|
@sessions[hostname] = :nosession
|
|
128
130
|
@conn_status[hostname] = :error
|
|
131
|
+
exitcode = -1
|
|
129
132
|
log("[#{e.class}] SSH on <#{username}@#{ip}>" \
|
|
130
133
|
" exec: #{@action[:command]}", :error)
|
|
131
134
|
end
|
|
132
135
|
output = encode_and_split(@action[:encoding], text)
|
|
133
|
-
|
|
136
|
+
@result.exitcode = exitcode
|
|
134
137
|
@result.content = output
|
|
135
138
|
@result.content.compact!
|
|
136
139
|
end
|
|
@@ -180,6 +183,7 @@ class Case
|
|
|
180
183
|
" ip=<#{ip}>, HOSTID=<#{hostname}>", :warn)
|
|
181
184
|
end
|
|
182
185
|
output = encode_and_split(@action[:encoding], text)
|
|
186
|
+
@result.exitcode = -1
|
|
183
187
|
@result.content = output
|
|
184
188
|
@result.content.compact!
|
|
185
189
|
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
require "open3"
|
|
2
|
+
require "rainbow"
|
|
3
|
+
require_relative "../utils/project"
|
|
4
|
+
|
|
5
|
+
module Utils
|
|
6
|
+
def encode_and_split(encoding, text)
|
|
7
|
+
# Convert text to UTF-8 deleting unknown chars
|
|
8
|
+
text ||= "" # Ensure text is not nil
|
|
9
|
+
flag = [:default, "UTF-8"].include? encoding
|
|
10
|
+
return text.encode("UTF-8", invalid: :replace).split("\n") if flag
|
|
11
|
+
|
|
12
|
+
# Convert text from input ENCODING to UTF-8
|
|
13
|
+
ec = Encoding::Converter.new(encoding.to_s, "UTF-8")
|
|
14
|
+
begin
|
|
15
|
+
text = ec.convert(text)
|
|
16
|
+
rescue => e
|
|
17
|
+
warn "[ERROR] #{e}"
|
|
18
|
+
warn " Suggest declare text encoding, for example:"
|
|
19
|
+
warn " run 'command', on: :host, :encoding => 'ISO-8859-1'"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
text.split("\n")
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def my_execute(cmd, encoding = "UTF-8")
|
|
26
|
+
# TODO: mover a la clase ExecuteManager
|
|
27
|
+
return {exitstatus: 0, content: ""} if Project.debug?
|
|
28
|
+
|
|
29
|
+
begin
|
|
30
|
+
text, status = Open3.capture2e(cmd)
|
|
31
|
+
exitstatus = status.exitstatus
|
|
32
|
+
rescue => e
|
|
33
|
+
verbose Rainbow("!").green
|
|
34
|
+
text = e.to_s
|
|
35
|
+
exitstatus = 1
|
|
36
|
+
end
|
|
37
|
+
content = encode_and_split(encoding, text)
|
|
38
|
+
{exitstatus: exitstatus, content: content}
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module DSL
|
|
4
|
+
# expect, expect2, expect_any, expect_first, expect_last
|
|
5
|
+
# expect_nothing, expect_none, expect_one
|
|
6
|
+
|
|
4
7
|
# expect <condition>, :weight => <value>
|
|
5
8
|
def expect(input, args = {})
|
|
6
9
|
if input.instance_of?(TrueClass) || input.instance_of?(FalseClass)
|
|
@@ -16,18 +19,16 @@ module DSL
|
|
|
16
19
|
@action_counter += 1
|
|
17
20
|
@action[:id] = @action_counter
|
|
18
21
|
@action[:check] = cond
|
|
19
|
-
@action[:result] = @result.value
|
|
20
22
|
|
|
21
|
-
@action[:
|
|
22
|
-
@action[:expected] = @result.expected
|
|
23
|
-
@action[:expected] = args[:expected] if args[:expected]
|
|
23
|
+
@action[:result] = (args[:value] || @result.value)
|
|
24
24
|
|
|
25
|
+
@action[:alterations] = @result.alterations
|
|
26
|
+
@action[:expected] = (args[:expected] || @result.expected)
|
|
25
27
|
@report.lines << @action.clone
|
|
26
28
|
weight(1.0)
|
|
27
29
|
|
|
28
|
-
|
|
29
|
-
c =
|
|
30
|
-
c = app.letter[:good] if cond
|
|
30
|
+
c = Settings.letter[:bad]
|
|
31
|
+
c = Settings.letter[:good] if cond
|
|
31
32
|
verbose Rainbow(c).green
|
|
32
33
|
end
|
|
33
34
|
|
|
@@ -40,6 +41,22 @@ module DSL
|
|
|
40
41
|
expect2 result.count.gt(0), args
|
|
41
42
|
end
|
|
42
43
|
|
|
44
|
+
def expect_exit(value)
|
|
45
|
+
@result.alterations = "Read exit code"
|
|
46
|
+
real_value = result.exitcode
|
|
47
|
+
cond = if value.is_a? Range
|
|
48
|
+
expect_value = "With range #{value}"
|
|
49
|
+
value.to_a.include? real_value
|
|
50
|
+
elsif value.is_a? Array
|
|
51
|
+
expect_value = "Inside list #{value}"
|
|
52
|
+
value.include? real_value
|
|
53
|
+
else
|
|
54
|
+
expect_value = value
|
|
55
|
+
(real_value == value.to_i)
|
|
56
|
+
end
|
|
57
|
+
expect2 cond, value: real_value, expected: expect_value
|
|
58
|
+
end
|
|
59
|
+
|
|
43
60
|
def expect_first(input, args = {})
|
|
44
61
|
@result.first
|
|
45
62
|
output = input
|
|
@@ -54,7 +71,6 @@ module DSL
|
|
|
54
71
|
expect2 input, expected: output
|
|
55
72
|
end
|
|
56
73
|
|
|
57
|
-
# def expect_none(input, args = {})
|
|
58
74
|
def expect_nothing(args = {})
|
|
59
75
|
expect2 result.count.eq(0), args
|
|
60
76
|
end
|
|
@@ -79,8 +95,8 @@ module DSL
|
|
|
79
95
|
expect2 result.count.eq(1), args
|
|
80
96
|
end
|
|
81
97
|
|
|
82
|
-
# Set weight value for the action
|
|
83
98
|
def weight(value = nil)
|
|
99
|
+
# Set weight value for the action
|
|
84
100
|
if value.nil?
|
|
85
101
|
@action[:weight]
|
|
86
102
|
elsif value == :default
|