teuton 2.8.0 → 2.9.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +4 -4
- data/docs/changelog/changelog.1.md +119 -0
- data/docs/changelog/changelog.2.md +109 -0
- data/docs/diagram.md +10 -10
- data/docs/dsl/expect.md +76 -25
- data/docs/dsl/result.md +24 -30
- data/docs/learn/02-target.md +32 -27
- data/docs/learn/25-expect-result.md +39 -0
- data/docs/learn/26-expect_sequence.md +79 -0
- data/docs/learn/27-run_script.md +91 -0
- data/docs/learn/28-upload.md +55 -0
- data/docs/learn/README.md +4 -15
- data/docs/videos.md +14 -8
- data/lib/teuton/case/case.rb +3 -2
- data/lib/teuton/case/config.rb +0 -5
- data/lib/teuton/case/dsl/all.rb +5 -1
- data/lib/teuton/case/dsl/expect.rb +13 -42
- data/lib/teuton/case/dsl/expect_exitcode.rb +31 -0
- data/lib/teuton/case/dsl/expect_sequence.rb +173 -0
- data/lib/teuton/case/dsl/getset.rb +0 -1
- data/lib/teuton/case/dsl/host.rb +5 -0
- data/lib/teuton/case/dsl/macro.rb +7 -3
- data/lib/teuton/case/dsl/run_script.rb +35 -0
- data/lib/teuton/case/dsl/upload.rb +42 -0
- data/lib/teuton/case/dsl/weight.rb +12 -0
- data/lib/teuton/case/host.rb +68 -0
- data/lib/teuton/case/play.rb +2 -6
- data/lib/teuton/{utils → case}/result/ext_array.rb +0 -1
- data/lib/teuton/{utils → case}/result/ext_compare.rb +0 -1
- data/lib/teuton/{utils → case}/result/ext_filter.rb +0 -2
- data/lib/teuton/{utils → case}/result/result.rb +13 -21
- data/lib/teuton/check/checker.rb +82 -0
- data/lib/teuton/check/dsl/all.rb +37 -0
- data/lib/teuton/check/{builtin.rb → dsl/builtin.rb} +1 -3
- data/lib/teuton/check/dsl/expect.rb +90 -0
- data/lib/teuton/check/dsl/expect_sequence.rb +29 -0
- data/lib/teuton/check/dsl/getset.rb +23 -0
- data/lib/teuton/check/dsl/run.rb +35 -0
- data/lib/teuton/check/main.rb +29 -0
- data/lib/teuton/check/show.rb +75 -100
- data/lib/teuton/deprecated/application_test.rb +32 -0
- data/lib/teuton/readme/dsl/all.rb +32 -0
- data/lib/teuton/readme/dsl/expect.rb +29 -0
- data/lib/teuton/readme/dsl/getset.rb +33 -0
- data/lib/teuton/readme/dsl/run.rb +51 -0
- data/lib/teuton/readme/lang.rb +8 -10
- data/lib/teuton/readme/main.rb +27 -0
- data/lib/teuton/readme/readme.rb +31 -58
- data/lib/teuton/readme/result.rb +7 -0
- data/lib/teuton/utils/configfile_reader.rb +25 -10
- data/lib/teuton/utils/logger.rb +32 -0
- data/lib/teuton/utils/verbose.rb +1 -1
- data/lib/teuton/version.rb +1 -1
- data/lib/teuton.rb +6 -5
- metadata +45 -39
- data/docs/CHANGELOG.md +0 -10
- data/docs/changelog/v2.0.md +0 -18
- data/docs/changelog/v2.1.md +0 -54
- data/docs/changelog/v2.2.md +0 -42
- data/docs/changelog/v2.3.md +0 -10
- data/docs/changelog/v2.4.md +0 -41
- data/docs/changelog/v2.5.md +0 -6
- data/docs/changelog/v2.6.md +0 -4
- data/docs/changelog/v2.7.md +0 -23
- data/docs/changelog/v2.8.md +0 -11
- data/docs/changelog/version2.1.md +0 -4
- data/docs/learn/videos.md +0 -13
- data/lib/teuton/case/execute/copy_ssh.rb +0 -70
- data/lib/teuton/check/dsl.rb +0 -112
- data/lib/teuton/check/laboratory.rb +0 -59
- data/lib/teuton/readme/dsl.rb +0 -126
- /data/lib/teuton/case/dsl/{goto.rb → run.rb} +0 -0
- /data/lib/teuton/{utils → deprecated}/application.rb +0 -0
- /data/lib/teuton/{case/deprecated → deprecated}/runner.rb +0 -0
- /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
|
-
|
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 -
|
14
|
+
* [Teuton Software 2.1 - Tutorial - Abr 2020](https://youtu.be/cyBN-rOYQeY)
|
13
15
|
|
14
|
-
Teuton
|
15
|
-
* ES -
|
16
|
-
*
|
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)
|
data/lib/teuton/case/case.rb
CHANGED
@@ -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 "
|
12
|
+
require_relative "result/result"
|
12
13
|
|
13
14
|
class Case
|
14
15
|
include DSL
|
data/lib/teuton/case/config.rb
CHANGED
data/lib/teuton/case/dsl/all.rb
CHANGED
@@ -1,8 +1,12 @@
|
|
1
1
|
require_relative "expect"
|
2
2
|
require_relative "getset"
|
3
|
-
require_relative "
|
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
|
-
|
4
|
-
|
5
|
-
# expect_nothing, expect_none, expect_one
|
3
|
+
require_relative "expect_exitcode"
|
4
|
+
require_relative "expect_sequence"
|
6
5
|
|
7
|
-
|
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("[
|
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
|
111
|
-
|
112
|
-
|
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,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
|
-
|
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
|
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
|