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.
- 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
|