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,42 @@
1
+ require_relative "../../utils/project"
2
+ require_relative "../../utils/verbose"
3
+
4
+ module DSL
5
+ def upload(localfilter, args = {})
6
+ abslocalfilter = if File.absolute_path? localfilter
7
+ localfilter
8
+ else
9
+ File.join(Project.value[:project_path], localfilter)
10
+ end
11
+
12
+ Dir.glob(abslocalfilter).each do |abslocalpath|
13
+ upload_one(abslocalpath, args)
14
+ end
15
+ end
16
+
17
+ def upload_one(localpath, args = {})
18
+ if args[:to].nil?
19
+ Logger.err("ERROR upload requires to: XXX")
20
+ exit 1
21
+ end
22
+
23
+ host = get_host(args[:to])
24
+ if host.protocol == "ssh"
25
+ begin
26
+ localfile = File.basename(localpath)
27
+ remotepath = args[:remotedir] ? File.join(args[:remotedir], localfile) : localfile
28
+ Net::SFTP.start(
29
+ host.ip, host.username, password: host.password, port: host.port
30
+ ) { |sftp| sftp.upload!(localpath, remotepath) }
31
+ verbose(Rainbow("u").green)
32
+ rescue => e
33
+ log("Upload #{localfile} to #{host.ip}:#{remotepath}", :warn)
34
+ log(e.to_s, :warn)
35
+ verbose(Rainbow("!").green)
36
+ end
37
+ elsif host.protocol != "local"
38
+ msg = Rainbow("==> [ERROR] upload: Incorrect protocol(#{host.protocol})").red
39
+ verboseln(msg)
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,12 @@
1
+ module DSL
2
+ def weight(value = nil)
3
+ # Set weight value for the action
4
+ if value.nil?
5
+ @action[:weight]
6
+ elsif value == :default
7
+ @action[:weight] = 1.0
8
+ else
9
+ @action[:weight] = value.to_f
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,68 @@
1
+ class Case
2
+ class Host
3
+ attr_reader :id
4
+ attr_reader :ip
5
+ attr_reader :username
6
+ attr_reader :password
7
+ attr_reader :port
8
+ attr_reader :protocol
9
+ attr_reader :route
10
+
11
+ def initialize(config)
12
+ @config = config
13
+ end
14
+
15
+ def get(id = nil)
16
+ if id.nil?
17
+ init_default
18
+ else
19
+ init(id)
20
+ end
21
+ self
22
+ end
23
+
24
+ def to_s
25
+ data = {
26
+ id: id,
27
+ ip: ip, username: username, password: password,
28
+ port: port, protocol: protocol, route: route
29
+ }
30
+ data.to_s
31
+ end
32
+
33
+ private
34
+
35
+ def init(id)
36
+ @id = id.to_sym
37
+ @ip = @config.get("#{@id}_ip".to_sym).to_s
38
+ @username = @config.get("#{@id}_username".to_sym).to_s
39
+ @password = @config.get("#{@id}_password".to_sym).to_s
40
+
41
+ @protocol = @config.get("#{@id}_protocol".to_sym).to_s.downcase
42
+ if @protocol == "nodata"
43
+ @protocol = if @ip == "localhost" || @ip.start_with?("127.0.0.")
44
+ "local"
45
+ else
46
+ "ssh"
47
+ end
48
+ end
49
+
50
+ @port = @config.get("#{@id}_port".to_sym).to_i
51
+ if @port.zero?
52
+ default = {"local" => 0, "ssh" => 22, "telnet" => 23}
53
+ @port = default[@protocol]
54
+ end
55
+ @route = @config.get("#{@id}_route".to_sym)
56
+ end
57
+
58
+ def init_default
59
+ @id = :default
60
+ @ip = "localhost"
61
+ @username = "NODATA"
62
+ @password = "NODATA"
63
+ @protocol = "local"
64
+ @port = 0
65
+ @route = "NODATA"
66
+ end
67
+ end
68
+ end
@@ -1,9 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Case
4
- # Case class: play
5
- # TODO: Encapsulate code into PlayManager class
6
- # * play_in_parallel, play_in_sequence, fill_report, close_opened_sessions
7
4
  # READ: sessions, config, groups, action, report
8
5
  # TODO: groups from Project or from Case???
9
6
  def play
@@ -18,19 +15,18 @@ class Case
18
15
  end
19
16
  alias_method :start, :play
20
17
 
18
+ private
19
+
21
20
  def close_opened_sessions
22
21
  @sessions.each_value do |s|
23
22
  s.close if s.instance_of? Net::SSH::Connection::Session
24
23
  end
25
24
  end
26
25
 
27
- private
28
-
29
26
  def play_groups_in_sequence
30
27
  verboseln "\n=> Starting case [#{@config.get(:tt_members)}]" if get(:tt_sequence) == true
31
28
  @groups.each do |t|
32
29
  @action[:groupname] = t[:name]
33
- # TODO: @parent(case).instance_eval(&t[:block])
34
30
  instance_eval(&t[:block])
35
31
  end
36
32
  end
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # This is an extension of Result class
4
3
  class Result
5
4
  def count
6
5
  @alterations << "count"
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Extension of Result class
4
3
  class Result
5
4
  def eq(input)
6
5
  # Return true when content is equal than input
@@ -1,8 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Result class extension
4
3
  class Result
5
- # TODO: Error line 102 undefined include? method for 0 Fixnum...
6
4
  def find(filter)
7
5
  @alterations << "find(#{filter})"
8
6
  case filter.class.to_s
@@ -4,15 +4,6 @@ require_relative "ext_array"
4
4
  require_relative "ext_compare"
5
5
  require_relative "ext_filter"
6
6
 
7
- # This object contains data returned by remote/local execution
8
- # * initialize
9
- # * alterations
10
- # * content
11
- # * debug
12
- # * ok?
13
- # * reset
14
- # * restore
15
- # * value
16
7
  class Result
17
8
  attr_reader :content
18
9
  attr_accessor :exitcode
@@ -22,6 +13,16 @@ class Result
22
13
  reset
23
14
  end
24
15
 
16
+ def reset
17
+ @content_backup = []
18
+ @content = []
19
+ @exitcode = -1
20
+
21
+ # @value = nil
22
+ @expected = nil
23
+ @alterations = []
24
+ end
25
+
25
26
  def alterations
26
27
  if @alterations.is_a? String
27
28
  @alterations
@@ -49,15 +50,6 @@ class Result
49
50
  @expected.to_s
50
51
  end
51
52
 
52
- def reset
53
- @content_backup = []
54
- @content = []
55
- @exitcode = -1
56
- @value = nil
57
- @expected = nil
58
- @alterations = []
59
- end
60
-
61
53
  def ok?
62
54
  @exitcode.zero?
63
55
  end
@@ -65,10 +57,10 @@ class Result
65
57
  def restore
66
58
  temp = @content_backup.clone
67
59
  reset
68
- @content_backup = temp
69
- @content = temp.clone
60
+ # @content_backup = temp
61
+ # @content = temp.clone
62
+ self.content = (temp)
70
63
  end
71
- alias_method :restore!, :restore
72
64
 
73
65
  def value
74
66
  @content[0]
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../case/dsl/macro"
4
+ require_relative "../case/result/result"
5
+ require_relative "../utils/project"
6
+ require_relative "../utils/logger"
7
+ require_relative "dsl/all"
8
+ require_relative "show"
9
+
10
+ class Checker
11
+ include DSL # Include case/DSL/macro functions only
12
+ include CheckDSL
13
+
14
+ attr_reader :result
15
+
16
+ def initialize(script_path, config_path)
17
+ @path = {}
18
+ @path[:script] = script_path
19
+ @path[:dirname] = File.dirname(script_path)
20
+ @path[:filename] = File.basename(script_path, ".rb")
21
+ @path[:config] = config_path
22
+ reset
23
+ end
24
+
25
+ def reset
26
+ @result = Result.new
27
+ @targetid = 0
28
+ @stats = {
29
+ groups: 0,
30
+ targets: 0,
31
+ logs: 0,
32
+ readmes: 0,
33
+ uniques: 0,
34
+ hosts: {},
35
+ gets: {},
36
+ sets: [],
37
+ uploads: []
38
+ }
39
+ @target_begin = nil
40
+ end
41
+
42
+ def show
43
+ Logger.verbose = true
44
+ process_content
45
+ cs = ShowCheck.new(stats: @stats, path: @path)
46
+ cs.show_stats
47
+ cs.revise_config_content
48
+ end
49
+
50
+ def show_onlyconfig
51
+ Logger.verbose = false
52
+ process_content
53
+ Logger.verbose = true
54
+ cs = ShowCheck.new(stats: @stats, path: @path)
55
+ cs.suggest_config_content
56
+ end
57
+
58
+ private
59
+
60
+ def process_content
61
+ groups = Project.value[:groups]
62
+ option = Project.value[:options]
63
+
64
+ Logger.info ""
65
+ if Project.value[:uses].size.positive?
66
+ Logger.info Terminal::Table.new { |st| st.add_row ["USE: external libraries"] }
67
+ Project.value[:uses].each_with_index { Logger.info " #{_2 + 1}. #{_1}" }
68
+ end
69
+ groups.each do |t|
70
+ @stats[:groups] += 1
71
+ unless option[:panel]
72
+ msg = "GROUP: #{t[:name]}"
73
+ my_screen_table = Terminal::Table.new { |st| st.add_row [msg] }
74
+ Logger.info my_screen_table
75
+ end
76
+ instance_eval(&t[:block])
77
+ end
78
+ if @target_begin
79
+ Logger.warn "WARN Last 'target' requires 'expect'\n"
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,37 @@
1
+ require_relative "builtin"
2
+ require_relative "expect"
3
+ require_relative "getset"
4
+ require_relative "run"
5
+
6
+ module CheckDSL
7
+ def log(text = "", type = :info)
8
+ @stats[:logs] += 1
9
+ prefix = (type == :info) ? "" : "#{type.to_s.upcase}: "
10
+ Logger.info " log #{prefix}" + text.to_s
11
+ end
12
+
13
+ def readme(text)
14
+ @stats[:readmes] += 1
15
+ Logger.info " readme #{text}"
16
+ end
17
+
18
+ def target(desc, args = {})
19
+ if @target_begin
20
+ Logger.warn "WARN Previous 'target' requires 'expect'"
21
+ end
22
+ @target_begin = true
23
+ @stats[:targets] += 1
24
+ @targetid += 1
25
+ weight = args[:weight] ? args[:weight].to_f : 1.0
26
+ Logger.info format("(%03<targetid>d) target %<desc>s", targetid: @targetid, desc: desc)
27
+ Logger.info " weight #{weight}"
28
+ end
29
+ alias_method :goal, :target
30
+
31
+ def unique(key, _value)
32
+ @stats[:uniques] += 1
33
+
34
+ Logger.info " unique value for <#{key}>"
35
+ Logger.info ""
36
+ end
37
+ end
@@ -16,9 +16,7 @@ class Builtin
16
16
  end
17
17
  end
18
18
 
19
- # Laboratory
20
- # * service
21
- class Laboratory
19
+ module CheckDSL
22
20
  def service(param)
23
21
  log "BUILTIN service(#{param})"
24
22
  @builtin ||= Builtin.new(self)
@@ -0,0 +1,90 @@
1
+ require_relative "expect_sequence"
2
+
3
+ module CheckDSL
4
+ def expect(cond)
5
+ unless @target_begin
6
+ Logger.warn "WARN 'expect' with no previous 'target'"
7
+ end
8
+ Logger.info " alter #{result.alterations}" unless result.alterations.empty?
9
+ Logger.info " expect #{cond} (#{cond.class})"
10
+ Logger.info ""
11
+ @target_begin = false
12
+ end
13
+
14
+ def expect_exit(cond)
15
+ unless @target_begin
16
+ Logger.warn "WARN 'expect' with no previous 'target'"
17
+ end
18
+ Logger.info " expect_exit #{cond} (#{cond.class})"
19
+ Logger.info ""
20
+ @target_begin = false
21
+ end
22
+
23
+ def expect_fail
24
+ unless @target_begin
25
+ Logger.warn "WARN 'expect' with no previous 'target'"
26
+ end
27
+ Logger.info " expect_fail"
28
+ Logger.info ""
29
+ @target_begin = false
30
+ end
31
+
32
+ def expect_first(cond)
33
+ unless @target_begin
34
+ Logger.warn "WARN 'expect' with no previous 'target'"
35
+ end
36
+ Logger.info " alter #{result.alterations}" unless result.alterations.empty?
37
+ Logger.info " expect_first #{cond} (#{cond.class})"
38
+ Logger.info ""
39
+ @target_begin = false
40
+ end
41
+
42
+ def expect_last(cond)
43
+ unless @target_begin
44
+ Logger.warn "WARN 'expect' with no previous 'target'"
45
+ end
46
+ Logger.info " alter #{result.alterations}" unless result.alterations.empty?
47
+ Logger.info " expect_last #{cond} (#{cond.class})"
48
+ Logger.info ""
49
+ @target_begin = false
50
+ end
51
+
52
+ def expect_none(cond = nil, args = {})
53
+ unless @target_begin
54
+ Logger.warn "WARN 'expect' with no previous 'target'"
55
+ end
56
+ Logger.info " alter #{result.alterations}" unless result.alterations.empty?
57
+ Logger.info " expect_none #{cond} (#{cond.class})"
58
+ Logger.info ""
59
+ @target_begin = false
60
+ end
61
+
62
+ def expect_nothing
63
+ expect_none nil, {}
64
+ end
65
+
66
+ def expect_ok
67
+ expect_exit 0
68
+ end
69
+
70
+ def expect_one(cond)
71
+ unless @target_begin
72
+ Logger.warn "WARN 'expect' with no previous 'target'"
73
+ end
74
+ Logger.info " alter #{result.alterations}" unless result.alterations.empty?
75
+ Logger.info " expect_one #{cond} (#{cond.class})"
76
+ Logger.info ""
77
+ @target_begin = false
78
+ end
79
+
80
+ def expect_sequence(&block)
81
+ unless @target_begin
82
+ Logger.warn "WARN 'expect' with no previous 'target'"
83
+ end
84
+ seq = CheckDSL::ExpectSequence.new
85
+ seq.is_valid?(&block)
86
+ Logger.info " expect_sequence #{seq.expected}"
87
+ Logger.info ""
88
+ @target_begin = false
89
+ end
90
+ end
@@ -0,0 +1,29 @@
1
+ module CheckDSL
2
+ class ExpectSequence
3
+ def initialize
4
+ @expected = []
5
+ end
6
+
7
+ def is_valid?(&block)
8
+ instance_eval(&block)
9
+ end
10
+
11
+ def expected
12
+ @expected.join(">")
13
+ end
14
+
15
+ private
16
+
17
+ def find(value)
18
+ @expected << "find(#{value})"
19
+ end
20
+
21
+ def next_to(value)
22
+ @expected << "next_to(#{value})"
23
+ end
24
+
25
+ def ignore(value)
26
+ @expected << "ignore(#{value})"
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,23 @@
1
+ module CheckDSL
2
+ def get(varname)
3
+ data = @stats[:gets]
4
+ data[varname] = data[varname] ? (data[varname] + 1) : 1
5
+ "get(#{varname})"
6
+ end
7
+
8
+ def gett(option)
9
+ get(option)
10
+ end
11
+
12
+ def set(key, value)
13
+ key = ":" + key.to_s if key.instance_of? Symbol
14
+ value = ":" + value.to_s if value.instance_of? Symbol
15
+
16
+ @stats[:sets] << "#{key}=#{value}"
17
+ Logger.info " set(#{key},#{value})"
18
+ end
19
+
20
+ def unset(key)
21
+ Logger.info " unset(#{key})"
22
+ end
23
+ end
@@ -0,0 +1,35 @@
1
+ module CheckDSL
2
+ def run(command, args = {})
3
+ args[:exec] = command
4
+ host = :localhost
5
+ host = args[:on] if args[:on]
6
+ goto(host, args)
7
+ end
8
+
9
+ def run_script(command, args = {})
10
+ host = :localhost
11
+ host = args[:on] if args[:on]
12
+ filename = command.split[1]
13
+ upload filename, to: host
14
+ run command, args
15
+ end
16
+
17
+ def goto(host = :localhost, args = {})
18
+ result.reset
19
+ @stats[:hosts][host] = @stats[:hosts][host] ? (@stats[:hosts][host] + 1) : 1
20
+ Logger.info " run '#{args[:exec]}' on #{host}"
21
+ end
22
+
23
+ def upload(filename, args = {})
24
+ host = args[:to]
25
+ args.delete(:to)
26
+ custom = if args == {}
27
+ ""
28
+ else
29
+ values = args.map { "#{_1}=#{_2}" }
30
+ "and #{values.join(",")}"
31
+ end
32
+ @stats[:uploads] << filename
33
+ Logger.info " upload '#{filename}' to #{host} #{custom}"
34
+ end
35
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../utils/project"
4
+
5
+ def use(filename)
6
+ filename += ".rb"
7
+ rbfiles = File.join(Project.value[:project_path], "**", filename)
8
+ files = Dir.glob(rbfiles)
9
+ use = []
10
+ files.sort.each { |f| use << f if f.include?(filename) }
11
+ require_relative use[0]
12
+ Project.value[:uses] << use[0]
13
+ end
14
+
15
+ def group(name, &block)
16
+ Project.value[:groups] << {name: name, block: block}
17
+ end
18
+ alias task group
19
+
20
+ def define_macro(name, *args, &block)
21
+ Project.value[:macros][name] = {args: args, block: block}
22
+ end
23
+ alias def_macro define_macro
24
+ alias defmacro define_macro
25
+
26
+ def start(&block)
27
+ # Don't do nothing. We are checking test not running it
28
+ end
29
+ alias play start