teuton 2.8.0 → 2.9.1

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.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +4 -4
  3. data/docs/changelog/changelog.1.md +119 -0
  4. data/docs/changelog/changelog.2.md +109 -0
  5. data/docs/diagram.md +10 -10
  6. data/docs/dsl/expect.md +76 -25
  7. data/docs/dsl/result.md +24 -30
  8. data/docs/learn/02-target.md +32 -27
  9. data/docs/learn/25-expect-result.md +39 -0
  10. data/docs/learn/26-expect_sequence.md +79 -0
  11. data/docs/learn/27-run_script.md +91 -0
  12. data/docs/learn/28-upload.md +55 -0
  13. data/docs/learn/README.md +4 -15
  14. data/docs/videos.md +14 -8
  15. data/lib/teuton/case/case.rb +3 -2
  16. data/lib/teuton/case/config.rb +0 -5
  17. data/lib/teuton/case/dsl/all.rb +5 -1
  18. data/lib/teuton/case/dsl/expect.rb +13 -42
  19. data/lib/teuton/case/dsl/expect_exitcode.rb +31 -0
  20. data/lib/teuton/case/dsl/expect_sequence.rb +173 -0
  21. data/lib/teuton/case/dsl/getset.rb +0 -1
  22. data/lib/teuton/case/dsl/host.rb +5 -0
  23. data/lib/teuton/case/dsl/macro.rb +7 -3
  24. data/lib/teuton/case/dsl/run_script.rb +35 -0
  25. data/lib/teuton/case/dsl/upload.rb +42 -0
  26. data/lib/teuton/case/dsl/weight.rb +12 -0
  27. data/lib/teuton/case/host.rb +68 -0
  28. data/lib/teuton/case/play.rb +2 -6
  29. data/lib/teuton/{utils → case}/result/ext_array.rb +0 -1
  30. data/lib/teuton/{utils → case}/result/ext_compare.rb +0 -1
  31. data/lib/teuton/{utils → case}/result/ext_filter.rb +0 -2
  32. data/lib/teuton/{utils → case}/result/result.rb +13 -21
  33. data/lib/teuton/check/checker.rb +82 -0
  34. data/lib/teuton/check/dsl/all.rb +37 -0
  35. data/lib/teuton/check/{builtin.rb → dsl/builtin.rb} +1 -3
  36. data/lib/teuton/check/dsl/expect.rb +90 -0
  37. data/lib/teuton/check/dsl/expect_sequence.rb +29 -0
  38. data/lib/teuton/check/dsl/getset.rb +23 -0
  39. data/lib/teuton/check/dsl/run.rb +35 -0
  40. data/lib/teuton/check/main.rb +29 -0
  41. data/lib/teuton/check/show.rb +75 -100
  42. data/lib/teuton/deprecated/application_test.rb +32 -0
  43. data/lib/teuton/readme/dsl/all.rb +32 -0
  44. data/lib/teuton/readme/dsl/expect.rb +29 -0
  45. data/lib/teuton/readme/dsl/getset.rb +33 -0
  46. data/lib/teuton/readme/dsl/run.rb +51 -0
  47. data/lib/teuton/readme/lang.rb +8 -10
  48. data/lib/teuton/readme/main.rb +27 -0
  49. data/lib/teuton/readme/readme.rb +31 -58
  50. data/lib/teuton/readme/result.rb +7 -0
  51. data/lib/teuton/utils/configfile_reader.rb +25 -10
  52. data/lib/teuton/utils/logger.rb +32 -0
  53. data/lib/teuton/utils/verbose.rb +1 -1
  54. data/lib/teuton/version.rb +1 -1
  55. data/lib/teuton.rb +6 -5
  56. metadata +45 -39
  57. data/docs/CHANGELOG.md +0 -10
  58. data/docs/changelog/v2.0.md +0 -18
  59. data/docs/changelog/v2.1.md +0 -54
  60. data/docs/changelog/v2.2.md +0 -42
  61. data/docs/changelog/v2.3.md +0 -10
  62. data/docs/changelog/v2.4.md +0 -41
  63. data/docs/changelog/v2.5.md +0 -6
  64. data/docs/changelog/v2.6.md +0 -4
  65. data/docs/changelog/v2.7.md +0 -23
  66. data/docs/changelog/v2.8.md +0 -11
  67. data/docs/changelog/version2.1.md +0 -4
  68. data/docs/learn/videos.md +0 -13
  69. data/lib/teuton/case/execute/copy_ssh.rb +0 -70
  70. data/lib/teuton/check/dsl.rb +0 -112
  71. data/lib/teuton/check/laboratory.rb +0 -59
  72. data/lib/teuton/readme/dsl.rb +0 -126
  73. /data/lib/teuton/case/dsl/{goto.rb → run.rb} +0 -0
  74. /data/lib/teuton/{utils → deprecated}/application.rb +0 -0
  75. /data/lib/teuton/{case/deprecated → deprecated}/runner.rb +0 -0
  76. /data/lib/teuton/{case/deprecated → deprecated}/utils.rb +0 -0
@@ -0,0 +1,79 @@
1
+ [<<back](README.md)
2
+
3
+ # DSL: expect_sequence
4
+
5
+ Evaluate the occurrence of a certain sequence that takes place in different lines of the output.
6
+
7
+ > Example files at [examples/26-expect_sequence](../../examples/26-expect_sequence)
8
+
9
+ ## Description
10
+
11
+ In the classic target/run/expect, the expect statement works by locating lines from the output of the previous command that meet certain criteria.
12
+
13
+ We can even (using regular expressions) detect if there is any line in the output where a certain sequence appears.
14
+
15
+
16
+ ```ruby
17
+ # Example:
18
+ # expect with regular expression to detect [a, b, c] sequence
19
+ # within a line
20
+
21
+ expect /a.*?b.*?c/
22
+ ```
23
+
24
+ > Regular expressions are very powerful but they are also complex to use.
25
+
26
+ To evaluate the occurrence of a certain sequence that takes place in different lines of the output we will use the new "expect_sequence" instruction.
27
+
28
+
29
+ ```ruby
30
+ # Example:
31
+ # expect_sequence to detect [a, b, c] sequence
32
+
33
+ expect_sequence do
34
+ find "a"
35
+ find "b"
36
+ find "c"
37
+ end
38
+ ```
39
+
40
+ > NOTE: expect_sequence can be useful for evaluating iptables firewall configurations where permission assignment order is relevant.
41
+
42
+ ## Evaluating different sequences
43
+
44
+ * **Simple sequence**. Validate sequences where the elements are in order. Use `find` statement to find each element of the sequence.
45
+
46
+ ```ruby
47
+ # Examples: [A,B,C], [A,s,B,s,C], [x,A,B,s,C,x], etc.
48
+
49
+ expect_sequence do
50
+ find "A"
51
+ find "B"
52
+ find "C"
53
+ end
54
+ ```
55
+
56
+ * **Strict sequence**. validate sequences where the elements are in strict consecutive order. First use `find` to find an element in the sequence and then `next_to` for the next element in strict order.
57
+
58
+ ```ruby
59
+ # Examples: [A,B,C], [x,A,B,C,x], etc.
60
+
61
+ expect_sequence do
62
+ find "A"
63
+ next_to "B"
64
+ next_to "C"
65
+ end
66
+ ```
67
+
68
+ * **Strict sequence with jumps**. Use `ignore N` to indicate that there are N lines between 2 elements of the sequence.
69
+
70
+ ```ruby
71
+ # Examples: [A,B,s,s,C], [x,A,B,s,s,C,x], etc.
72
+
73
+ expect_sequence do
74
+ find "A"
75
+ next_to "B"
76
+ ignore 2
77
+ next_to "C"
78
+ end
79
+ ```
@@ -0,0 +1,91 @@
1
+ [<<back](README.md)
2
+
3
+ # DSL: run_script
4
+
5
+ You know the classic sequence `target/run/expect`, but sometimes you need to run our own script files on the remote computer. So you have to:
6
+
7
+ 1. Upload a copy of the script file to the remote host
8
+ 2. and then run it on remote host
9
+
10
+ **run_script** upload and execute your own local script on remote host.
11
+
12
+ > Example files at [examples/27-run_file](../../examples/27-run_script)
13
+
14
+ ## Example scripts
15
+
16
+ Suppose we have the following files:
17
+ ```
18
+ example
19
+ ├── config.yaml
20
+ ├── show.sh
21
+ └── start.rb
22
+ ```
23
+
24
+ Contents of the `show.sh` script:
25
+ ```bash
26
+ #!/usr/bin/env bash
27
+ MESSAGE=$1
28
+ echo $MESSAGE
29
+ exit 0
30
+ ```
31
+
32
+ ## Usage examples
33
+
34
+ `run_script` is the DSL keyword in charge of uploading the script to the remote computer and executing it. When invoking run_script we have two styles: compact or separate components. Let's see
35
+
36
+ **Compact invocation**: The "command" to execute contains the interpreter, the script, and the arguments.
37
+
38
+ ```ruby
39
+ target "Mode 1: Upload script and execute on remote host"
40
+ run_script "bash show.sh Hello", on: :host1
41
+ expect "Hello"
42
+ ```
43
+
44
+ **Separate components**: pass the name of the script, the interpreter in charge of processing it and its arguments through separate parameters.
45
+
46
+ ```ruby
47
+ target "Mode 2: Upload script and execute on remote host"
48
+ run_script "show.sh", shell: "bash", args: "Hello", on: :host1
49
+ expect "Hello"
50
+ ```
51
+
52
+ Or setting shell default value:
53
+
54
+ ```ruby
55
+ set(:shell, "bash")
56
+
57
+ target "Mode 2: Upload script and execute on remote host"
58
+ run_script "show.sh", args: "Hello", on: :host1
59
+ expect "Hello"
60
+ ```
61
+
62
+ ## Running example
63
+
64
+ ```
65
+ ------------------------------------
66
+ Started at 2023-07-23 13:46:11 +0100
67
+ ....uu..u.u.u.uu..u.!F!F!F!F
68
+ Finished in 30.457 seconds
69
+ ------------------------------------
70
+
71
+ CASE RESULTS
72
+ +------+-----------+-------+-------+
73
+ | CASE | MEMBERS | GRADE | STATE |
74
+ | 01 | Localhost | 100.0 | ✔ |
75
+ | 02 | Remote1 | 100.0 | ✔ |
76
+ | 03 | Remote2 | 100.0 | ✔ |
77
+ | 04 | Remote3 | 0.0 | ? |
78
+ +------+-----------+-------+-------+
79
+
80
+ CONN ERRORS
81
+ +------+---------+-------+------------------+
82
+ | CASE | MEMBERS | HOST | ERROR |
83
+ | 04 | Remote3 | host1 | host_unreachable |
84
+ +------+---------+-------+------------------+
85
+ ```
86
+
87
+ Meaning of progress symbols:
88
+ * `.`: check ok
89
+ * `F`: check fail
90
+ * `!`: connection fail
91
+ * `u`: upload ok
@@ -0,0 +1,55 @@
1
+ [<<back](README.md)
2
+
3
+ # DSL: upload
4
+
5
+ `upload` is a dsl instruction, whose purpose is to upload files to the remote host.
6
+
7
+ ```ruby
8
+ upload "FILENAME", to: :host1
9
+ ```
10
+
11
+ * `upload "FILENAME"`, upload local file to remote.
12
+ * `to: :host1`, specifies remote host.
13
+
14
+ > Example files at [examples/28-upload](../../examples/28-upload)
15
+
16
+ ## Other options
17
+
18
+ * Upload "LOCALDIR/FILENAME" to default remote dir into remote host:
19
+
20
+ ```ruby
21
+ upload "LOCALDIR/FILENAME", to: :host1
22
+ ```
23
+
24
+ * Upload "LOCALDIR/FILENAME" to remote dir into remote host:
25
+
26
+ ```ruby
27
+ upload "LOCALDIR/FILENAME", remotedir: "REMOTEDIR", to: :host1
28
+ ```
29
+
30
+ * Upload several local files from "LOCALDIR" to default remote dir into host:
31
+
32
+ ```ruby
33
+ upload "LOCALDIR/*", to: :host1
34
+ ```
35
+
36
+ * Upload several local files from "LOCALDIR" to remote host:
37
+
38
+ ```ruby
39
+ upload "LOCALDIR/*", remotedir: "REMOTEDIR", to: :host1
40
+ ```
41
+
42
+ ## Example
43
+
44
+ ```ruby
45
+ target "Upload file and then run it"
46
+ upload "script/show.sh", remotedir: "sh", to: :host1
47
+ run "bash sh/show.sh HelloWorld", on: :host1
48
+ expect "HelloWorld"
49
+ ```
50
+
51
+ Example steps:
52
+ 1. Describe target.
53
+ 2. Upload local file to remote host.
54
+ 3. Run script using Bash on remote host.
55
+ 4. Evaluate script output.
data/docs/learn/README.md CHANGED
@@ -28,20 +28,9 @@ Learn how write your own Teuton tests:
28
28
  1. [RESULT object](22-result.md)
29
29
  1. [Test code](23-test-code.md)
30
30
  1. [Test SQL and database](24-test-sql.md)
31
+ 1. [expect vs result](25-expect-result.md) TODO
32
+ 1. [EXPECT_SEQUENCE](26-expect_sequence.md)
33
+ 1. [RUN_SCRIPT](27-run_script.md)
34
+ 1. [UPLOAD](28-upload.md)
31
35
 
32
36
  Mores examples at [teuton-tests](https://github.com/dvarrui/teuton-tests) GitHub repository.
33
-
34
- # Videos
35
-
36
- By now there are no English videos. We are sorry!
37
- But if you want to see Spanish videos, here you are:
38
-
39
- Teuton (v2.0):
40
- * [ES - CHAPI19: Charla Teuton](https://youtu.be/KFWQDfNAFxI?t=12221)
41
- * [ES - CHAPI19: Teuton demo](https://github.com/dvarrui/proyectos-de-ejemplo/tree/master/charlas/teuton)
42
-
43
- Sysadmingame (Teuton v1.0)
44
- * [Sysadmingame (1 de 3): Instalación del programa](https://youtu.be/dnyMq9_KDco)
45
- * [Sysadmingame (2 de 3): Crear un caso simple](https://youtu.be/0e2g5Izvc6c)
46
- * [Sysadmingame (3 de 3): Crear un caso complejo](https://youtu.be/ebEK6OXH8kQ)
47
- * [CHAPI16 - Charla sysadmingame](https://youtu.be/cNJaB5xzHHQ)
data/docs/videos.md CHANGED
@@ -7,14 +7,20 @@
7
7
 
8
8
  # Videos
9
9
 
10
- Teuton:
10
+ > By now there are no English videos. We are sorry!
11
+
12
+ Teuton v2.1:
11
13
  * [Apuntes FP Informática - I Congreso Virtual - Mayo 2020](https://youtu.be/RxIV26BAoGo)
12
- * [Teuton Software 2.1 - Tutorial - Oct 2020](https://youtu.be/cyBN-rOYQeY)
14
+ * [Teuton Software 2.1 - Tutorial - Abr 2020](https://youtu.be/cyBN-rOYQeY)
13
15
 
14
- Teuton en el 2016 se llamaba "sysadmingame".
15
- * ES -[CHAPI16 - Presentación sysadmingame chapi16 - Abril 2016](https://youtu.be/cNJaB5xzHHQ)
16
- * sysadmingame:
17
- 1. [Instalación del programa](https://youtu.be/dnyMq9_KDco)
18
- 2. [Crear un caso simple](https://youtu.be/0e2g5Izvc6c)
19
- 3. [Crear un caso complejo](https://youtu.be/ebEK6OXH8kQ)
16
+ Teuton v2.0:
17
+ * [ES - CHAPI19: Charla Teuton](https://youtu.be/KFWQDfNAFxI?t=12221)
18
+ * [ES - CHAPI19: Teuton demo](https://github.com/dvarrui/proyectos-de-ejemplo/tree/master/charlas/teuton)
20
19
 
20
+ Sysadmingame (Teuton v1.0):
21
+ * [Sysadmingame (1 de 3): Instalación del programa](https://youtu.be/dnyMq9_KDco)
22
+ * [Sysadmingame (2 de 3): Crear un caso simple](https://youtu.be/0e2g5Izvc6c)
23
+ * [Sysadmingame (3 de 3): Crear un caso complejo](https://youtu.be/ebEK6OXH8kQ)
24
+
25
+ Sysadmingame: En el 2016 el proyecto se llamaba "sysadmingame".
26
+ * ES -[CHAPI16 - Presentación sysadmingame chapi16 - Abril 2016](https://youtu.be/cNJaB5xzHHQ)
@@ -2,13 +2,14 @@
2
2
 
3
3
  require_relative "../utils/project"
4
4
  require_relative "../utils/verbose"
5
- require_relative "../utils/result/result"
6
5
  require_relative "../report/report"
7
6
  require_relative "dsl/all"
8
7
  require_relative "config"
9
8
  require_relative "close"
9
+ # require_relative "builtin/main"
10
+ require_relative "host"
10
11
  require_relative "play"
11
- require_relative "builtin/main"
12
+ require_relative "result/result"
12
13
 
13
14
  class Case
14
15
  include DSL
@@ -2,11 +2,6 @@
2
2
 
3
3
  require_relative "../utils/project"
4
4
 
5
- # Class Case::Config
6
- # * get
7
- # * set
8
- # * unset
9
- # * missing_method
10
5
  class Case
11
6
  class Config
12
7
  # This class manage configuration for only one case
@@ -1,8 +1,12 @@
1
1
  require_relative "expect"
2
2
  require_relative "getset"
3
- require_relative "goto"
3
+ require_relative "host"
4
4
  require_relative "log"
5
5
  require_relative "macro"
6
+ require_relative "run"
7
+ require_relative "run_script"
6
8
  require_relative "send"
7
9
  require_relative "target"
8
10
  require_relative "unique"
11
+ require_relative "upload"
12
+ require_relative "weight"
@@ -1,17 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module DSL
4
- # expect, expect2, expect_any, expect_first, expect_last
5
- # expect_nothing, expect_none, expect_one
3
+ require_relative "expect_exitcode"
4
+ require_relative "expect_sequence"
6
5
 
7
- # expect <condition>, :weight => <value>
6
+ module DSL
7
+ # expect <condition>,
8
+ # value: RealValue,
9
+ # expected: ExpectedValue,
10
+ # weight: float
11
+ #
8
12
  def expect(input, args = {})
9
13
  if input.instance_of?(TrueClass) || input.instance_of?(FalseClass)
10
14
  expect2(input, args)
11
15
  elsif input.instance_of?(String) || input.instance_of?(Regexp) || input.instance_of?(Array)
12
16
  expect_any input
13
17
  else
14
- puts Rainbow("[TypeError] expect #{input} (#{input.class})").red
18
+ puts Rainbow("[ERROR] Case expect TypeError: expect #{input} (#{input.class})").red
15
19
  end
16
20
  end
17
21
 
@@ -45,30 +49,6 @@ module DSL
45
49
  expect2 result.count.gt(0), args
46
50
  end
47
51
 
48
- def expect_exit(value)
49
- @result.alterations = "Read exit code"
50
- real_value = result.exitcode
51
- cond = if value.is_a? Range
52
- expect_value = "With range #{value}"
53
- value.to_a.include? real_value
54
- elsif value.is_a? Array
55
- expect_value = "Inside list #{value}"
56
- value.include? real_value
57
- else
58
- expect_value = value
59
- (real_value == value.to_i)
60
- end
61
- expect2 cond, value: real_value, expected: expect_value
62
- end
63
-
64
- def expect_fail
65
- @result.alterations = "Read exit code"
66
- real_value = result.exitcode
67
- expect_value = "Greater than 0"
68
- cond = (real_value > 0)
69
- expect2 cond, value: real_value, expected: expect_value
70
- end
71
-
72
52
  def expect_first(input, args = {})
73
53
  @result.first
74
54
  output = input
@@ -107,18 +87,9 @@ module DSL
107
87
  expect2 result.count.eq(1), args
108
88
  end
109
89
 
110
- def expect_ok
111
- expect_exit 0
112
- end
113
-
114
- def weight(value = nil)
115
- # Set weight value for the action
116
- if value.nil?
117
- @action[:weight]
118
- elsif value == :default
119
- @action[:weight] = 1.0
120
- else
121
- @action[:weight] = value.to_f
122
- end
90
+ def expect_sequence(&block)
91
+ seq = ExpectSequence.new(result.content.dup)
92
+ cond = seq.is_valid?(&block)
93
+ expect2 cond, value: seq.real, expected: seq.expected
123
94
  end
124
95
  end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DSL
4
+ def expect_exit(value)
5
+ @result.alterations = "Read exit code"
6
+ real_value = result.exitcode
7
+ cond = if value.is_a? Range
8
+ expect_value = "With range #{value}"
9
+ value.to_a.include? real_value
10
+ elsif value.is_a? Array
11
+ expect_value = "Inside list #{value}"
12
+ value.include? real_value
13
+ else
14
+ expect_value = value
15
+ (real_value == value.to_i)
16
+ end
17
+ expect2 cond, value: real_value, expected: expect_value
18
+ end
19
+
20
+ def expect_fail
21
+ @result.alterations = "Read exit code"
22
+ real_value = result.exitcode
23
+ expect_value = "Greater than 0"
24
+ cond = (real_value > 0)
25
+ expect2 cond, value: real_value, expected: expect_value
26
+ end
27
+
28
+ def expect_ok
29
+ expect_exit 0
30
+ end
31
+ end
@@ -0,0 +1,173 @@
1
+ class ExpectSequence
2
+ attr_reader :result
3
+ attr_reader :states
4
+
5
+ def initialize(lines)
6
+ @lines = lines
7
+ end
8
+
9
+ def is_valid?(&block)
10
+ @expected = []
11
+ @states = [
12
+ {last_index: -1, steps: [], found: []}
13
+ ]
14
+ instance_eval(&block)
15
+ @result = find_best_state
16
+ @result[:ok]
17
+ end
18
+
19
+ def expected
20
+ @expected.join(">")
21
+ end
22
+
23
+ def real
24
+ # From final result return evaluation progress
25
+ text = []
26
+ @result[:steps].each do |step|
27
+ index = text.size
28
+ text << if step
29
+ @expected[index]
30
+ else
31
+ "not #{@expected[index]}"
32
+ end
33
+ end
34
+ text.join(">")
35
+ end
36
+
37
+ private
38
+
39
+ def find_best_state
40
+ @states.each do |state|
41
+ state[:score] = (state[:steps].select { _1 }).size
42
+ state[:fails] = (state[:steps].select { !_1 }).size
43
+ state[:ok] = (state[:fails] == 0)
44
+ end
45
+ best = @states[0]
46
+ @states.each { |state| best = state if state[:score] > best[:score] }
47
+ best
48
+ end
49
+
50
+ def find(value)
51
+ @expected << "find(#{value})"
52
+ newstates = []
53
+ @states.each do |state|
54
+ last_index = state[:last_index]
55
+
56
+ if last_index > (@lines.size - 1)
57
+ steps = state[:steps].clone
58
+ steps << false
59
+ newstates << {
60
+ last_index: last_index,
61
+ steps: steps,
62
+ found: state[:found].clone
63
+ }
64
+ next
65
+ end
66
+
67
+ findindexes = get_indexes(value: value, from: last_index)
68
+ findindexes.each do |findindex|
69
+ found = state[:found].clone
70
+ found << findindex
71
+ steps = state[:steps].clone
72
+ steps << true
73
+ newstates << {
74
+ last_index: findindex,
75
+ steps: steps,
76
+ found: found
77
+ }
78
+ end
79
+ end
80
+ @states = if newstates.size.zero?
81
+ @states.each { |state| state[:steps] << false }
82
+ else
83
+ newstates
84
+ end
85
+ end
86
+
87
+ def next_to(value)
88
+ @expected << "next_to(#{value})"
89
+ newstates = []
90
+
91
+ @states.each do |state|
92
+ last_index = state[:last_index]
93
+
94
+ if last_index > (@lines.size - 1)
95
+ steps = state[:steps].clone
96
+ steps << false
97
+ newstates << {
98
+ last_index: last_index,
99
+ steps: steps,
100
+ found: state[:found].clone
101
+ }
102
+ next
103
+ end
104
+
105
+ last_index += 1
106
+ found = state[:found].clone
107
+ steps = state[:steps].clone
108
+ line = @lines[last_index]
109
+ if line.include?(value)
110
+ found << last_index
111
+ steps << true
112
+ else
113
+ steps << false
114
+ end
115
+ newstates << {
116
+ last_index: last_index,
117
+ steps: steps,
118
+ found: found
119
+ }
120
+ end
121
+ @states = if newstates.size.zero?
122
+ @states.each { |state| state[:steps] << false }
123
+ else
124
+ newstates
125
+ end
126
+ end
127
+
128
+ def ignore(value)
129
+ @expected << "ignore(#{value})"
130
+ newstates = []
131
+ @states.each do |state|
132
+ last_index = state[:last_index] + value.to_i
133
+
134
+ steps = state[:steps].clone
135
+ steps << !(last_index > (@lines.size - 1))
136
+
137
+ newstates << {
138
+ last_index: last_index,
139
+ steps: steps,
140
+ found: state[:found].clone
141
+ }
142
+ end
143
+
144
+ @states = if newstates.size.zero?
145
+ @states.each { |state| state[:steps] << false }
146
+ else
147
+ newstates
148
+ end
149
+ end
150
+
151
+ def get_indexes(value:, from:)
152
+ indexes = []
153
+
154
+ @lines.each_with_index do |line, index|
155
+ next if index < from
156
+
157
+ indexes << index if line_include_value?(line: line, value: value)
158
+ end
159
+ indexes
160
+ end
161
+
162
+ def line_include_value?(line:, value:)
163
+ if value.is_a? String
164
+ return true if line.include? value
165
+ elsif value.is_a? Regexp
166
+ return true << index if value.match(line)
167
+ else
168
+ puts "[ERROR] expect_sequence #{value.class}"
169
+ exit 1
170
+ end
171
+ false
172
+ end
173
+ end
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # DSL#get and DSL#set
4
3
  module DSL
5
4
  # Read param option from [running, config or global] Hash data
6
5
  def get(option)
@@ -0,0 +1,5 @@
1
+ module DSL
2
+ def get_host(id)
3
+ Case::Host.new(config).get(id)
4
+ end
5
+ end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "../../utils/project"
4
+ require_relative "../../utils/logger"
4
5
 
5
6
  module DSL
6
7
  ##
@@ -10,7 +11,9 @@ module DSL
10
11
  def macro(name, input = {})
11
12
  macros = Project.value[:macros]
12
13
  unless macros[name]
13
- log("Macro #{name} not found!", :error)
14
+ msg = "DSL '#{name}' not found!"
15
+ log(msg, :error)
16
+ Logger.error("ERROR #{msg}")
14
17
  return
15
18
  end
16
19
  input.each_pair { |k, v| set(k, v) }
@@ -32,9 +35,10 @@ module DSL
32
35
  def method_missing(method, args = {})
33
36
  a = method.to_s
34
37
  if a.start_with?("_")
35
- return instance_eval("get(:#{a[1, a.size - 1]})", __FILE__, __LINE__)
38
+ return instance_eval("get(:#{a[1, a.size]})", __FILE__, __LINE__)
39
+ elsif a[0, 6] == "macro_"
40
+ return macro a[6, a.size], args
36
41
  end
37
- return macro a[6, a.size], args if a[0, 6] == "macro_"
38
42
  macro a, args
39
43
  end
40
44
 
@@ -0,0 +1,35 @@
1
+ require_relative "../../utils/project"
2
+ require_relative "../../utils/verbose"
3
+
4
+ module DSL
5
+ def run_script(script, args = {})
6
+ items = script.split(" ")
7
+ if items.size == 1
8
+ shell = args[:shell] || ((get(:shell) != "NODATA") ? get(:shell) : nil)
9
+ script = "#{shell} #{script}" if shell
10
+ script = "#{script} #{args[:args]} " if args[:args]
11
+ end
12
+
13
+ items = script.split(" ")
14
+ if items.size < 1
15
+ msg = Rainbow("==> [ERROR] run_script: Incorrect command '#{command}'").red
16
+ verboseln(msg)
17
+ return
18
+ end
19
+
20
+ host = get_host(args[:on])
21
+ if host.protocol == "local"
22
+ items[1] = File.join(Project.value[:project_path], items[1])
23
+ command = items.join(" ")
24
+ run(command, args)
25
+ elsif host.protocol == "ssh"
26
+ upload items[1], to: host.id
27
+ items[1] = File.basename(items[1])
28
+ command = items.join(" ")
29
+ run(command, args)
30
+ else
31
+ msg = Rainbow("==> [ERROR] run_script: Incorrect protocol(#{host.protocol})").red
32
+ verboseln(msg)
33
+ end
34
+ end
35
+ end