omnitest 0.2.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 +7 -0
- data/.gitignore +18 -0
- data/.gitmodules +0 -0
- data/.groc.json +7 -0
- data/.rspec +6 -0
- data/.rubocop.yml +5 -0
- data/.rubocop_todo.yml +47 -0
- data/.travis.yml +12 -0
- data/.yardopts +3 -0
- data/Gemfile +26 -0
- data/README.md +341 -0
- data/Rakefile +33 -0
- data/appveyor.yml +9 -0
- data/bin/omnidoc +5 -0
- data/bin/omnitask +5 -0
- data/bin/omnitest +5 -0
- data/bower.json +21 -0
- data/doc-src/index.md.tt +341 -0
- data/doc-src/project_sets.md.tt +31 -0
- data/doc-src/usage/crosstask.md.tt +86 -0
- data/doc-src/usage/omnitest.md.tt +87 -0
- data/features/bootstrapping.feature +25 -0
- data/features/cloning.feature +32 -0
- data/features/fixtures/configs/omnitest_sample.yaml +11 -0
- data/features/fixtures/configs/skeptic_empty.yaml +12 -0
- data/features/fixtures/configs/skeptic_hello_world.yaml +10 -0
- data/features/show.feature +38 -0
- data/features/states.feature +40 -0
- data/features/step_definitions/sdk_steps.rb +22 -0
- data/features/support/env.rb +9 -0
- data/lib/omnitest.rb +211 -0
- data/lib/omnitest/cli.rb +297 -0
- data/lib/omnitest/command.rb +103 -0
- data/lib/omnitest/command/generate.rb +29 -0
- data/lib/omnitest/command/generators/code2doc.rb +79 -0
- data/lib/omnitest/command/generators/dashboard.rb +148 -0
- data/lib/omnitest/command/generators/documentation.rb +119 -0
- data/lib/omnitest/command/list.rb +62 -0
- data/lib/omnitest/command/project_action.rb +26 -0
- data/lib/omnitest/command/scenario_action.rb +20 -0
- data/lib/omnitest/command/show.rb +148 -0
- data/lib/omnitest/command/task.rb +27 -0
- data/lib/omnitest/command/test.rb +41 -0
- data/lib/omnitest/configuration.rb +53 -0
- data/lib/omnitest/documentation_generator.rb +68 -0
- data/lib/omnitest/project.rb +100 -0
- data/lib/omnitest/project_logger.rb +273 -0
- data/lib/omnitest/project_set.rb +47 -0
- data/lib/omnitest/reporters.rb +27 -0
- data/lib/omnitest/reporters/hash_reporter.rb +32 -0
- data/lib/omnitest/reporters/json_reporter.rb +12 -0
- data/lib/omnitest/reporters/markdown_reporter.rb +26 -0
- data/lib/omnitest/reporters/yaml_reporter.rb +12 -0
- data/lib/omnitest/run_action.rb +44 -0
- data/lib/omnitest/version.rb +3 -0
- data/lib/omnitest/workflow.rb +5 -0
- data/mkdocs.yml +8 -0
- data/omnitest.gemspec +39 -0
- data/omnitest.yaml +5 -0
- data/resources/assets/angular/angular.min.js +217 -0
- data/resources/assets/angular/angular.min.js.map +8 -0
- data/resources/assets/angular/json-formatter.min.css +6 -0
- data/resources/assets/angular/json-formatter.min.js +7 -0
- data/resources/assets/angular/ng-table.map +1 -0
- data/resources/assets/angular/ng-table.min.css +3 -0
- data/resources/assets/angular/ng-table.min.js +3 -0
- data/resources/assets/angular/ui-bootstrap-tpls.min.js +10 -0
- data/resources/assets/bootstrap/bootstrap.min.css +9 -0
- data/resources/assets/fonts/glyphicons-halflings-regular.eot +0 -0
- data/resources/assets/fonts/glyphicons-halflings-regular.svg +229 -0
- data/resources/assets/fonts/glyphicons-halflings-regular.ttf +0 -0
- data/resources/assets/fonts/glyphicons-halflings-regular.woff +0 -0
- data/resources/assets/pygments/autumn.css +58 -0
- data/resources/assets/pygments/borland.css +46 -0
- data/resources/assets/pygments/bw.css +34 -0
- data/resources/assets/pygments/colorful.css +61 -0
- data/resources/assets/pygments/default.css +62 -0
- data/resources/assets/pygments/emacs.css +61 -0
- data/resources/assets/pygments/friendly.css +61 -0
- data/resources/assets/pygments/fruity.css +69 -0
- data/resources/assets/pygments/github.css +61 -0
- data/resources/assets/pygments/manni.css +61 -0
- data/resources/assets/pygments/monokai.css +64 -0
- data/resources/assets/pygments/murphy.css +61 -0
- data/resources/assets/pygments/native.css +69 -0
- data/resources/assets/pygments/pastie.css +60 -0
- data/resources/assets/pygments/perldoc.css +58 -0
- data/resources/assets/pygments/tango.css +69 -0
- data/resources/assets/pygments/trac.css +59 -0
- data/resources/assets/pygments/vim.css +69 -0
- data/resources/assets/pygments/vs.css +33 -0
- data/resources/assets/pygments/zenburn.css +1 -0
- data/resources/assets/style.css +56 -0
- data/resources/code_sample.tt +2 -0
- data/resources/generators/dashboard/files/dashboard.html.tt +51 -0
- data/resources/generators/dashboard/files/dashboard.js +26 -0
- data/resources/generators/dashboard/templates/_test_report.html.haml +91 -0
- data/resources/generators/todo/templates/todo.md.tt +6 -0
- data/resources/generators/todo/todo_template.rb +1 -0
- data/samples/.gitignore +2 -0
- data/samples/_markdown.md +5 -0
- data/samples/bootstrap.sh +2 -0
- data/samples/clone.sh +2 -0
- data/samples/code2doc.sh +5 -0
- data/samples/default_bootstrap.rb +7 -0
- data/samples/detect.sh +2 -0
- data/samples/exec.sh +2 -0
- data/samples/omnitest.yaml +24 -0
- data/samples/omnitest_simple.yaml +8 -0
- data/samples/scripts/bootstrap +3 -0
- data/samples/show.sh +4 -0
- data/samples/skeptic.yaml +13 -0
- data/samples/skeptic_simple.yaml +9 -0
- data/samples/test.sh +2 -0
- data/samples/tests/omnitest/validators.rb +23 -0
- data/samples/verify.sh +3 -0
- data/scripts/bootstrap.ps1 +7 -0
- data/scripts/run_script.sh +4 -0
- data/skeptic.yaml +26 -0
- data/spec/fabricators/project_fabricator.rb +19 -0
- data/spec/fabricators/scenario_fabricator.rb +6 -0
- data/spec/fabricators/test_manifest_fabricator.rb +41 -0
- data/spec/fabricators/validator_fabricator.rb +12 -0
- data/spec/fixtures/factorial.py +18 -0
- data/spec/fixtures/omnitest.yaml +11 -0
- data/spec/fixtures/skeptic.yaml +16 -0
- data/spec/fixtures/src-doc/_scenario.md.erb +1 -0
- data/spec/fixtures/src-doc/quine.md.erb +20 -0
- data/spec/omnitest/cli_spec.rb +38 -0
- data/spec/omnitest/configuration_spec.rb +25 -0
- data/spec/omnitest/documentation_generator_spec.rb +59 -0
- data/spec/omnitest/file_finder_spec.rb +21 -0
- data/spec/omnitest/project_spec.rb +65 -0
- data/spec/omnitest_spec.rb +13 -0
- data/spec/spec_helper.rb +32 -0
- data/spec/thor_spy.rb +66 -0
- data/tests/omnitest/bootstrap_validations.rb +7 -0
- data/tests/omnitest/show_validations.rb +22 -0
- data/yard_macros.rb +25 -0
- metadata +470 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
require 'benchmark'
|
|
2
|
+
|
|
3
|
+
module Omnitest
|
|
4
|
+
module Command
|
|
5
|
+
class Task < Omnitest::Command::Base
|
|
6
|
+
include RunAction
|
|
7
|
+
|
|
8
|
+
# Invoke the command.
|
|
9
|
+
def call
|
|
10
|
+
banner "Starting Omnitest (v#{Omnitest::VERSION})"
|
|
11
|
+
elapsed = Benchmark.measure do
|
|
12
|
+
setup
|
|
13
|
+
task = args.shift
|
|
14
|
+
project_regex = args.shift
|
|
15
|
+
projects = Omnitest.filter_projects(project_regex)
|
|
16
|
+
if options[:exec]
|
|
17
|
+
run_action(projects, :execute, options[:concurrency])
|
|
18
|
+
else
|
|
19
|
+
run_action(projects, task, options[:concurrency])
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
# Need task summary...
|
|
23
|
+
banner "Omnitest is finished. #{Core::Util.duration(elapsed.real)}"
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
require 'omnitest/command'
|
|
2
|
+
|
|
3
|
+
require 'benchmark'
|
|
4
|
+
|
|
5
|
+
module Omnitest
|
|
6
|
+
module Command
|
|
7
|
+
# Command to test one or more instances.
|
|
8
|
+
class Test < Omnitest::Command::Base
|
|
9
|
+
include RunAction
|
|
10
|
+
|
|
11
|
+
# Invoke the command.
|
|
12
|
+
def call
|
|
13
|
+
banner "Starting Omnitest (v#{Omnitest::VERSION})"
|
|
14
|
+
scenarios = nil
|
|
15
|
+
elapsed = Benchmark.measure do
|
|
16
|
+
setup
|
|
17
|
+
scenarios = parse_subcommand(args.shift, args.shift)
|
|
18
|
+
|
|
19
|
+
run_action(scenarios, :test, options[:concurrency])
|
|
20
|
+
end
|
|
21
|
+
banner "Omnitest is finished. #{Core::Util.duration(elapsed.real)}"
|
|
22
|
+
test_summary(scenarios)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def test_summary(scenarios)
|
|
26
|
+
# TODO: Need an actual test summary
|
|
27
|
+
failed_scenarios = scenarios.select do | s |
|
|
28
|
+
!s.status_description.match(/Fully Verified|<Not Found>/)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
shell.say
|
|
32
|
+
failed_scenarios.each do | scenario |
|
|
33
|
+
shell.say_status scenario.status_description, scenario.slug
|
|
34
|
+
end
|
|
35
|
+
status_line = "#{scenarios.size} scenarios, #{failed_scenarios.size} failures" # , x pending
|
|
36
|
+
shell.say status_line
|
|
37
|
+
abort unless failed_scenarios.empty?
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
|
|
2
|
+
require 'rspec/support'
|
|
3
|
+
require 'rspec/expectations'
|
|
4
|
+
|
|
5
|
+
module Omnitest
|
|
6
|
+
RESOURCES_DIR = File.expand_path '../../../resources', __FILE__
|
|
7
|
+
|
|
8
|
+
class Configuration < Omnitest::Core::Dash
|
|
9
|
+
extend Forwardable
|
|
10
|
+
field :dry_run, Object, default: false
|
|
11
|
+
field :log_root, Pathname, default: '.omnitest/logs'
|
|
12
|
+
field :log_level, Symbol, default: :info
|
|
13
|
+
field :travis, Object, default: false
|
|
14
|
+
field :concurrency, Integer
|
|
15
|
+
|
|
16
|
+
# TODO: This should probably be configurable, or tied to Thor color options.
|
|
17
|
+
if RSpec.respond_to?(:configuration)
|
|
18
|
+
RSpec.configuration.color = true
|
|
19
|
+
else
|
|
20
|
+
RSpec::Expectations.configuration.color = true
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def skeptic
|
|
24
|
+
Skeptic.configuration
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def default_logger
|
|
28
|
+
@default_logger ||= ProjectLogger.new(stdout: $stdout, level: Core::Util.to_logger_level(log_level))
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def project_set
|
|
32
|
+
@project_set ||= load_project_set('omnitest.yaml')
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def project_set=(project_set_data)
|
|
36
|
+
if project_set_data.is_a? Skeptic::TestManifest
|
|
37
|
+
@project_set = project_set_data
|
|
38
|
+
else
|
|
39
|
+
@project_set = ProjectSet.from_yaml project_set_data
|
|
40
|
+
end
|
|
41
|
+
@project_set
|
|
42
|
+
rescue Errno::ENOENT => e
|
|
43
|
+
raise UserError, "Could not load test manifest: #{e.message}"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def clear
|
|
47
|
+
skeptic.clear
|
|
48
|
+
super
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
alias_method :load_project_set, :project_set=
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
require 'tilt' # padrino-helpers wants you to pre-require tilt/erubis
|
|
2
|
+
require 'erubis'
|
|
3
|
+
require 'padrino-helpers'
|
|
4
|
+
|
|
5
|
+
module Omnitest
|
|
6
|
+
class DocumentationGenerator
|
|
7
|
+
[
|
|
8
|
+
Padrino::Helpers::OutputHelpers,
|
|
9
|
+
Padrino::Helpers::AssetTagHelpers,
|
|
10
|
+
Padrino::Helpers::TagHelpers,
|
|
11
|
+
Omnitest::Psychic::Code2Doc::CodeHelper
|
|
12
|
+
].each do | helper|
|
|
13
|
+
include helper
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
attr_reader :scenario
|
|
17
|
+
|
|
18
|
+
def initialize(template_file = nil, scenario = nil)
|
|
19
|
+
@scenario = scenario
|
|
20
|
+
@template_file = template_file
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def process(scenarios)
|
|
24
|
+
return nil unless File.readable? @template_file
|
|
25
|
+
|
|
26
|
+
@scenarios = scenarios
|
|
27
|
+
erb = ERB.new File.read(@template_file)
|
|
28
|
+
@result = erb.result(binding) || ''
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def save(target_file)
|
|
32
|
+
fail 'No results to write, please call process before save' if @result.nil? || @result.empty?
|
|
33
|
+
|
|
34
|
+
FileUtils.mkdir_p File.dirname(target_file)
|
|
35
|
+
File.open(target_file, 'wb') do |f|
|
|
36
|
+
f.write @result
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def code2doc(source_file, language = nil)
|
|
41
|
+
source_code = File.read(source_file)
|
|
42
|
+
segmenter_language ||= infer_language(source_file)
|
|
43
|
+
|
|
44
|
+
buffer = StringIO.new
|
|
45
|
+
segmenter_options = {
|
|
46
|
+
language: language
|
|
47
|
+
}
|
|
48
|
+
segmenter = Omnitest::Psychic::Code2Doc::CodeSegmenter.new(segmenter_options)
|
|
49
|
+
segments = segmenter.segment source_code
|
|
50
|
+
segments.each do |comment, code|
|
|
51
|
+
comment = comment.join("\n")
|
|
52
|
+
code = code.join("\n")
|
|
53
|
+
code = code_block(code, language) unless code.empty?
|
|
54
|
+
next if comment.empty? && code.empty?
|
|
55
|
+
code = "\n#{code}\n" if !comment.empty? && !code.empty? # Markdown needs separation
|
|
56
|
+
buffer.puts [comment, code].join("\n")
|
|
57
|
+
end
|
|
58
|
+
buffer.string
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
private
|
|
62
|
+
|
|
63
|
+
def infer_language(source_file)
|
|
64
|
+
language, comment_style = Psychic::Code2Doc::CommentStyles.infer File.extname(source_file)
|
|
65
|
+
segmenter_language = comment_style[:language] || language
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
module Omnitest
|
|
2
|
+
class Project < Omnitest::Core::Dash
|
|
3
|
+
include Omnitest::Core::Logging
|
|
4
|
+
include Omnitest::Core::FileSystem
|
|
5
|
+
|
|
6
|
+
class GitOptions < Omnitest::Core::Dash
|
|
7
|
+
required_field :repo, String
|
|
8
|
+
field :branch, String
|
|
9
|
+
field :to, String
|
|
10
|
+
|
|
11
|
+
def initialize(data)
|
|
12
|
+
data = { repo: data } if data.is_a? String
|
|
13
|
+
super
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
field :name, String
|
|
18
|
+
field :basedir, Pathname
|
|
19
|
+
field :language, String
|
|
20
|
+
field :git, GitOptions
|
|
21
|
+
|
|
22
|
+
alias_method :cwd, :basedir
|
|
23
|
+
|
|
24
|
+
attr_accessor :psychic, :skeptic
|
|
25
|
+
|
|
26
|
+
def psychic
|
|
27
|
+
@psychic ||= Omnitest::Psychic.new(name: name, cwd: basedir, logger: logger, travis: Omnitest.configuration.travis)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def skeptic
|
|
31
|
+
@skeptic ||= Omnitest::Skeptic.new(psychic)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def execute(*args)
|
|
35
|
+
psychic.execute(*args)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def basedir
|
|
39
|
+
self[:basedir] ||= "projects/#{name}"
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def logger
|
|
43
|
+
@logger ||= Omnitest.new_logger(self)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def clone
|
|
47
|
+
if git.nil? || git.repo.nil?
|
|
48
|
+
logger.info 'Skipping clone because there are no git options'
|
|
49
|
+
return
|
|
50
|
+
end
|
|
51
|
+
branch = git.branch ||= 'master'
|
|
52
|
+
target_dir = git.to ||= basedir
|
|
53
|
+
target_dir = Omnitest::Core::FileSystem.relativize(target_dir, Omnitest.basedir)
|
|
54
|
+
if File.exist? target_dir
|
|
55
|
+
logger.info "Skipping clone because #{target_dir} already exists"
|
|
56
|
+
else
|
|
57
|
+
clone_cmd = "git clone #{git.repo} -b #{branch} #{target_dir}"
|
|
58
|
+
logger.info "Cloning: #{clone_cmd}"
|
|
59
|
+
Omnitest.psychic.execute(clone_cmd)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def task(task_name, opts = { fail_if_missing: true })
|
|
64
|
+
banner_msg = opts[:custom_banner] || "Running task #{task_name} for #{name}"
|
|
65
|
+
banner banner_msg
|
|
66
|
+
fail "Project #{name} has not been cloned" unless cloned?
|
|
67
|
+
psychic.task(task_name).execute
|
|
68
|
+
rescue Omnitest::Psychic::TaskNotImplementedError => e
|
|
69
|
+
if opts[:fail_if_missing]
|
|
70
|
+
logger.error("Could not run task #{task_name} for #{name}: #{e.message}")
|
|
71
|
+
raise ActionFailed.new("Failed to run task #{task_name} for #{name}: #{e.message}", e)
|
|
72
|
+
else
|
|
73
|
+
logger.warn "Skipping #{task_name} for #{name}, no #{task_name} task exists"
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def workflow(workflow_name)
|
|
78
|
+
workflow_definition = Omnitest.configuration.project_set.workflows[workflow_name]
|
|
79
|
+
fail UserError, "Workflow '#{workflow_name}' is not defined" if workflow_definition.nil?
|
|
80
|
+
|
|
81
|
+
workflow = psychic.workflow(workflow_name) do
|
|
82
|
+
workflow_definition.tasks.each do | task_name |
|
|
83
|
+
task task_name
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
workflow.execute
|
|
88
|
+
rescue Psychic::TaskNotImplementedError => e
|
|
89
|
+
raise UserError, "Cannot run workflow '#{workflow_name}' for project '#{name}': #{e.message}"
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def bootstrap
|
|
93
|
+
task('bootstrap', custom_banner: "Bootstrapping #{name}", fail_if_missing: false)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def cloned?
|
|
97
|
+
File.directory? basedir
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
require 'fileutils'
|
|
2
|
+
require 'logger'
|
|
3
|
+
|
|
4
|
+
module Omnitest
|
|
5
|
+
class ProjectLogger
|
|
6
|
+
include ::Logger::Severity
|
|
7
|
+
|
|
8
|
+
# @return [IO] the log device
|
|
9
|
+
attr_reader :logdev
|
|
10
|
+
|
|
11
|
+
# Constructs a new logger.
|
|
12
|
+
#
|
|
13
|
+
# @param options [Hash] configuration for a new logger
|
|
14
|
+
# @option options [Symbol] :color color to use when when outputting
|
|
15
|
+
# messages
|
|
16
|
+
# @option options [Integer] :level the logging severity threshold
|
|
17
|
+
# (default: `Omnitest::DEFAULT_LOG_LEVEL`)
|
|
18
|
+
# @option options [String,IO] :logdev filepath String or IO object to be
|
|
19
|
+
# used for logging (default: `nil`)
|
|
20
|
+
# @option options [String] :progname program name to include in log
|
|
21
|
+
# messages (default: `"Omnitest"`)
|
|
22
|
+
# @option options [IO] :stdout a standard out IO object to use
|
|
23
|
+
# (default: `$stdout`)
|
|
24
|
+
def initialize(options = {})
|
|
25
|
+
color = options[:color]
|
|
26
|
+
|
|
27
|
+
@loggers = []
|
|
28
|
+
@loggers << @logdev = logdev_logger(options[:logdev]) if options[:logdev]
|
|
29
|
+
@loggers << stdout_logger(options[:stdout], color) if options[:stdout]
|
|
30
|
+
@loggers << stdout_logger($stdout, color) if @loggers.empty?
|
|
31
|
+
|
|
32
|
+
self.progname = options[:progname] || 'Omnitest'
|
|
33
|
+
self.level = options[:level] || default_log_level
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
class << self
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
# @api private
|
|
40
|
+
# @!macro delegate_to_first_logger
|
|
41
|
+
# @method $1()
|
|
42
|
+
def delegate_to_first_logger(meth)
|
|
43
|
+
define_method(meth) { |*args| @loggers.first.public_send(meth, *args) }
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# @api private
|
|
47
|
+
# @!macro delegate_to_all_loggers
|
|
48
|
+
# @method $1()
|
|
49
|
+
def delegate_to_all_loggers(meth)
|
|
50
|
+
define_method(meth) do |*args|
|
|
51
|
+
result = nil
|
|
52
|
+
@loggers.each { |l| result = l.public_send(meth, *args) }
|
|
53
|
+
result
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# @return [Integer] the logging severity threshold
|
|
59
|
+
# @see http://is.gd/Okuy5p
|
|
60
|
+
delegate_to_first_logger :level
|
|
61
|
+
|
|
62
|
+
# Sets the logging severity threshold.
|
|
63
|
+
#
|
|
64
|
+
# @param level [Integer] the logging severity threshold
|
|
65
|
+
# @see http://is.gd/H1VBFH
|
|
66
|
+
delegate_to_all_loggers :level=
|
|
67
|
+
|
|
68
|
+
# @return [String] program name to include in log messages
|
|
69
|
+
# @see http://is.gd/5uHGK0
|
|
70
|
+
delegate_to_first_logger :progname
|
|
71
|
+
|
|
72
|
+
# Sets the program name to include in log messages.
|
|
73
|
+
#
|
|
74
|
+
# @param progname [String] the program name to include in log messages
|
|
75
|
+
# @see http://is.gd/f2U5Xj
|
|
76
|
+
delegate_to_all_loggers :progname=
|
|
77
|
+
|
|
78
|
+
# @return [String] the date format being used
|
|
79
|
+
# @see http://is.gd/btmFWJ
|
|
80
|
+
delegate_to_first_logger :datetime_format
|
|
81
|
+
|
|
82
|
+
# Sets the date format being used.
|
|
83
|
+
#
|
|
84
|
+
# @param format [String] the date format
|
|
85
|
+
# @see http://is.gd/M36ml8
|
|
86
|
+
delegate_to_all_loggers :datetime_format=
|
|
87
|
+
|
|
88
|
+
# Log a message if the given severity is high enough.
|
|
89
|
+
#
|
|
90
|
+
# @see http://is.gd/5opBW0
|
|
91
|
+
delegate_to_all_loggers :add
|
|
92
|
+
|
|
93
|
+
# Dump one or more messages to info.
|
|
94
|
+
#
|
|
95
|
+
# @param message [#to_s] the message to log
|
|
96
|
+
# @see http://is.gd/BCp5KV
|
|
97
|
+
delegate_to_all_loggers :<<
|
|
98
|
+
|
|
99
|
+
# Log a message with severity of banner (high level).
|
|
100
|
+
#
|
|
101
|
+
# @param message_or_progname [#to_s] the message to log. In the block
|
|
102
|
+
# form, this is the progname to use in the log message.
|
|
103
|
+
# @yield evaluates to the message to log. This is not evaluated unless the
|
|
104
|
+
# logger's level is sufficient to log the message. This allows you to
|
|
105
|
+
# create potentially expensive logging messages that are only called when
|
|
106
|
+
# the logger is configured to show them.
|
|
107
|
+
# @return [nil,true] when the given severity is not high enough (for this
|
|
108
|
+
# particular logger), log no message, and return true
|
|
109
|
+
# @see http://is.gd/pYUCYU
|
|
110
|
+
delegate_to_all_loggers :banner
|
|
111
|
+
|
|
112
|
+
# Log a message with severity of debug.
|
|
113
|
+
#
|
|
114
|
+
# @param message_or_progname [#to_s] the message to log. In the block
|
|
115
|
+
# form, this is the progname to use in the log message.
|
|
116
|
+
# @yield evaluates to the message to log. This is not evaluated unless the
|
|
117
|
+
# logger's level is sufficient to log the message. This allows you to
|
|
118
|
+
# create potentially expensive logging messages that are only called when
|
|
119
|
+
# the logger is configured to show them.
|
|
120
|
+
# @return [nil,true] when the given severity is not high enough (for this
|
|
121
|
+
# particular logger), log no message, and return true
|
|
122
|
+
# @see http://is.gd/Re97Zp
|
|
123
|
+
delegate_to_all_loggers :debug
|
|
124
|
+
|
|
125
|
+
# @return [true,false] whether or not the current severity level
|
|
126
|
+
# allows for the printing of debug messages
|
|
127
|
+
# @see http://is.gd/Iq08xB
|
|
128
|
+
delegate_to_first_logger :debug?
|
|
129
|
+
|
|
130
|
+
# Log a message with severity of info.
|
|
131
|
+
#
|
|
132
|
+
# @param message_or_progname [#to_s] the message to log. In the block
|
|
133
|
+
# form, this is the progname to use in the log message.
|
|
134
|
+
# @yield evaluates to the message to log. This is not evaluated unless the
|
|
135
|
+
# logger's level is sufficient to log the message. This allows you to
|
|
136
|
+
# create potentially expensive logging messages that are only called when
|
|
137
|
+
# the logger is configured to show them.
|
|
138
|
+
# @return [nil,true] when the given severity is not high enough (for this
|
|
139
|
+
# particular logger), log no message, and return true
|
|
140
|
+
# @see http://is.gd/pYUCYU
|
|
141
|
+
delegate_to_all_loggers :info
|
|
142
|
+
|
|
143
|
+
# @return [true,false] whether or not the current severity level
|
|
144
|
+
# allows for the printing of info messages
|
|
145
|
+
# @see http://is.gd/lBtJkT
|
|
146
|
+
delegate_to_first_logger :info?
|
|
147
|
+
|
|
148
|
+
# Log a message with severity of error.
|
|
149
|
+
#
|
|
150
|
+
# @param message_or_progname [#to_s] the message to log. In the block
|
|
151
|
+
# form, this is the progname to use in the log message.
|
|
152
|
+
# @yield evaluates to the message to log. This is not evaluated unless the
|
|
153
|
+
# logger's level is sufficient to log the message. This allows you to
|
|
154
|
+
# create potentially expensive logging messages that are only called when
|
|
155
|
+
# the logger is configured to show them.
|
|
156
|
+
# @return [nil,true] when the given severity is not high enough (for this
|
|
157
|
+
# particular logger), log no message, and return true
|
|
158
|
+
# @see http://is.gd/mLwYMl
|
|
159
|
+
delegate_to_all_loggers :error
|
|
160
|
+
|
|
161
|
+
# @return [true,false] whether or not the current severity level
|
|
162
|
+
# allows for the printing of error messages
|
|
163
|
+
# @see http://is.gd/QY19JL
|
|
164
|
+
delegate_to_first_logger :error?
|
|
165
|
+
|
|
166
|
+
# Log a message with severity of warn.
|
|
167
|
+
#
|
|
168
|
+
# @param message_or_progname [#to_s] the message to log. In the block
|
|
169
|
+
# form, this is the progname to use in the log message.
|
|
170
|
+
# @yield evaluates to the message to log. This is not evaluated unless the
|
|
171
|
+
# logger's level is sufficient to log the message. This allows you to
|
|
172
|
+
# create potentially expensive logging messages that are only called when
|
|
173
|
+
# the logger is configured to show them.
|
|
174
|
+
# @return [nil,true] when the given severity is not high enough (for this
|
|
175
|
+
# particular logger), log no message, and return true
|
|
176
|
+
# @see http://is.gd/PX9AIS
|
|
177
|
+
delegate_to_all_loggers :warn
|
|
178
|
+
|
|
179
|
+
# @return [true,false] whether or not the current severity level
|
|
180
|
+
# allows for the printing of warn messages
|
|
181
|
+
# @see http://is.gd/Gdr4lD
|
|
182
|
+
delegate_to_first_logger :warn?
|
|
183
|
+
|
|
184
|
+
# Log a message with severity of fatal.
|
|
185
|
+
#
|
|
186
|
+
# @param message_or_progname [#to_s] the message to log. In the block
|
|
187
|
+
# form, this is the progname to use in the log message.
|
|
188
|
+
# @yield evaluates to the message to log. This is not evaluated unless the
|
|
189
|
+
# logger's level is sufficient to log the message. This allows you to
|
|
190
|
+
# create potentially expensive logging messages that are only called when
|
|
191
|
+
# the logger is configured to show them.
|
|
192
|
+
# @return [nil,true] when the given severity is not high enough (for this
|
|
193
|
+
# particular logger), log no message, and return true
|
|
194
|
+
# @see http://is.gd/5ElFPK
|
|
195
|
+
delegate_to_all_loggers :fatal
|
|
196
|
+
|
|
197
|
+
# @return [true,false] whether or not the current severity level
|
|
198
|
+
# allows for the printing of fatal messages
|
|
199
|
+
# @see http://is.gd/7PgwRl
|
|
200
|
+
delegate_to_first_logger :fatal?
|
|
201
|
+
|
|
202
|
+
# Log a message with severity of unknown.
|
|
203
|
+
#
|
|
204
|
+
# @param message_or_progname [#to_s] the message to log. In the block
|
|
205
|
+
# form, this is the progname to use in the log message.
|
|
206
|
+
# @yield evaluates to the message to log. This is not evaluated unless the
|
|
207
|
+
# logger's level is sufficient to log the message. This allows you to
|
|
208
|
+
# create potentially expensive logging messages that are only called when
|
|
209
|
+
# the logger is configured to show them.
|
|
210
|
+
# @return [nil,true] when the given severity is not high enough (for this
|
|
211
|
+
# particular logger), log no message, and return true
|
|
212
|
+
# @see http://is.gd/Y4hqpf
|
|
213
|
+
delegate_to_all_loggers :unknown
|
|
214
|
+
|
|
215
|
+
# Close the logging devices.
|
|
216
|
+
#
|
|
217
|
+
# @see http://is.gd/b13cVn
|
|
218
|
+
delegate_to_all_loggers :close
|
|
219
|
+
|
|
220
|
+
private
|
|
221
|
+
|
|
222
|
+
# @return [Integer] the default logger level
|
|
223
|
+
# @api private
|
|
224
|
+
def default_log_level
|
|
225
|
+
Omnitest::Core::Util.to_logger_level(Omnitest.configuration.log_level)
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
# Construct a new standard out logger.
|
|
229
|
+
#
|
|
230
|
+
# @param stdout [IO] the IO object that represents stdout (or similar)
|
|
231
|
+
# @param color [Symbol] color to use when outputing messages
|
|
232
|
+
# @return [StdoutLogger] a new logger
|
|
233
|
+
# @api private
|
|
234
|
+
def stdout_logger(stdout, color)
|
|
235
|
+
logger = Omnitest::Core::StdoutLogger.new(stdout)
|
|
236
|
+
if Omnitest.tty?
|
|
237
|
+
logger.formatter = proc do |_severity, _datetime, _progname, msg|
|
|
238
|
+
Core::Color.colorize("#{msg}", color).concat("\n")
|
|
239
|
+
end
|
|
240
|
+
else
|
|
241
|
+
logger.formatter = proc do |_severity, _datetime, _progname, msg|
|
|
242
|
+
msg.concat("\n")
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
logger
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
# Construct a new logdev logger.
|
|
249
|
+
#
|
|
250
|
+
# @param filepath_or_logdev [String,IO] a filepath String or IO object
|
|
251
|
+
# @return [LogdevLogger] a new logger
|
|
252
|
+
# @api private
|
|
253
|
+
def logdev_logger(filepath_or_logdev)
|
|
254
|
+
Omnitest::Core::LogdevLogger.new(resolve_logdev(filepath_or_logdev))
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
# Return an IO object from a filepath String or the IO object itself.
|
|
258
|
+
#
|
|
259
|
+
# @param filepath_or_logdev [String,IO] a filepath String or IO object
|
|
260
|
+
# @return [IO] an IO object
|
|
261
|
+
# @api private
|
|
262
|
+
def resolve_logdev(filepath_or_logdev)
|
|
263
|
+
if filepath_or_logdev.is_a? String
|
|
264
|
+
FileUtils.mkdir_p(File.dirname(filepath_or_logdev))
|
|
265
|
+
file = File.open(File.expand_path(filepath_or_logdev), 'ab')
|
|
266
|
+
file.sync = true
|
|
267
|
+
file
|
|
268
|
+
else
|
|
269
|
+
filepath_or_logdev
|
|
270
|
+
end
|
|
271
|
+
end
|
|
272
|
+
end
|
|
273
|
+
end
|