teuton 2.5.0 → 2.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/docs/CHANGELOG.md +2 -0
  3. data/docs/changelog/todo.md +4 -6
  4. data/docs/changelog/v2.6.md +4 -0
  5. data/docs/changelog/v2.7.md +11 -0
  6. data/docs/diagram.md +55 -0
  7. data/docs/learn/02-target.md +37 -12
  8. data/docs/learn/03-remote_hosts.md +1 -1
  9. data/docs/learn/04-config.md +1 -1
  10. data/docs/learn/06-cmd_check.md +4 -6
  11. data/docs/learn/07-target_weight.md +1 -3
  12. data/docs/learn/21-exit_codes.md +9 -16
  13. data/docs/learn/README.md +1 -1
  14. data/lib/teuton/case/case.rb +95 -0
  15. data/lib/teuton/{case_manager/case → case}/close.rb +2 -0
  16. data/lib/teuton/{case_manager/case → case}/config.rb +3 -3
  17. data/lib/teuton/{case_manager/case → case/deprecated}/runner.rb +14 -10
  18. data/lib/teuton/case/deprecated/utils.rb +40 -0
  19. data/lib/teuton/{case_manager/case/dsl/main.rb → case/dsl/all.rb} +0 -2
  20. data/lib/teuton/{case_manager/case → case}/dsl/expect.rb +25 -9
  21. data/lib/teuton/{case_manager/case → case}/dsl/goto.rb +10 -9
  22. data/lib/teuton/{case_manager/case → case}/dsl/log.rb +1 -2
  23. data/lib/teuton/{case_manager/case → case}/dsl/macro.rb +2 -2
  24. data/lib/teuton/{case_manager/case → case}/dsl/send.rb +3 -8
  25. data/lib/teuton/case/execute/execute_base.rb +55 -0
  26. data/lib/teuton/case/execute/execute_local.rb +29 -0
  27. data/lib/teuton/case/execute/execute_manager.rb +56 -0
  28. data/lib/teuton/case/execute/execute_ssh.rb +90 -0
  29. data/lib/teuton/case/execute/execute_telnet.rb +56 -0
  30. data/lib/teuton/{case_manager/case → case}/play.rb +11 -14
  31. data/lib/teuton/case_manager/case_manager.rb +20 -39
  32. data/lib/teuton/case_manager/check_cases.rb +14 -12
  33. data/lib/teuton/case_manager/dsl.rb +7 -9
  34. data/lib/teuton/case_manager/export_manager.rb +19 -6
  35. data/lib/teuton/case_manager/hall_of_fame.rb +9 -10
  36. data/lib/teuton/case_manager/report.rb +11 -9
  37. data/lib/teuton/case_manager/send_manager.rb +17 -0
  38. data/lib/teuton/{report/show.rb → case_manager/show_report.rb} +4 -6
  39. data/lib/teuton/case_manager/utils.rb +2 -43
  40. data/lib/teuton/check/dsl.rb +1 -2
  41. data/lib/teuton/check/laboratory.rb +7 -7
  42. data/lib/teuton/check/show.rb +5 -8
  43. data/lib/teuton/cli.rb +10 -0
  44. data/lib/teuton/readme/dsl.rb +5 -7
  45. data/lib/teuton/readme/lang.rb +3 -2
  46. data/lib/teuton/readme/readme.rb +15 -18
  47. data/lib/teuton/report/formatter/default/array.rb +6 -5
  48. data/lib/teuton/report/formatter/default/txt.rb +1 -0
  49. data/lib/teuton/report/formatter/resume/array.rb +3 -3
  50. data/lib/teuton/report/formatter/resume/html.rb +2 -2
  51. data/lib/teuton/report/report.rb +6 -5
  52. data/lib/teuton/skeleton.rb +8 -10
  53. data/lib/teuton/{application.rb → utils/application.rb} +13 -5
  54. data/lib/teuton/utils/name_file_finder.rb +40 -45
  55. data/lib/teuton/utils/project.rb +73 -0
  56. data/lib/teuton/{case_manager/case → utils}/result/ext_array.rb +5 -5
  57. data/lib/teuton/{case_manager/case → utils}/result/result.rb +10 -8
  58. data/lib/teuton/utils/settings.rb +12 -0
  59. data/lib/teuton/utils/verbose.rb +2 -2
  60. data/lib/teuton/version.rb +1 -1
  61. data/lib/teuton.rb +28 -27
  62. metadata +43 -30
  63. data/lib/teuton/case_manager/case/case.rb +0 -117
  64. data/lib/teuton/case_manager/case/main.rb +0 -7
  65. data/lib/teuton/case_manager/main.rb +0 -3
  66. /data/lib/teuton/{case_manager/case → case}/builtin/main.rb +0 -0
  67. /data/lib/teuton/{case_manager/case → case}/builtin/package.rb +0 -0
  68. /data/lib/teuton/{case_manager/case → case}/builtin/service.rb +0 -0
  69. /data/lib/teuton/{case_manager/case → case}/builtin/teuton_file.rb +0 -0
  70. /data/lib/teuton/{case_manager/case → case}/builtin/teuton_host.rb +0 -0
  71. /data/lib/teuton/{case_manager/case → case}/builtin/user.rb +0 -0
  72. /data/lib/teuton/{case_manager/case → case}/dsl/getset.rb +0 -0
  73. /data/lib/teuton/{case_manager/case → case}/dsl/target.rb +0 -0
  74. /data/lib/teuton/{case_manager/case → case}/dsl/unique.rb +0 -0
  75. /data/lib/teuton/{case_manager/case → utils}/result/ext_compare.rb +0 -0
  76. /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: 8f53359ed5f8eae1b3a798630c5d56ae46076073bface7d3788de57b245a80cb
4
- data.tar.gz: 366afd9ccee6db9bdf5756fe5954050231681763489bab11b1841e9279998c08
3
+ metadata.gz: 7fa647498d568e303c8c02ea44277a595f3796a404a523daf6c1b0408110de97
4
+ data.tar.gz: b733858b7e97b373aca8477a359649b5e6614cdd60caffbdd052e450aa12dffa
5
5
  SHA512:
6
- metadata.gz: a40866560ec0d622b48322c0689dfe36cb9820cf565ce4258a8b71d38a1a3cc88e57f68e208c0d2a6c1a0787b7a2698af0446757bb2167fdf04d2bcd8002178f
7
- data.tar.gz: 288e6105576a15ac25eb20d298bb552b77347b65a3a2df6632d0ef26063061c77c32ef02af88a6f7244790df9573b6e79d7e9fee8b0606006a41b0cd171a51c5
6
+ metadata.gz: 60b94cd2ef2632e1fdbe81515909be71bce35d011f739ecc97806c1cfaa8115a7b743ee4369b54dffe366f1d7b06486fe451827c2fb4ce7fd37448fbf56b549b
7
+ data.tar.gz: 312bd19998b3ef68cc61780dda49cf1711033736a2593206501d5f428cd64780974a2adfc4198dd1097b178f6202637dcc10e11131c90495de553fc33547520f
data/docs/CHANGELOG.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ * [version 2.5](changelog/v2.5.md)
6
+ * [version 2.4](changelog/v2.4.md)
5
7
  * [version 2.3](changelog/v2.3.md)
6
8
  * [version 2.2](changelog/v2.2.md)
7
9
  * [version 2.1](changelog/v2.1.md)
@@ -2,17 +2,15 @@
2
2
  ## TO-DO
3
3
 
4
4
  New features:
5
- - Parse new input format, and detect parse errors
6
- - Teuton readme --lang=es
7
- - Export files with other langs
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,4 @@
1
+
2
+ ## [2.6.0]
3
+
4
+ - [ADD] When running local or SSH commands, stdout and stderr are captured and readed by "expect" sentence.
@@ -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
+ ```
@@ -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/01-target
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
- └── 01-target
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
- > more var/02-target/case-01.txt
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 | 01-target |
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 | 2022-12-24 13:31:28 +0000 |
90
- | finish_time | 2022-12-24 13:31:28 +0000 |
91
- | duration | 0.001880141 |
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 | 1.0 |
94
- | good_weight | 1.0 |
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 |
@@ -43,7 +43,7 @@ Define 1 target (item to be checked):
43
43
  group "Remote hosts" do
44
44
  target "Create user david"
45
45
  run "id david", on: :host1
46
- expect "david"
46
+ expect [ "uid=", "(david)", "gid=" ]
47
47
  end
48
48
  ```
49
49
 
@@ -24,7 +24,7 @@ group "Reading params from config file" do
24
24
 
25
25
  target "Create user #{get(:username)}"
26
26
  run "id #{get(:username)}"
27
- expect get(:username)
27
+ expect [ "uid=", "("+get(:username)+")", "gid=" ]
28
28
 
29
29
  end
30
30
  ```
@@ -3,10 +3,10 @@
3
3
 
4
4
  # check test
5
5
 
6
- Check Teuton test syntax and show statistics.
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) (String)
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) (String)
28
+ expect ["uid=", "(get(username))", "gid="] (Array)
31
29
 
32
30
  +----------------------------+
33
31
  | GROUP: Using file: network |
@@ -1,24 +1,17 @@
1
1
  [<< back](README.md)
2
2
 
3
- # Example: 16-exit_codes
3
+ # Example: exit_codes
4
4
 
5
- _I am sorry! We have not solved the problem of getting the exit code of the commands so that it works for any platform. But we can help you do this work._
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
- `result` stores information from the last command executed by a "run" action. [Offers many functions](../dsl/definition/result.md)) that transforms output data, but also we have been added tow more: first and last.
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;echo $?"
15
- expect_last "0"
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
- All terminal output generated by `run` action is captured (Use `result.debug` to show result content into screen), and as we need only the last line, we use `expect_last "0"`.
21
-
22
- > More information about:
23
- > * [expect](../dsl/definition/expect.md) keyword.
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 ID](14-moodle_id.md)
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
@@ -2,6 +2,8 @@
2
2
 
3
3
  class Case
4
4
  def close(uniques)
5
+ # Invoked from check_cases!
6
+
5
7
  fails = 0
6
8
  @uniques.each do |key|
7
9
  next unless uniques[key].include?(id) && uniques[key].count > 1
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "../../application"
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] || Application.instance.ialias.clone
17
- @global = args[:global] || Application.instance.global.clone
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
- i = my_execute(@action[:command], @action[:encoding])
34
- @result.exitstatus = i[:exitstatus]
35
- @result.content = i[: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
- # revise: @result.exitstatus = text.exitstatus
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,5 +1,3 @@
1
- # frozen_string_literal: true
2
-
3
1
  require_relative "expect"
4
2
  require_relative "getset"
5
3
  require_relative "goto"
@@ -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[:alterations] = @result.alterations
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
- app = Application.instance
29
- c = app.letter[:bad]
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