Module: DSL

Included in:
Case, Checker, Readme
Defined in:
lib/teuton/case/dsl/target.rb,
lib/teuton/case/dsl/log.rb,
lib/teuton/case/dsl/run.rb,
lib/teuton/case/dsl/host.rb,
lib/teuton/case/dsl/send.rb,
lib/teuton/case/dsl/macro.rb,
lib/teuton/case/dsl/expect.rb,
lib/teuton/case/dsl/getset.rb,
lib/teuton/case/dsl/unique.rb,
lib/teuton/case/dsl/upload.rb,
lib/teuton/case/dsl/weight.rb,
lib/teuton/case/dsl/run_script.rb,
lib/teuton/case/dsl/expect_exitcode.rb

Overview

DSL#target

Instance Method Summary collapse

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, args = {}) ⇒ Object

If a method call is missing, then:

  • delegate to concept parent.

  • Invoke macro (assert)



35
36
37
38
39
40
41
42
43
# File 'lib/teuton/case/dsl/macro.rb', line 35

def method_missing(method, args = {})
  a = method.to_s
  if a.start_with?("_")
    return instance_eval("get(:#{a[1, a.size]})", __FILE__, __LINE__)
  elsif a[0, 6] == "macro_"
    return macro a[6, a.size], args
  end
  macro a, args
end

Instance Method Details

#expect(input, args = {}) ⇒ Object

expect <condition>,

   value: RealValue,
expected: ExpectedValue,
  weight: float


12
13
14
15
16
17
18
19
20
# File 'lib/teuton/case/dsl/expect.rb', line 12

def expect(input, args = {})
  if input.instance_of?(TrueClass) || input.instance_of?(FalseClass)
    expect2(input, args)
  elsif input.instance_of?(String) || input.instance_of?(Regexp) || input.instance_of?(Array)
    expect_any input
  else
    puts Rainbow("[ERROR] Case expect TypeError: expect #{input} (#{input.class})").red
  end
end

#expect2(cond, args = {}) ⇒ Object



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/teuton/case/dsl/expect.rb', line 22

def expect2(cond, args = {})
  @action_counter += 1
  @action[:id] = @action_counter
  if @result.exitcode < 0
    # When exitcode is less than zero, it is because there has been 
    # an error in the remote connection (SSH or Telnet)
    @action[:check] = false
    @action[:result] = @action[:output]
  else
    @action[:check] = cond
    @action[:result] = (args[:value] || @result.value)
  end

  @action[:alterations] = @result.alterations
  @action[:expected] = (args[:expected] || @result.expected)
  @report.lines << @action.clone
  weight(1.0)

  c = Settings.letter[:bad]
  c = Settings.letter[:good] if cond
  verbose Rainbow(c).green
end

#expect_any(input, args = {}) ⇒ Object



45
46
47
48
49
50
51
52
# File 'lib/teuton/case/dsl/expect.rb', line 45

def expect_any(input, args = {})
  if input.instance_of? Array
    input.each { |i| result.find(i) }
  else
    result.find(input)
  end
  expect2 result.count.gt(0), args
end

#expect_exit(value) ⇒ Object



4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# File 'lib/teuton/case/dsl/expect_exitcode.rb', line 4

def expect_exit(value)
  @result.alterations = "Read exit code"
  real_value = result.exitcode
  cond = if value.is_a? Range
    expect_value = "With range #{value}"
    value.to_a.include? real_value
  elsif value.is_a? Array
    expect_value = "Inside list #{value}"
    value.include? real_value
  else
    expect_value = value
    (real_value == value.to_i)
  end
  expect2 cond, value: real_value, expected: expect_value
end

#expect_failObject



20
21
22
23
24
25
26
# File 'lib/teuton/case/dsl/expect_exitcode.rb', line 20

def expect_fail
  @result.alterations = "Read exit code"
  real_value = result.exitcode
  expect_value = "Greater than 0"
  cond = (real_value > 0)
  expect2 cond, value: real_value, expected: expect_value
end

#expect_first(input, args = {}) ⇒ Object



54
55
56
57
58
59
# File 'lib/teuton/case/dsl/expect.rb', line 54

def expect_first(input, args = {})
  @result.first
  output = input
  output = args[:expected] if args[:expected]
  expect2 input, expected: output
end

#expect_last(input, args = {}) ⇒ Object



61
62
63
64
65
66
# File 'lib/teuton/case/dsl/expect.rb', line 61

def expect_last(input, args = {})
  @result.last
  output = input
  output = args[:expected] if args[:expected]
  expect2 input, expected: output
end

#expect_none(input = nil, args = {}) ⇒ Object



72
73
74
75
76
77
78
79
80
81
# File 'lib/teuton/case/dsl/expect.rb', line 72

def expect_none(input = nil, args = {})
  if input.nil?
    # nothing to do
  elsif input.instance_of? Array
    input.each { |i| result.find(i) }
  else
    result.find(input)
  end
  expect2 result.count.eq(0), args
end

#expect_nothing(args = {}) ⇒ Object



68
69
70
# File 'lib/teuton/case/dsl/expect.rb', line 68

def expect_nothing(args = {})
  expect2 result.count.eq(0), args
end

#expect_okObject



28
29
30
# File 'lib/teuton/case/dsl/expect_exitcode.rb', line 28

def expect_ok
  expect_exit 0
end

#expect_one(input, args = {}) ⇒ Object



83
84
85
86
87
88
89
90
# File 'lib/teuton/case/dsl/expect.rb', line 83

def expect_one(input, args = {})
  if input.instance_of? Array
    input.each { |i| result.find(i) }
  else
    result.find(input)
  end
  expect2 result.count.eq(1), args
end

#expect_sequence(&block) ⇒ Object



92
93
94
95
96
# File 'lib/teuton/case/dsl/expect.rb', line 92

def expect_sequence(&block)
  seq = ExpectSequence.new(result.content.dup)
  cond = seq.is_valid?(&block)
  expect2 cond, value: seq.real, expected: seq.expected
end

#get(option) ⇒ Object

Read param option from [running, config or global] Hash data



5
6
7
# File 'lib/teuton/case/dsl/getset.rb', line 5

def get(option)
  @config.get(option)
end

#get_host(id) ⇒ Object



2
3
4
# File 'lib/teuton/case/dsl/host.rb', line 2

def get_host(id)
  Case::Host.new(config).get(id)
end

#gett(option) ⇒ Object



9
10
11
12
# File 'lib/teuton/case/dsl/getset.rb', line 9

def gett(option)
  value = get(option)
  "#{value} (#{option})"
end

#goto(host = :localhost, args = {}) ⇒ Object Also known as: on

Run command from the host identify as “host” goto :host1, :execute => “command”



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/teuton/case/dsl/run.rb', line 20

def goto(host = :localhost, args = {})
  @result.reset
  args[:on] = host unless args[:on]
  @action[:command] = args[:execute].to_s if args[:execute]
  @action[:command] = args[:exec].to_s if args[:exec]
  tempfile(args[:tempfile]) if args[:tempfile]
  @action[:encoding] = args[:encoding] || "UTF-8"

  ExecuteManager.new(self).call(host)
  @action[:output] = if @result.content.size < 2
    @result.value.clone
  else
    "(#{@result.content.size} lines)"
  end
end

#log(text = "", type = :info) ⇒ Object Also known as: msg

Record log message



8
9
10
11
12
13
14
15
16
17
# File 'lib/teuton/case/dsl/log.rb', line 8

def log(text = "", type = :info)
  s = " INFO"
  s = Rainbow("WARN!").color(:yellow) if type == :warn
  s = Rainbow("ERROR").bg(:red) if type == :error
  t = Time.now
  f = format("%<hour>02d:%<min>02d:%<sec>02d", {hour: t.hour, min: t.min, sec: t.sec})
  msg = "[#{f}] #{s}: #{text}"
  msg = "[#{f}] #{text}" if s == ""
  @report.lines << msg
end

#macro(name, input = {}) ⇒ Object

Invoke macro



11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/teuton/case/dsl/macro.rb', line 11

def macro(name, input = {})
  macros = Project.value[:macros]
  unless macros[name]
    msg = "DSL '#{name}' not found!"
    log(msg, :error)
    Logger.error("ERROR #{msg}")
    return
  end
  input.each_pair { |k, v| set(k, v) }
  errors = []
  macros[name][:args].each do |i|
    errors << i if get(i) == "NODATA"
  end
  if errors.count > 0
    log("Macro #{name} => required params #{errors.join(",")}", :error)
  else
    instance_eval(&macros[name][:block])
  end
  input.each_pair { |k, v| unset(k) }
end

#readme(_text) ⇒ Object



5
6
7
# File 'lib/teuton/case/dsl/target.rb', line 5

def readme(_text)
  # Usefull only for "teuton reamde" command action.
end

#remote_tempdirObject



63
64
65
# File 'lib/teuton/case/dsl/send.rb', line 63

def remote_tempdir
  File.join("/", "tmp") # TODO: Remove this?
end

#remote_tempfileObject



59
60
61
# File 'lib/teuton/case/dsl/send.rb', line 59

def remote_tempfile
  @action[:remote_tempfile]
end

#respond_to_missing?(method) ⇒ Boolean



45
46
47
# File 'lib/teuton/case/dsl/macro.rb', line 45

def respond_to_missing?(method, *)
  true
end

#run(command, args = {}) ⇒ Object

DSL run and goto run: It’s the same as goto :localhost



11
12
13
14
15
16
# File 'lib/teuton/case/dsl/run.rb', line 11

def run(command, args = {})
  args[:exec] = command.to_s
  host = :localhost
  host = args[:on] if args[:on]
  goto(host, args)
end

#run_script(script, args = {}) ⇒ Object



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/teuton/case/dsl/run_script.rb', line 5

def run_script(script, args = {})
  items = script.split(" ")
  if items.size == 1
    shell = args[:shell] || (get(:shell) != "NODATA" ? get(:shell) : nil)
    script = "#{shell} #{script}" if shell
    script = "#{script} #{args[:args]} " if args[:args]
  end

  items = script.split(" ")
  if items.size < 1
    msg = Rainbow("==> [ERROR] run_script: Incorrect command '#{command}'").red
    verboseln(msg)
    return
  end

  host = get_host(args[:on])
  if host.protocol == "local"
    items[1] = File.join(Project.value[:project_path], items[1])
    command = items.join(" ")
    run(command, args)
  elsif host.protocol == "ssh"
    upload items[1], to: host.id
    items[1] = File.basename(items[1])
    command = items.join(" ")
    run(command, args)
  else
    msg = Rainbow("==> [ERROR] run_script: Incorrect protocol(#{host.protocol})").red
    verboseln(msg)
  end
end

#send(args = {}) ⇒ Object

  • send, tempfile, tempdir, remote_tempdir, remote_tempfile



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/teuton/case/dsl/send.rb', line 5

def send(args = {})
  return if skip?

  return unless args[:copy_to]

  host = args[:copy_to].to_s
  return unless @conn_status[host].nil?

  ip = get((host + "_ip").to_sym)
  username = get((host + "_username").to_sym).to_s
  password = get((host + "_password").to_sym).to_s
  port = get((host + "_port").to_sym).to_i
  port = 22 if port.zero?

  filename = "#{@report.filename}.#{@report.format}"
  filename = "#{@report.filename}.txt" if @report.format == :colored_text
  localfilepath = File.join(@report.output_dir, filename)
  filename = args[:prefix].to_s + filename if args[:prefix]

  remotefilepath = if args[:dir]
    File.join(args[:dir], filename)
  else
    File.join(".", filename)
  end

  # Upload a file or directory to the remote host
  begin
    Net::SFTP.start(ip, username, password: password, port: port) do |sftp|
      sftp.upload!(localfilepath, remotefilepath)
    end
    msg = Rainbow("==> Case #{get(:tt_members)}: report (#{remotefilepath}) copy to (#{ip})").green
    verboseln(msg)
  rescue
    msg = Rainbow("==> [FAIL] #{get(:tt_members)}: 'scp #{localfilepath}' to #{remotefilepath}").red
    verboseln(msg)
  end
end

#set(key, value) ⇒ Object



14
15
16
# File 'lib/teuton/case/dsl/getset.rb', line 14

def set(key, value)
  @config.set(key, value)
end

#target(desc, args = {}) ⇒ Object Also known as: goal



9
10
11
12
13
14
# File 'lib/teuton/case/dsl/target.rb', line 9

def target(desc, args = {})
  @action[:description] = desc.to_s
  @action[:asset] = args[:asset].to_s if args[:asset]
  w = args[:weight] || 1.0
  weight(w)
end

#tempdirObject



55
56
57
# File 'lib/teuton/case/dsl/send.rb', line 55

def tempdir
  @tmpdir
end

#tempfile(input = nil) ⇒ Object



43
44
45
46
47
48
49
50
51
52
53
# File 'lib/teuton/case/dsl/send.rb', line 43

def tempfile(input = nil)
  return @action[:tempfile] if input.nil?

  name = input
  name = "teuton.tmp" if input == :default

  @action[:tempfile] = File.join(@tmpdir, name)
  @action[:remote_tempfile] = File.join(remote_tempdir, name)

  @action[:tempfile]
end

#unique(key, value) ⇒ Object



4
5
6
7
8
# File 'lib/teuton/case/dsl/unique.rb', line 4

def unique(key, value)
  return if value.nil?

  @uniques << "#{key}=#{value}".to_sym
end

#unset(key) ⇒ Object



18
19
20
# File 'lib/teuton/case/dsl/getset.rb', line 18

def unset(key)
  @config.unset(key)
end

#upload(localfilter, args = {}) ⇒ Object



5
6
7
8
9
10
11
12
13
14
15
# File 'lib/teuton/case/dsl/upload.rb', line 5

def upload(localfilter, args = {})
  abslocalfilter = if File.absolute_path? localfilter
    localfilter
  else
    File.join(Project.value[:project_path], localfilter)
  end

  Dir.glob(abslocalfilter).each do |abslocalpath|
    upload_one(abslocalpath, args)
  end
end

#upload_one(localpath, args = {}) ⇒ Object



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/teuton/case/dsl/upload.rb', line 17

def upload_one(localpath, args = {})
  if args[:to].nil?
    Logger.err("ERROR upload requires to: XXX")
    exit 1
  end

  host = get_host(args[:to])
  if host.protocol == "ssh"
    begin
      localfile = File.basename(localpath)
      remotepath = args[:remotedir] ? File.join(args[:remotedir], localfile) : localfile
      Net::SFTP.start(
        host.ip, host.username, password: host.password, port: host.port
      ) { |sftp| sftp.upload!(localpath, remotepath) }
      verbose(Rainbow("u").green)
    rescue => e
      log("Upload #{localfile} to #{host.ip}:#{remotepath}", :warn)
      log(e.to_s, :warn)
      verbose(Rainbow("!").green)
    end
  elsif host.protocol != "local"
    msg = Rainbow("==> [ERROR] upload: Incorrect protocol(#{host.protocol})").red
    verboseln(msg)
  end
end

#weight(value = nil) ⇒ Object



2
3
4
5
6
7
8
9
10
11
# File 'lib/teuton/case/dsl/weight.rb', line 2

def weight(value = nil)
  # Set weight value for the action
  if value.nil?
    @action[:weight]
  elsif value == :default
    @action[:weight] = 1.0
  else
    @action[:weight] = value.to_f
  end
end