teuton 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/teuton +4 -0
- data/lib/teuton/application.rb +53 -0
- data/lib/teuton/case_manager/case/builtin/main.rb +24 -0
- data/lib/teuton/case_manager/case/builtin/package.rb +20 -0
- data/lib/teuton/case_manager/case/builtin/service.rb +32 -0
- data/lib/teuton/case_manager/case/builtin/user.rb +20 -0
- data/lib/teuton/case_manager/case/case.rb +114 -0
- data/lib/teuton/case_manager/case/close.rb +29 -0
- data/lib/teuton/case_manager/case/config.rb +76 -0
- data/lib/teuton/case_manager/case/dsl/check.rb +24 -0
- data/lib/teuton/case_manager/case/dsl/deprecated.rb +14 -0
- data/lib/teuton/case_manager/case/dsl/expect.rb +78 -0
- data/lib/teuton/case_manager/case/dsl/getset.rb +22 -0
- data/lib/teuton/case_manager/case/dsl/goto.rb +35 -0
- data/lib/teuton/case_manager/case/dsl/log.rb +14 -0
- data/lib/teuton/case_manager/case/dsl/main.rb +11 -0
- data/lib/teuton/case_manager/case/dsl/missing.rb +12 -0
- data/lib/teuton/case_manager/case/dsl/send.rb +69 -0
- data/lib/teuton/case_manager/case/dsl/target.rb +16 -0
- data/lib/teuton/case_manager/case/dsl/unique.rb +11 -0
- data/lib/teuton/case_manager/case/main.rb +7 -0
- data/lib/teuton/case_manager/case/play.rb +59 -0
- data/lib/teuton/case_manager/case/result/ext_array.rb +43 -0
- data/lib/teuton/case_manager/case/result/ext_compare.rb +147 -0
- data/lib/teuton/case_manager/case/result/ext_filter.rb +68 -0
- data/lib/teuton/case_manager/case/result/result.rb +73 -0
- data/lib/teuton/case_manager/case/runner.rb +134 -0
- data/lib/teuton/case_manager/case_manager.rb +76 -0
- data/lib/teuton/case_manager/check_cases.rb +73 -0
- data/lib/teuton/case_manager/dsl.rb +31 -0
- data/lib/teuton/case_manager/export_manager.rb +20 -0
- data/lib/teuton/case_manager/hall_of_fame.rb +28 -0
- data/lib/teuton/case_manager/main.rb +6 -0
- data/lib/teuton/case_manager/report.rb +52 -0
- data/lib/teuton/case_manager/show.rb +19 -0
- data/lib/teuton/case_manager/utils.rb +57 -0
- data/lib/teuton/command/create.rb +20 -0
- data/lib/teuton/command/download.rb +26 -0
- data/lib/teuton/command/main.rb +9 -0
- data/lib/teuton/command/play.rb +34 -0
- data/lib/teuton/command/readme.rb +23 -0
- data/lib/teuton/command/test.rb +35 -0
- data/lib/teuton/command/update.rb +27 -0
- data/lib/teuton/command/version.rb +13 -0
- data/lib/teuton/files/start.rb +13 -0
- data/lib/teuton/project/configfile_reader.rb +49 -0
- data/lib/teuton/project/laboratory/builtin.rb +23 -0
- data/lib/teuton/project/laboratory/dsl.rb +117 -0
- data/lib/teuton/project/laboratory/laboratory.rb +55 -0
- data/lib/teuton/project/laboratory/show.rb +161 -0
- data/lib/teuton/project/name_file_finder.rb +129 -0
- data/lib/teuton/project/project.rb +62 -0
- data/lib/teuton/project/project_creator.rb +79 -0
- data/lib/teuton/project/readme/dsl.rb +109 -0
- data/lib/teuton/project/readme/lang.rb +30 -0
- data/lib/teuton/project/readme/readme.rb +156 -0
- data/lib/teuton/rake_function/check.rb +39 -0
- data/lib/teuton/rake_function/install.rb +36 -0
- data/lib/teuton/report/close.rb +34 -0
- data/lib/teuton/report/formatter/array_formatter.rb +84 -0
- data/lib/teuton/report/formatter/base_formatter.rb +33 -0
- data/lib/teuton/report/formatter/csv_formatter.rb +31 -0
- data/lib/teuton/report/formatter/formatter_factory.rb +73 -0
- data/lib/teuton/report/formatter/html_formatter.rb +81 -0
- data/lib/teuton/report/formatter/json_formatter.rb +17 -0
- data/lib/teuton/report/formatter/list_formatter.rb +71 -0
- data/lib/teuton/report/formatter/moodle_csv_formatter.rb +28 -0
- data/lib/teuton/report/formatter/resume_array_formatter.rb +49 -0
- data/lib/teuton/report/formatter/resume_json_formatter.rb +16 -0
- data/lib/teuton/report/formatter/resume_list_formatter.rb +62 -0
- data/lib/teuton/report/formatter/resume_txt_formatter.rb +102 -0
- data/lib/teuton/report/formatter/resume_yaml_formatter.rb +16 -0
- data/lib/teuton/report/formatter/txt_formatter.rb +102 -0
- data/lib/teuton/report/formatter/xml_formatter.rb +42 -0
- data/lib/teuton/report/formatter/yaml_formatter.rb +18 -0
- data/lib/teuton/report/report.rb +55 -0
- data/lib/teuton/report/show.rb +111 -0
- data/lib/teuton/utils/verbose.rb +15 -0
- data/lib/teuton.rb +17 -0
- metadata +263 -0
@@ -0,0 +1,31 @@
|
|
1
|
+
require_relative '../application'
|
2
|
+
require_relative 'case_manager'
|
3
|
+
|
4
|
+
def use(filename)
|
5
|
+
filename += '.rb'
|
6
|
+
app = Application.instance
|
7
|
+
rbfiles = File.join(app.project_path, "**", filename)
|
8
|
+
files = Dir.glob(rbfiles)
|
9
|
+
findfiles = []
|
10
|
+
files.sort.each { |f| findfiles << f if f.include?(filename) }
|
11
|
+
require_relative findfiles.first
|
12
|
+
app.uses << File.basename(findfiles.first)
|
13
|
+
end
|
14
|
+
|
15
|
+
def define_check(name, *args, &block)
|
16
|
+
Application.instance.checks[name] = { args: args, block: block }
|
17
|
+
end
|
18
|
+
alias definecheck define_check
|
19
|
+
alias def_check define_check
|
20
|
+
alias defcheck define_check
|
21
|
+
alias dcheck define_check
|
22
|
+
|
23
|
+
def group(name, &block)
|
24
|
+
Application.instance.groups << { name: name, block: block }
|
25
|
+
end
|
26
|
+
alias task group
|
27
|
+
|
28
|
+
def play(&block)
|
29
|
+
CaseManager.instance.play(&block)
|
30
|
+
end
|
31
|
+
alias start play
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../application'
|
4
|
+
|
5
|
+
# ExportManager#run
|
6
|
+
module ExportManager
|
7
|
+
def self.run(main_report, cases, args)
|
8
|
+
# default :mode=>:all, :format=>:txt
|
9
|
+
format = args[:format] || Application.instance.default[:format]
|
10
|
+
mode = args[:mode] || :all
|
11
|
+
# Export case reports
|
12
|
+
if %i[details all].include? mode
|
13
|
+
threads = []
|
14
|
+
cases.each { |c| threads << Thread.new { c.export format } }
|
15
|
+
threads.each(&:join)
|
16
|
+
end
|
17
|
+
# Export resume report
|
18
|
+
main_report.export_resume format if %i[resume all].include? mode
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
|
2
|
+
require_relative '../application'
|
3
|
+
|
4
|
+
class CaseManager
|
5
|
+
|
6
|
+
private
|
7
|
+
|
8
|
+
def build_hall_of_fame
|
9
|
+
celebrities = {}
|
10
|
+
|
11
|
+
@cases.each do |c|
|
12
|
+
grade = c.grade # report.tail[:grade]
|
13
|
+
if celebrities[grade]
|
14
|
+
label = celebrities[grade] + '*'
|
15
|
+
else
|
16
|
+
label = '*'
|
17
|
+
end
|
18
|
+
celebrities[grade] = label unless c.skip
|
19
|
+
end
|
20
|
+
|
21
|
+
a = celebrities.sort_by { |key, _value| key }
|
22
|
+
list = a.reverse
|
23
|
+
|
24
|
+
app = Application.instance
|
25
|
+
app.options[:case_number] = @cases.size
|
26
|
+
app.hall_of_fame = list
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
|
2
|
+
class CaseManager
|
3
|
+
|
4
|
+
private
|
5
|
+
|
6
|
+
def open_main_report(p_config_filename)
|
7
|
+
app = Application.instance
|
8
|
+
|
9
|
+
@report.head[:tt_title] = "Executing [#{app.name}] (version #{Application::VERSION})"
|
10
|
+
@report.head[:tt_scriptname] = app.script_path
|
11
|
+
@report.head[:tt_configfile] = p_config_filename
|
12
|
+
@report.head[:tt_debug] = true if @debug
|
13
|
+
# @report.head[:tt_uses] = app.uses.join(', ')
|
14
|
+
@report.head.merge!(app.global)
|
15
|
+
|
16
|
+
verboseln ' '
|
17
|
+
verboseln '=' * @report.head[:tt_title].length
|
18
|
+
verboseln @report.head[:tt_title]
|
19
|
+
end
|
20
|
+
|
21
|
+
def close_main_report(start_time)
|
22
|
+
finish_time = Time.now
|
23
|
+
@report.tail[:start_time] = start_time
|
24
|
+
@report.tail[:finish_time] = finish_time
|
25
|
+
@report.tail[:duration] = finish_time - start_time
|
26
|
+
|
27
|
+
verbose "\n[INFO] Duration = #{format('%3.3f',(finish_time - start_time))}"
|
28
|
+
verboseln " (#{finish_time})"
|
29
|
+
verboseln '=' * @report.head[:tt_title].length
|
30
|
+
verboseln ' '
|
31
|
+
|
32
|
+
app = Application.instance
|
33
|
+
@cases.each do |c|
|
34
|
+
line = {}
|
35
|
+
if c.skip?
|
36
|
+
line = { skip: true, id: '-', grade: 0.0, letter: '',
|
37
|
+
members: '-', conn_status: {},
|
38
|
+
moodle_id: '', moodle_feedback: '' }
|
39
|
+
else
|
40
|
+
line[:skip] = false
|
41
|
+
line[:id] = format('case_%02d', c.id.to_i)
|
42
|
+
line[:letter] = app.letter[:error] if c.grade < 50.0
|
43
|
+
line[:grade] = c.grade.to_f #format(' %3d', c.grade.to_f)
|
44
|
+
line[:members] = c.members
|
45
|
+
line[:conn_status] = c.conn_status
|
46
|
+
line[:moodle_id] = c.get(:tt_moodle_id)
|
47
|
+
line[:moodle_feedback] = "\"Filename: #{c.filename}. Date: #{Time.now}\""
|
48
|
+
end
|
49
|
+
@report.lines << line
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require_relative '../application'
|
3
|
+
|
4
|
+
# CaseManager#show
|
5
|
+
class CaseManager
|
6
|
+
def show(mode = :resume)
|
7
|
+
return if Application.instance.quiet?
|
8
|
+
|
9
|
+
@report.show if %i[resume all].include? mode
|
10
|
+
|
11
|
+
return unless %i[details all].include? mode
|
12
|
+
|
13
|
+
@cases.each do |c|
|
14
|
+
puts '____'
|
15
|
+
c.show
|
16
|
+
end
|
17
|
+
puts '.'
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../application'
|
4
|
+
|
5
|
+
# Define general use methods
|
6
|
+
module Utils
|
7
|
+
# Create the directory if it dosn't exist.
|
8
|
+
def ensure_dir(dirname)
|
9
|
+
unless Dir.exist?(dirname)
|
10
|
+
FileUtils.mkdir_p(dirname)
|
11
|
+
return false
|
12
|
+
end
|
13
|
+
true
|
14
|
+
end
|
15
|
+
|
16
|
+
def encode_and_split(encoding, text)
|
17
|
+
# Convert text to UTF-8 deleting unknown chars
|
18
|
+
text = text || '' # Ensure text is not nil
|
19
|
+
flag = [:default, 'UTF-8'].include? encoding
|
20
|
+
return text.encode('UTF-8', invalid: :replace).split("\n") if flag
|
21
|
+
|
22
|
+
# Convert text from input ENCODING to UTF-8
|
23
|
+
ec = Encoding::Converter.new(encoding.to_s, 'UTF-8')
|
24
|
+
begin
|
25
|
+
text = ec.convert(text)
|
26
|
+
rescue StandardError => e
|
27
|
+
puts "[ERROR] #{e}: Declare text encoding..."
|
28
|
+
puts " goto :host, :exec => 'command', :encoding => 'ISO-8859-1'"
|
29
|
+
end
|
30
|
+
|
31
|
+
text.split("\n")
|
32
|
+
end
|
33
|
+
|
34
|
+
def my_execute(cmd, encoding = 'UTF-8')
|
35
|
+
return { exitstatus: 0, content: '' } if Application.instance.debug
|
36
|
+
|
37
|
+
begin
|
38
|
+
text = `#{cmd}`
|
39
|
+
exitstatus = $CHILD_STATUS.exitstatus
|
40
|
+
rescue StandardError => e # rescue Exception => e
|
41
|
+
verbose '!'
|
42
|
+
puts("[ERROR] #{e}: Local exec: #{cmd}")
|
43
|
+
end
|
44
|
+
content = encode_and_split(encoding, text)
|
45
|
+
{ exitstatus: exitstatus, content: content }
|
46
|
+
end
|
47
|
+
|
48
|
+
def verboseln(text)
|
49
|
+
verbose(text + "\n")
|
50
|
+
end
|
51
|
+
|
52
|
+
def verbose(text)
|
53
|
+
return if Application.instance.quiet?
|
54
|
+
|
55
|
+
print text
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../project/project_creator.rb'
|
4
|
+
|
5
|
+
# Teuton#create
|
6
|
+
class Teuton < Thor
|
7
|
+
map ['c', '-c', '--create'] => 'create'
|
8
|
+
desc 'create DIRECTORY', 'Create skeleton for a new project'
|
9
|
+
long_desc <<-LONGDESC
|
10
|
+
Create files for a new project: foo.rb, foo.yaml and .gitignore
|
11
|
+
|
12
|
+
Example:
|
13
|
+
|
14
|
+
#{$PROGRAM_NAME} create foo/demo
|
15
|
+
|
16
|
+
LONGDESC
|
17
|
+
def create(path_to_new_dir)
|
18
|
+
ProjectCreator.create(path_to_new_dir)
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rainbow'
|
4
|
+
|
5
|
+
# Class method Teuton#download
|
6
|
+
class Teuton < Thor
|
7
|
+
map ['-dc', '--dc', '--download'] => 'download'
|
8
|
+
desc 'download', 'Download Teuton challenges from git repo'
|
9
|
+
long_desc <<-LONGDESC
|
10
|
+
- Download Teuton challenges from git repo.
|
11
|
+
|
12
|
+
- Same as:
|
13
|
+
git clone https://github.com/teuton-software/teuton-challenges.git
|
14
|
+
|
15
|
+
Example:
|
16
|
+
|
17
|
+
#{$PROGRAM_NAME} download
|
18
|
+
|
19
|
+
LONGDESC
|
20
|
+
def download
|
21
|
+
repo = 'teuton-challenges'
|
22
|
+
puts "[INFO] Downloading <#{repo}> repo..."
|
23
|
+
system("git clone https://github.com/teuton-software/#{repo}.git")
|
24
|
+
puts "[INFO] Your files are into <#{Rainbow(repo).bright}> directory..."
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Teuton#play
|
4
|
+
class Teuton < Thor
|
5
|
+
map ['p', '-p', 'play', '--play'] => 'play'
|
6
|
+
option :export, type: :string
|
7
|
+
option :cname, type: :string
|
8
|
+
option :cpath, type: :string
|
9
|
+
option :case, type: :string
|
10
|
+
option :quiet, type: :boolean
|
11
|
+
desc '[play] [OPTIONS] DIRECTORY',
|
12
|
+
'Run challenge from directory'
|
13
|
+
long_desc <<-LONGDESC
|
14
|
+
This function execute challenge from specified directory.
|
15
|
+
By default, show progress on the screen.
|
16
|
+
|
17
|
+
Let's see others options:
|
18
|
+
|
19
|
+
(1) teuton foo, run challenge from foo/start.rb with foo/config.yaml config file.
|
20
|
+
|
21
|
+
(2) teuton play foo, same as (1).
|
22
|
+
|
23
|
+
(3) teuton play --export=json foo, run challenge and export using json format.
|
24
|
+
Others output formats availables are: txt, colored_text, json, yaml.
|
25
|
+
|
26
|
+
(4) teuton play --cname=demo foo, run challenge from foo/start.rb with foo/demo.yaml config file.
|
27
|
+
|
28
|
+
(5) teuton foo/demo.rb, Run challenge from foo/demo.rb with foo/demo.yaml config file.
|
29
|
+
|
30
|
+
LONGDESC
|
31
|
+
def play(path_to_rb_file)
|
32
|
+
Project.play(path_to_rb_file, options)
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Teuton#readme
|
4
|
+
class Teuton < Thor
|
5
|
+
map ['r', '-r', '--readme'] => 'readme'
|
6
|
+
option :lang, type: :string
|
7
|
+
desc 'readme DIRECTORY',
|
8
|
+
'Create README.md file from challenge contents'
|
9
|
+
long_desc <<-LONGDESC
|
10
|
+
|
11
|
+
(1) teuton readme foo
|
12
|
+
, Create README.md from foo/start.rb.
|
13
|
+
|
14
|
+
(2) teuton readme foo/demo.rb
|
15
|
+
, Create README.md from foo/demo.rb.
|
16
|
+
|
17
|
+
By default lang=es, but It's available lang=en too.
|
18
|
+
|
19
|
+
LONGDESC
|
20
|
+
def readme(path_to_rb_file)
|
21
|
+
Project.readme(path_to_rb_file, options)
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Teuton#test
|
4
|
+
class Teuton < Thor
|
5
|
+
map ['t', '-t', '--test'] => 'test'
|
6
|
+
option :c, type: :boolean
|
7
|
+
option :cname, type: :string
|
8
|
+
option :cpath, type: :string
|
9
|
+
desc 'test [OPTIONS] DIRECTORY',
|
10
|
+
'Test or check challenge contents'
|
11
|
+
long_desc <<-LONGDESC
|
12
|
+
|
13
|
+
(1) teuton test path/to/dir/foo
|
14
|
+
, Test content of start.rb and config.yaml files.
|
15
|
+
|
16
|
+
(2) teuton test path/to/dir/foo -c
|
17
|
+
, Only test CONFIG information from config.yaml.
|
18
|
+
|
19
|
+
(3) teuton test path/to/dir/foo --cname=demo
|
20
|
+
, Test content of start.rb and demo.yaml files.
|
21
|
+
|
22
|
+
(4) teuton test path/to/file/foo.rb
|
23
|
+
, Test content of foo.rb and foo.yaml files.
|
24
|
+
|
25
|
+
(5) teuton test path/to/file/foo.rb -c
|
26
|
+
, Only test CONFIG information from foo.yaml.
|
27
|
+
|
28
|
+
(6) teuton test path/to/file/foo.rb --cname=demo
|
29
|
+
, Test content of foo.rb and demo.yaml files.
|
30
|
+
|
31
|
+
LONGDESC
|
32
|
+
def test(path_to_rb_file)
|
33
|
+
Project.test(path_to_rb_file, options)
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rainbow'
|
4
|
+
|
5
|
+
# Class method Teuton#update
|
6
|
+
class Teuton < Thor
|
7
|
+
map ['--update', '-u', 'u'] => 'update'
|
8
|
+
desc 'update', 'Update TEUTON from git repo'
|
9
|
+
long_desc <<-LONGDESC
|
10
|
+
Update TEUTON project, downloading files from git repo.
|
11
|
+
Execute "cd PATH/TO/TEUTON/DIR && git pull".
|
12
|
+
|
13
|
+
Alias: teuton u, teuton -u, teuton --update
|
14
|
+
|
15
|
+
LONGDESC
|
16
|
+
def update
|
17
|
+
dir = File.absolute_path(File.join(File.dirname(__FILE__), '..', '..'))
|
18
|
+
ok = system("cd #{dir} && git pull")
|
19
|
+
if ok
|
20
|
+
puts Rainbow('[ OK ] teuton update').green.bright
|
21
|
+
exit(0)
|
22
|
+
else
|
23
|
+
puts Rainbow('[FAIL] teuton update').red.bright
|
24
|
+
exit(1)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rainbow'
|
4
|
+
|
5
|
+
# Class method Teuton#version
|
6
|
+
class Teuton < Thor
|
7
|
+
map ['v', '-v', '--version'] => 'version'
|
8
|
+
desc 'version', 'Show the program version'
|
9
|
+
def version
|
10
|
+
print Rainbow(Application::NAME).bright.blue
|
11
|
+
puts ' (version ' + Rainbow(Application::VERSION).green + ')'
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'yaml'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
# Functions that read data from ConfigFile using formats YAML and JSON
|
7
|
+
# * read
|
8
|
+
# * read_yaml
|
9
|
+
# * read_json
|
10
|
+
module ConfigFileReader
|
11
|
+
def self.read(filepath)
|
12
|
+
unless File.exist?(filepath)
|
13
|
+
data = {}
|
14
|
+
data[:global] = {}
|
15
|
+
data[:alias] = {}
|
16
|
+
data[:cases] = [{ tt_members: 'anonymous' }]
|
17
|
+
return data
|
18
|
+
end
|
19
|
+
return read_yaml(filepath) if File.extname(filepath) == '.yaml'
|
20
|
+
|
21
|
+
return read_json(filepath) if File.extname(filepath) == '.json'
|
22
|
+
|
23
|
+
raise "[ERROR] ConfigFileReader: #{filepath}"
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.read_yaml(filepath)
|
27
|
+
begin
|
28
|
+
data = YAML.load(File.open(filepath))
|
29
|
+
rescue StandardError => e
|
30
|
+
puts "\n" + ('=' * 80)
|
31
|
+
puts "[ERROR] ConfigFileReader#read <#{filepath}>"
|
32
|
+
puts ' I suggest to revise file format!'
|
33
|
+
puts " #{e.message}\n" + ('=' * 80)
|
34
|
+
raise "[ERROR] ConfigFileReader <#{e}>"
|
35
|
+
end
|
36
|
+
data[:global] = data[:global] || {}
|
37
|
+
data[:alias] = data[:alias] || {}
|
38
|
+
data[:cases] = data[:cases] || []
|
39
|
+
data
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.read_json(filepath)
|
43
|
+
data = JSON.parse(File.read(filepath), symbolize_names: true)
|
44
|
+
data[:global] = data[:global] || {}
|
45
|
+
data[:alias] = data[:alias] || {}
|
46
|
+
data[:cases] = data[:cases] || []
|
47
|
+
data
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
|
2
|
+
class Builtin
|
3
|
+
attr_accessor :param
|
4
|
+
|
5
|
+
def initialize(parent)
|
6
|
+
@parent = parent
|
7
|
+
end
|
8
|
+
|
9
|
+
def method_missing(method)
|
10
|
+
@parent.log "BUILTIN #{method}"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# Laboratory
|
15
|
+
# * service
|
16
|
+
class Laboratory
|
17
|
+
def service(param)
|
18
|
+
log "BUILTIN service(#{param})"
|
19
|
+
@builtin = @builtin || Builtin.new(self)
|
20
|
+
@builtin.param = param
|
21
|
+
@builtin
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
# Laboratory
|
2
|
+
# * target
|
3
|
+
# * request (development)
|
4
|
+
# * tempfile
|
5
|
+
# * goto
|
6
|
+
# * run
|
7
|
+
# * expect
|
8
|
+
# * get
|
9
|
+
# * unique
|
10
|
+
# * log
|
11
|
+
# * set
|
12
|
+
class Laboratory
|
13
|
+
def readme(_text)
|
14
|
+
# Usefull for "teuton reamde" action.
|
15
|
+
end
|
16
|
+
|
17
|
+
def target(desc, args = {})
|
18
|
+
@stats[:targets] += 1
|
19
|
+
@targetid += 1
|
20
|
+
weight = args[:weight] || 1.0
|
21
|
+
verboseln '(%03d' % @targetid + ") target #{desc}"
|
22
|
+
verboseln " weight #{weight}"
|
23
|
+
end
|
24
|
+
alias goal target
|
25
|
+
|
26
|
+
def request(text)
|
27
|
+
@requests << text.to_s
|
28
|
+
end
|
29
|
+
|
30
|
+
def tempfile(_tempfile = nil)
|
31
|
+
'tempfile'
|
32
|
+
end
|
33
|
+
|
34
|
+
def goto(host = :localhost, args = {})
|
35
|
+
result.reset
|
36
|
+
|
37
|
+
if @hosts[host]
|
38
|
+
@hosts[host] += 1
|
39
|
+
else
|
40
|
+
@hosts[host] = 1
|
41
|
+
end
|
42
|
+
verboseln " goto #{host} and #{args}"
|
43
|
+
end
|
44
|
+
|
45
|
+
def run(command, args = {})
|
46
|
+
args[:exec] = command
|
47
|
+
goto(:localhost, args)
|
48
|
+
end
|
49
|
+
|
50
|
+
def expect(_cond, args = {})
|
51
|
+
#unless [ String, Array, Regexp].include? _cond.class
|
52
|
+
# verboseln "[ERROR] expect #{_cond} (#{_cond.class})"
|
53
|
+
# return
|
54
|
+
#end
|
55
|
+
verboseln " alter #{result.alterations}" unless result.alterations.empty?
|
56
|
+
#verboseln " expect #{result.expected} (#{result.expected.class})"
|
57
|
+
verboseln " expect #{_cond} (#{_cond.class})"
|
58
|
+
verboseln ''
|
59
|
+
end
|
60
|
+
|
61
|
+
def expect_one(_cond, args = {})
|
62
|
+
verboseln " alter #{result.alterations}" unless result.alterations.empty?
|
63
|
+
verboseln " expect_one #{_cond} (#{_cond.class})"
|
64
|
+
verboseln ''
|
65
|
+
end
|
66
|
+
|
67
|
+
def expect_none(_cond, args = {})
|
68
|
+
verboseln " alter #{result.alterations}" unless result.alterations.empty?
|
69
|
+
verboseln " expect_none #{_cond} (#{_cond.class})"
|
70
|
+
verboseln ''
|
71
|
+
end
|
72
|
+
|
73
|
+
def get(varname)
|
74
|
+
@stats[:gets] += 1
|
75
|
+
|
76
|
+
if @gets[varname]
|
77
|
+
@gets[varname] += 1
|
78
|
+
else
|
79
|
+
@gets[varname] = 1
|
80
|
+
end
|
81
|
+
|
82
|
+
"get(#{varname})"
|
83
|
+
end
|
84
|
+
|
85
|
+
# If a method call is missing, then delegate to concept parent.
|
86
|
+
def method_missing(method)
|
87
|
+
a = method.to_s
|
88
|
+
instance_eval("get(:#{a[0, a.size - 1]})") if a[a.size - 1] == '?'
|
89
|
+
end
|
90
|
+
|
91
|
+
def gett(option)
|
92
|
+
value = get(option)
|
93
|
+
value
|
94
|
+
end
|
95
|
+
|
96
|
+
def unique(key, _value)
|
97
|
+
@stats[:uniques] += 1
|
98
|
+
|
99
|
+
verboseln " ! Unique value for <#{key}>"
|
100
|
+
verboseln ''
|
101
|
+
end
|
102
|
+
|
103
|
+
def log(text = '', type = :info)
|
104
|
+
@stats[:logs] += 1
|
105
|
+
verboseln " log [#{type}]: " + text.to_s
|
106
|
+
end
|
107
|
+
|
108
|
+
def set(key, value)
|
109
|
+
@stats[:sets] += 1
|
110
|
+
|
111
|
+
key = ':' + key.to_s if key.class == Symbol
|
112
|
+
value = ':' + value.to_s if value.class == Symbol
|
113
|
+
|
114
|
+
@sets[key] = value
|
115
|
+
"set(#{key},#{value})"
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'terminal-table'
|
4
|
+
require 'rainbow'
|
5
|
+
|
6
|
+
require_relative '../../application'
|
7
|
+
require_relative '../../case_manager/case/result/result'
|
8
|
+
require_relative 'show'
|
9
|
+
require_relative 'dsl'
|
10
|
+
require_relative 'builtin'
|
11
|
+
|
12
|
+
def use(filename)
|
13
|
+
filename += '.rb'
|
14
|
+
app = Application.instance
|
15
|
+
rbfiles = File.join(app.project_path, "**", filename)
|
16
|
+
files = Dir.glob(rbfiles)
|
17
|
+
use = []
|
18
|
+
files.sort.each { |f| use << f if f.include?(filename) }
|
19
|
+
require_relative use[0]
|
20
|
+
end
|
21
|
+
|
22
|
+
def group(name, &block)
|
23
|
+
Application.instance.groups << { name: name, block: block }
|
24
|
+
end
|
25
|
+
alias task group
|
26
|
+
|
27
|
+
def start(&block)
|
28
|
+
# don't do nothing
|
29
|
+
end
|
30
|
+
alias play start
|
31
|
+
|
32
|
+
# Show objectives stats from RB script file
|
33
|
+
class Laboratory
|
34
|
+
attr_reader :result
|
35
|
+
|
36
|
+
def initialize(script_path, config_path)
|
37
|
+
@path = {}
|
38
|
+
@path[:script] = script_path
|
39
|
+
@path[:dirname] = File.dirname(script_path)
|
40
|
+
@path[:filename] = File.basename(script_path, '.rb')
|
41
|
+
@path[:config] = config_path
|
42
|
+
reset
|
43
|
+
end
|
44
|
+
|
45
|
+
def reset
|
46
|
+
@result = Result.new
|
47
|
+
@targetid = 0
|
48
|
+
@stats = { groups: 0, targets: 0, uniques: 0, gets: 0, logs: 0, sets: 0 }
|
49
|
+
@gets = {}
|
50
|
+
@sets = {}
|
51
|
+
@hosts = {}
|
52
|
+
@requests = []
|
53
|
+
@verbose = Application.instance.verbose
|
54
|
+
end
|
55
|
+
end
|