dragnet 5.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/.github/workflows/release.yml +45 -0
- data/.github/workflows/ruby-linters.yml +41 -0
- data/.github/workflows/ruby-tests.yml +38 -0
- data/.github/workflows/sphinx-doc.yml +79 -0
- data/.gitignore +13 -0
- data/.reek.yml +15 -0
- data/.rspec +3 -0
- data/.rubocop.yml +14 -0
- data/.ruby-version +1 -0
- data/.travis.yml +6 -0
- data/CHANGELOG.md +178 -0
- data/Gemfile +18 -0
- data/README.md +119 -0
- data/Rakefile +8 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/default.reek +7 -0
- data/dragnet.gemspec +39 -0
- data/exe/dragnet +9 -0
- data/lib/dragnet/base_repository.rb +69 -0
- data/lib/dragnet/cli/base.rb +72 -0
- data/lib/dragnet/cli/logger.rb +72 -0
- data/lib/dragnet/cli/master.rb +173 -0
- data/lib/dragnet/cli.rb +8 -0
- data/lib/dragnet/errors/error.rb +8 -0
- data/lib/dragnet/errors/file_not_found_error.rb +11 -0
- data/lib/dragnet/errors/incompatible_repository_error.rb +10 -0
- data/lib/dragnet/errors/missing_timestamp_attribute_error.rb +11 -0
- data/lib/dragnet/errors/no_mtr_files_found_error.rb +11 -0
- data/lib/dragnet/errors/not_a_repository_error.rb +11 -0
- data/lib/dragnet/errors/repo_path_not_found_error.rb +10 -0
- data/lib/dragnet/errors/unable_to_write_report_error.rb +11 -0
- data/lib/dragnet/errors/unknown_export_format_error.rb +11 -0
- data/lib/dragnet/errors/validation_error.rb +11 -0
- data/lib/dragnet/errors/yaml_format_error.rb +9 -0
- data/lib/dragnet/errors.rb +9 -0
- data/lib/dragnet/explorer.rb +103 -0
- data/lib/dragnet/exporter.rb +130 -0
- data/lib/dragnet/exporters/exporter.rb +29 -0
- data/lib/dragnet/exporters/html_exporter.rb +158 -0
- data/lib/dragnet/exporters/id_generator.rb +35 -0
- data/lib/dragnet/exporters/json_exporter.rb +34 -0
- data/lib/dragnet/exporters/serializers/repo_serializer.rb +40 -0
- data/lib/dragnet/exporters/serializers/test_record_serializer.rb +101 -0
- data/lib/dragnet/exporters/serializers/verification_result_serializer.rb +34 -0
- data/lib/dragnet/exporters/serializers.rb +12 -0
- data/lib/dragnet/exporters/templates/template.html.erb +518 -0
- data/lib/dragnet/exporters.rb +13 -0
- data/lib/dragnet/helpers/repository_helper.rb +27 -0
- data/lib/dragnet/multi_repository.rb +48 -0
- data/lib/dragnet/repo.rb +31 -0
- data/lib/dragnet/repository.rb +77 -0
- data/lib/dragnet/test_record.rb +91 -0
- data/lib/dragnet/validator.rb +79 -0
- data/lib/dragnet/validators/data_validator.rb +75 -0
- data/lib/dragnet/validators/entities/repo_validator.rb +31 -0
- data/lib/dragnet/validators/entities/test_record_validator.rb +93 -0
- data/lib/dragnet/validators/entities.rb +12 -0
- data/lib/dragnet/validators/fields/description_validator.rb +24 -0
- data/lib/dragnet/validators/fields/field_validator.rb +69 -0
- data/lib/dragnet/validators/fields/files_validator.rb +29 -0
- data/lib/dragnet/validators/fields/id_validator.rb +36 -0
- data/lib/dragnet/validators/fields/meta_data_field_validator.rb +36 -0
- data/lib/dragnet/validators/fields/path_validator.rb +22 -0
- data/lib/dragnet/validators/fields/repos_validator.rb +62 -0
- data/lib/dragnet/validators/fields/result_validator.rb +33 -0
- data/lib/dragnet/validators/fields/sha1_validator.rb +42 -0
- data/lib/dragnet/validators/fields.rb +17 -0
- data/lib/dragnet/validators/files_validator.rb +85 -0
- data/lib/dragnet/validators/repos_validator.rb +74 -0
- data/lib/dragnet/validators/validator.rb +20 -0
- data/lib/dragnet/validators.rb +12 -0
- data/lib/dragnet/verification_result.rb +125 -0
- data/lib/dragnet/verifier.rb +64 -0
- data/lib/dragnet/verifiers/changes_verifier.rb +70 -0
- data/lib/dragnet/verifiers/files_verifier.rb +51 -0
- data/lib/dragnet/verifiers/repos_verifier.rb +92 -0
- data/lib/dragnet/verifiers/repository_verifier.rb +27 -0
- data/lib/dragnet/verifiers/result_verifier.rb +32 -0
- data/lib/dragnet/verifiers/test_record_verifier.rb +85 -0
- data/lib/dragnet/verifiers/verifier.rb +37 -0
- data/lib/dragnet/verifiers.rb +8 -0
- data/lib/dragnet/version.rb +5 -0
- data/lib/dragnet.rb +18 -0
- metadata +190 -0
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../repo'
|
4
|
+
require_relative 'field_validator'
|
5
|
+
|
6
|
+
module Dragnet
|
7
|
+
module Validators
|
8
|
+
module Fields
|
9
|
+
# Validates that the +repos+ attribute in an MTR is valid. This means:
|
10
|
+
# * It is either a +Hash+ or an +Array+ of +Hash+es.
|
11
|
+
# * The attributes inside each of the +Hash+es are also valid.
|
12
|
+
class ReposValidator < Dragnet::Validators::Fields::FieldValidator
|
13
|
+
# Validates the MTR's +repos+ field.
|
14
|
+
# @param [String] key The name of the key (usually +'repos'+)
|
15
|
+
# @param [Object] value The value associated to the attribute.
|
16
|
+
# @return [Array<Dragnet::Repo>, nil] If +value+ is a valid +Hash+ or a
|
17
|
+
# valid +Array+ of +Hash+es an +Array+ of +Dragnet::Repo+ objects is
|
18
|
+
# returned. If +value+ is +nil+, +nil+ is returned.
|
19
|
+
# @raise [Dragnet::Errors::ValidationError] If +value+ is not a +Hash+
|
20
|
+
# or an +Array+ of +Hash+es or the attributes inside the +Hash+es are
|
21
|
+
# invalid.
|
22
|
+
# @see Dragnet::Repo#validate
|
23
|
+
def validate(key, value)
|
24
|
+
return unless value
|
25
|
+
|
26
|
+
validate_type(key, value, Hash, Array)
|
27
|
+
|
28
|
+
if value.is_a?(Array)
|
29
|
+
return if value.empty?
|
30
|
+
|
31
|
+
validate_array_types(key, value, Hash)
|
32
|
+
else
|
33
|
+
# This is needed because trying to apply the splat operator over a
|
34
|
+
# Hash will result in an Array of Arrays (one for each of the Hash's
|
35
|
+
# key pairs).
|
36
|
+
value = [value]
|
37
|
+
end
|
38
|
+
|
39
|
+
create_repos(value)
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
# @param [Array<Hash>] hashes The array of +Hash+es from which the Repo
|
45
|
+
# objects shall be created.
|
46
|
+
# @return [Array<Dragnet::Repo>] The array of +Dragnet::Repo+ objects
|
47
|
+
# that result from using each of the given +Hash+es as parameters for
|
48
|
+
# the constructor.
|
49
|
+
# @raise [Dragnet::Errors::ValidationError] If the attributes inside the
|
50
|
+
# +Hash+es are invalid.
|
51
|
+
# @see Dragnet::Repo#validate
|
52
|
+
def create_repos(hashes)
|
53
|
+
hashes.map do |hash|
|
54
|
+
repo = Dragnet::Repo.new(**hash)
|
55
|
+
repo.validate
|
56
|
+
repo
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'field_validator'
|
4
|
+
|
5
|
+
module Dragnet
|
6
|
+
module Validators
|
7
|
+
module Fields
|
8
|
+
# Validates the result field of an MTR Record
|
9
|
+
class ResultValidator < Dragnet::Validators::Fields::FieldValidator
|
10
|
+
VALID_RESULTS = %w[passed failed].freeze
|
11
|
+
|
12
|
+
# Validates the MTR's result
|
13
|
+
# @param [String] key The name of the key
|
14
|
+
# @param [Object] value The value of the key
|
15
|
+
# @return [String] The downcase version of the result field.
|
16
|
+
# @raise [Dragnet::Errors::ValidationError] If the result is missing, if
|
17
|
+
# it isn't a String or is not one of the allowed values for the field.
|
18
|
+
def validate(key, value)
|
19
|
+
validate_presence(key, value)
|
20
|
+
validate_type(key, value, String)
|
21
|
+
|
22
|
+
value = value.downcase
|
23
|
+
return value if VALID_RESULTS.include?(value)
|
24
|
+
|
25
|
+
validation_error(
|
26
|
+
"Invalid value for key result: '#{value}'. "\
|
27
|
+
"Valid values are #{VALID_RESULTS.join(', ')}"
|
28
|
+
)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'field_validator'
|
4
|
+
|
5
|
+
module Dragnet
|
6
|
+
module Validators
|
7
|
+
module Fields
|
8
|
+
# Validates the SHA1 field of a Manual Test Record
|
9
|
+
class SHA1Validator < Dragnet::Validators::Fields::FieldValidator
|
10
|
+
SHA1_MIN_LENGTH = 7
|
11
|
+
SHA1_MAX_LENGTH = 40
|
12
|
+
SHA1_REGEX = /\A[0-9a-f]+\Z/.freeze
|
13
|
+
|
14
|
+
# Validates the SHA1 of the MTR
|
15
|
+
# @param [String] key The name of the key
|
16
|
+
# @param [Object] value The value of the key
|
17
|
+
# @raise [Dragnet::Errors::ValidationError] If the SHA1 is missing, is not
|
18
|
+
# and string, is too short or too long or is not a valid hexadecimal
|
19
|
+
# string.
|
20
|
+
def validate(key, value)
|
21
|
+
validate_presence(key, value)
|
22
|
+
validate_type(key, value, String)
|
23
|
+
|
24
|
+
length = value.length
|
25
|
+
unless length >= SHA1_MIN_LENGTH && length <= SHA1_MAX_LENGTH
|
26
|
+
validation_error(
|
27
|
+
"Invalid value for key #{key}: '#{value}'. Expected a string between "\
|
28
|
+
"#{SHA1_MIN_LENGTH} and #{SHA1_MAX_LENGTH} characters"
|
29
|
+
)
|
30
|
+
end
|
31
|
+
|
32
|
+
return if value.match(SHA1_REGEX)
|
33
|
+
|
34
|
+
validation_error(
|
35
|
+
"Invalid value for key #{key}: '#{value}'. "\
|
36
|
+
"Doesn't seem to be a valid hexadecimal string"
|
37
|
+
)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'fields/description_validator'
|
4
|
+
require_relative 'fields/files_validator'
|
5
|
+
require_relative 'fields/id_validator'
|
6
|
+
require_relative 'fields/meta_data_field_validator'
|
7
|
+
require_relative 'fields/path_validator'
|
8
|
+
require_relative 'fields/repos_validator'
|
9
|
+
require_relative 'fields/result_validator'
|
10
|
+
require_relative 'fields/sha1_validator'
|
11
|
+
|
12
|
+
module Dragnet
|
13
|
+
module Validators
|
14
|
+
# Namespace module for entity fields validators.
|
15
|
+
module Fields; end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../errors/file_not_found_error'
|
4
|
+
require_relative 'validator'
|
5
|
+
|
6
|
+
module Dragnet
|
7
|
+
module Validators
|
8
|
+
# Validates the +files+ key in the given Manual Test Record object.
|
9
|
+
# Validates:
|
10
|
+
# - That the listed file(s) glob pattern(s) match at least one file in the
|
11
|
+
# repository.
|
12
|
+
class FilesValidator < Dragnet::Validators::Validator
|
13
|
+
attr_reader :test_record, :path
|
14
|
+
|
15
|
+
# Creates a new instance of the class.
|
16
|
+
# @param [Dragnet::TestRecord] test_record The +TestRecord+ object whose
|
17
|
+
# files should be validated.
|
18
|
+
# @param [Pathname] path The path to the repository where the files are
|
19
|
+
# supposed to be located.
|
20
|
+
def initialize(test_record, path)
|
21
|
+
@test_record = test_record
|
22
|
+
@files = test_record.files
|
23
|
+
@path = path
|
24
|
+
end
|
25
|
+
|
26
|
+
# Validates the +files+ key in the given data.
|
27
|
+
# Updates the +file+ key in the given +data+ to the actual files found in
|
28
|
+
# the repository.
|
29
|
+
# @raise [Dragnet::Errors::FileNotFoundError] If any of the listed files
|
30
|
+
# cannot be found in the given repository path or if a glob pattern
|
31
|
+
# doesn't match any files there.
|
32
|
+
def validate
|
33
|
+
return unless files
|
34
|
+
|
35
|
+
test_record.files = translate_paths && force_relative_paths && resolve_files
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
attr_reader :files
|
41
|
+
|
42
|
+
# Forces all the file paths to be relative by removing the +/+ at the
|
43
|
+
# start (if they have one). This is done to ensure that files are always
|
44
|
+
# considered relative to the path being checked.
|
45
|
+
def force_relative_paths
|
46
|
+
@files = files.map do |file|
|
47
|
+
file.sub(%r{^/}, '')
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Translate the file paths from windows style paths (with \ as path
|
52
|
+
# separator) to Unix style paths (with / as path separator).
|
53
|
+
# This is done so that the git commands work in all systems.
|
54
|
+
def translate_paths
|
55
|
+
@files = files.map do |file|
|
56
|
+
file.tr('\\', '/')
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Resolve the given files by checking for matches in the given repository.
|
61
|
+
# Glob patterns are resolved an translated into individual files.
|
62
|
+
# @return [Array<Pathname>] The resolved file paths.
|
63
|
+
# @raise [Dragnet::Errors::FileNotFoundError] If any of the listed files
|
64
|
+
# cannot be found in the given repository path or if a glob pattern
|
65
|
+
# doesn't match any files there.
|
66
|
+
def resolve_files
|
67
|
+
resolved_files = []
|
68
|
+
|
69
|
+
files.each do |file|
|
70
|
+
# Files can be defined as glob patterns
|
71
|
+
matched_files = path.glob(file)
|
72
|
+
|
73
|
+
if matched_files.empty?
|
74
|
+
raise Dragnet::Errors::FileNotFoundError,
|
75
|
+
"Could not find any files matching #{file} in #{path}"
|
76
|
+
end
|
77
|
+
|
78
|
+
resolved_files += matched_files
|
79
|
+
end
|
80
|
+
|
81
|
+
resolved_files
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../errors/repo_path_not_found_error'
|
4
|
+
require_relative 'files_validator'
|
5
|
+
|
6
|
+
module Dragnet
|
7
|
+
module Validators
|
8
|
+
# Validates the +Repo+ objects attached to the given +TestRecord+
|
9
|
+
class ReposValidator < Dragnet::Validators::Validator
|
10
|
+
attr_reader :test_record, :repos, :path
|
11
|
+
|
12
|
+
# @param [Dragnet::TestRecord] test_record The Test Record to validate.
|
13
|
+
# @param [Pathname] path The path where the repositories are supposed to
|
14
|
+
# be located.
|
15
|
+
def initialize(test_record, path)
|
16
|
+
@test_record = test_record
|
17
|
+
@path = path
|
18
|
+
@repos = test_record.repos
|
19
|
+
end
|
20
|
+
|
21
|
+
# Validates the +Repo+ objects inside the given +TestCase+
|
22
|
+
def validate
|
23
|
+
return unless repos
|
24
|
+
|
25
|
+
validate_paths
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
# Validates the +paths+ of the +Repo+ objects (makes sure the paths
|
31
|
+
# exist). Knowing that these paths exist, the +files+ attribute of the
|
32
|
+
# +Repo+ object can be validated as well.
|
33
|
+
# @raise [Dragnet::Errors::RepoPathNotFoundError] If one or more of the
|
34
|
+
# paths cannot be found.
|
35
|
+
# @raise [Dragnet::Errors::FileNotFoundError] If any of the files listed
|
36
|
+
# in the +files+ attribute do not exist inside the given +path+.
|
37
|
+
def validate_paths
|
38
|
+
repos.each do |repo|
|
39
|
+
repo_path = repo.path = repo.path.gsub('\\', '/')
|
40
|
+
repo_path = Pathname.new(repo_path)
|
41
|
+
|
42
|
+
complete_path = repo_path.absolute? ? repo_path : path / repo_path
|
43
|
+
|
44
|
+
if complete_path.exist?
|
45
|
+
validate_files(repo, complete_path)
|
46
|
+
next
|
47
|
+
end
|
48
|
+
|
49
|
+
repo_path_not_found(repo_path)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Validates the existence of the files listed in the +files+ attributes
|
54
|
+
# inside the +Repo+ object inside the +Repo+'s +path+.
|
55
|
+
# @param [Dragnet::Repo] repo The +Repo+ whose files should be validated.
|
56
|
+
# @param [Pathname] complete_path The path to the repository.
|
57
|
+
def validate_files(repo, complete_path)
|
58
|
+
return unless repo.files
|
59
|
+
|
60
|
+
Dragnet::Validators::FilesValidator.new(repo, complete_path).validate
|
61
|
+
end
|
62
|
+
|
63
|
+
# Raises a Dragnet::Errors::RepoPathNotFoundError with the appropriate
|
64
|
+
# message (which depends on whether the path is absolute or relative).
|
65
|
+
# @param [Pathname] repo_path The path that couldn't be found.
|
66
|
+
# @raise [Dragnet::Errors::RepoPathNotFoundError] is always raised.
|
67
|
+
def repo_path_not_found(repo_path)
|
68
|
+
message = "Cannot find the repository path #{repo_path}"
|
69
|
+
message += " inside #{path}" if repo_path.relative?
|
70
|
+
raise Dragnet::Errors::RepoPathNotFoundError, message
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../errors/yaml_format_error'
|
4
|
+
|
5
|
+
module Dragnet
|
6
|
+
module Validators
|
7
|
+
# Base class for all validators.
|
8
|
+
class Validator
|
9
|
+
private
|
10
|
+
|
11
|
+
# Raises a +Dragnet::Errors::YAMLFormatError+ with the given message.
|
12
|
+
# @param [String] message The message for the exception.
|
13
|
+
# @raise [Dragnet::Errors::YAMLFormatError] Is always raised with the
|
14
|
+
# given message.
|
15
|
+
def yaml_format_error(message)
|
16
|
+
raise Dragnet::Errors::YAMLFormatError, message
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'validators/data_validator'
|
4
|
+
require_relative 'validators/entities'
|
5
|
+
require_relative 'validators/fields'
|
6
|
+
require_relative 'validators/files_validator'
|
7
|
+
require_relative 'validators/validator'
|
8
|
+
|
9
|
+
module Dragnet
|
10
|
+
# Namespace for Validator classes.
|
11
|
+
module Validators; end
|
12
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'colorize'
|
4
|
+
|
5
|
+
require_relative 'errors/missing_timestamp_attribute_error'
|
6
|
+
|
7
|
+
module Dragnet
|
8
|
+
# Holds the verification result of a Manual Test Record
|
9
|
+
class VerificationResult
|
10
|
+
VALID_STATUSES = %i[passed skipped failed].freeze
|
11
|
+
|
12
|
+
attr_reader :status, :reason, :started_at, :finished_at
|
13
|
+
|
14
|
+
# Creates a new instance of the class.
|
15
|
+
# @param [Symbol] status The status
|
16
|
+
# @param [String] reason
|
17
|
+
def initialize(status:, reason: nil)
|
18
|
+
self.status = status
|
19
|
+
@reason = reason
|
20
|
+
end
|
21
|
+
|
22
|
+
def passed?
|
23
|
+
status == :passed
|
24
|
+
end
|
25
|
+
|
26
|
+
def skipped?
|
27
|
+
status == :skipped
|
28
|
+
end
|
29
|
+
|
30
|
+
def failed?
|
31
|
+
status == :failed
|
32
|
+
end
|
33
|
+
|
34
|
+
# Assigns the given status
|
35
|
+
# @param [Symbol] status The status
|
36
|
+
# @raise [ArgumentError] If the given status is not one of the accepted
|
37
|
+
# valid statuses.
|
38
|
+
def status=(status)
|
39
|
+
unless VALID_STATUSES.include?(status)
|
40
|
+
raise ArgumentError, "Invalid status #{status}."\
|
41
|
+
" Valid statuses are: #{VALID_STATUSES.join(', ')}"
|
42
|
+
end
|
43
|
+
|
44
|
+
@status = status
|
45
|
+
end
|
46
|
+
|
47
|
+
# Sets the verification's start time.
|
48
|
+
# @param [Time] time The verification's start time.
|
49
|
+
# @raise [ArgumentError] If the given +time+ is not an instance of +Time+.
|
50
|
+
# @raise [ArgumentError] If +finished_at+ is set and the given +time+ is
|
51
|
+
# bigger than or equal to it.
|
52
|
+
def started_at=(time)
|
53
|
+
validate_time(time)
|
54
|
+
raise ArgumentError, 'started_at must be smaller than finished_at' if finished_at && time >= finished_at
|
55
|
+
|
56
|
+
@runtime = nil
|
57
|
+
@started_at = time
|
58
|
+
end
|
59
|
+
|
60
|
+
# Sets the verification's finish time
|
61
|
+
# @param [Time] time The verification's finish time.
|
62
|
+
# @raise [TypeError] Is an attempt is made to set +finished_at+ before
|
63
|
+
# setting +started_at+.
|
64
|
+
# @raise [ArgumentError] If the given +time+ is not an instance of +Time+.
|
65
|
+
# @raise [ArgumentError] If +started_at+ is set and the given +time+ is
|
66
|
+
# smaller than or equal to it.
|
67
|
+
def finished_at=(time)
|
68
|
+
validate_time(time)
|
69
|
+
raise ArgumentError, 'finished_at must be greater than started_at' if started_at && time <= started_at
|
70
|
+
|
71
|
+
@runtime = nil
|
72
|
+
@finished_at = time
|
73
|
+
end
|
74
|
+
|
75
|
+
# @return [Float, nil] The runtime calculated from the started_at and
|
76
|
+
# finished_at attributes, if any of them is missing +nil+ is returned
|
77
|
+
# instead.
|
78
|
+
def runtime
|
79
|
+
runtime!
|
80
|
+
rescue Dragnet::Errors::MissingTimestampAttributeError
|
81
|
+
nil
|
82
|
+
end
|
83
|
+
|
84
|
+
# @return [Float] The runtime calculated from the started_at and finished_at
|
85
|
+
# timestamp attributes.
|
86
|
+
# @raise [TypeError] If either of these attributes is +nil+
|
87
|
+
def runtime!
|
88
|
+
@runtime ||= calculate_runtime
|
89
|
+
end
|
90
|
+
|
91
|
+
# @return [String] A string representation of the receiver that can be used
|
92
|
+
# to log the result of a verification.
|
93
|
+
def log_message
|
94
|
+
if passed?
|
95
|
+
'✔ PASSED '.colorize(:light_green)
|
96
|
+
elsif skipped?
|
97
|
+
"#{'⚠ SKIPPED'.colorize(:light_yellow)} #{reason}"
|
98
|
+
else
|
99
|
+
"#{'✘ FAILED '.colorize(:light_red)} #{reason || 'Unknown reason'}"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
# Checks if the given object is a +Time+ and raises an +ArgumentError+ if it
|
106
|
+
# isn't.
|
107
|
+
# @param [Object] time The object to check.
|
108
|
+
# @raise [ArgumentError] If the given object is not a +Time+ object.
|
109
|
+
def validate_time(time)
|
110
|
+
raise ArgumentError, "Expected a Time object, got #{time.class}" unless time.is_a?(Time)
|
111
|
+
end
|
112
|
+
|
113
|
+
# @return [Float] The runtime calculated from the started_at and finished_at
|
114
|
+
# timestamp attributes.
|
115
|
+
# @raise [TypeError] If either of these attributes is +nil+
|
116
|
+
def calculate_runtime
|
117
|
+
if started_at.nil? || finished_at.nil?
|
118
|
+
raise Dragnet::Errors::MissingTimestampAttributeError,
|
119
|
+
'Both started_at and finished_at must be set in order to calculate the runtime'
|
120
|
+
end
|
121
|
+
|
122
|
+
finished_at - started_at
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'git'
|
4
|
+
|
5
|
+
require_relative 'verifiers/test_record_verifier'
|
6
|
+
|
7
|
+
module Dragnet
|
8
|
+
# Executes the verification process on the given Test Records
|
9
|
+
class Verifier
|
10
|
+
attr_reader :test_records, :path, :logger
|
11
|
+
|
12
|
+
# Creates a new instance of the class.
|
13
|
+
# @param [Array<Hash>] test_records An array with the test records.
|
14
|
+
# @param [Dragnet::Repository] repository The repository where the MTR and
|
15
|
+
# the source files are stored.
|
16
|
+
# @param [#info] logger The logger object to use for output.
|
17
|
+
def initialize(test_records:, repository:, logger:)
|
18
|
+
@test_records = test_records
|
19
|
+
@repository = repository
|
20
|
+
@logger = logger
|
21
|
+
end
|
22
|
+
|
23
|
+
# Runs the verify process
|
24
|
+
# After the execution of this method each Test Record will get a +:result+
|
25
|
+
# key with the result of the verification process. This key contains a hash
|
26
|
+
# like the following:
|
27
|
+
#
|
28
|
+
# result: {
|
29
|
+
# status: :passed, # Either :passed, :failed or :skipped
|
30
|
+
# reason: 'String' # The reason for the failure (for :failed and :skipped)
|
31
|
+
# }
|
32
|
+
def verify
|
33
|
+
logger.info 'Verifying MTR files...'
|
34
|
+
test_records.each do |test_record|
|
35
|
+
logger.info "Verifying #{test_record.source_file}"
|
36
|
+
verify_mtr(test_record)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
attr_reader :repository
|
43
|
+
|
44
|
+
# Verifies the given Manual Test Record
|
45
|
+
# Runs the given test record through all the verifiers. If no verifier adds
|
46
|
+
# a +result+ key to the Test Record then the method adds one with passed
|
47
|
+
# status.
|
48
|
+
# @param [Dragnet::TestRecord] test_record The Test Record to verify.
|
49
|
+
def verify_mtr(test_record)
|
50
|
+
started_at = Time.now.utc
|
51
|
+
|
52
|
+
verification_result = Dragnet::Verifiers::TestRecordVerifier.new(
|
53
|
+
test_record: test_record, repository: repository, test_records: test_records
|
54
|
+
).verify
|
55
|
+
|
56
|
+
finished_at = Time.now.utc
|
57
|
+
verification_result.started_at = started_at
|
58
|
+
verification_result.finished_at = finished_at
|
59
|
+
test_record.verification_result = verification_result
|
60
|
+
|
61
|
+
logger.info(verification_result.log_message)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../verification_result'
|
4
|
+
require_relative 'repository_verifier'
|
5
|
+
|
6
|
+
module Dragnet
|
7
|
+
module Verifiers
|
8
|
+
# Checks for changes in the repository since the creation of the MTR Record
|
9
|
+
class ChangesVerifier < Dragnet::Verifiers::RepositoryVerifier
|
10
|
+
attr_reader :test_records
|
11
|
+
|
12
|
+
# @param [Dragnet::TestRecord] test_record The +TestRecord+ object to
|
13
|
+
# verify.
|
14
|
+
# @param [Dragnet::Repository] repository A +Dragnet::Repository+ object
|
15
|
+
# linked to the repository where the verification should be executed.
|
16
|
+
# @param [Array<Hash>] test_records The hash of all the test records. This
|
17
|
+
# is used to determine if the changes in the repository are only in the
|
18
|
+
# Test Record Files, in which case the Test Records will still be
|
19
|
+
# considered valid.
|
20
|
+
def initialize(test_record:, repository:, test_records:)
|
21
|
+
super(test_record: test_record, repository: repository)
|
22
|
+
@test_records = test_records
|
23
|
+
end
|
24
|
+
|
25
|
+
# Runs the verification process. Checks the changes on the repository
|
26
|
+
# between the Commit with the SHA1 registered in the MTR and the current
|
27
|
+
# HEAD.
|
28
|
+
# @return [Dragnet::VerificationResult, nil] A +VerificationResult+ with
|
29
|
+
# the details of the changes found in the repository or +nil+ if no
|
30
|
+
# changes were found.
|
31
|
+
def verify
|
32
|
+
diff = repository.diff(sha1, 'HEAD')
|
33
|
+
return unless diff.size.positive?
|
34
|
+
|
35
|
+
find_changes(diff)
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
# Scans the given diff for changes. If changes are detected then a
|
41
|
+
# +:result+ key will be added to the +test_record+. Changes to the MTR
|
42
|
+
# files themselves are ignored.
|
43
|
+
# @return [Dragnet::VerificationResult, nil] A +VerificationResult+ with
|
44
|
+
# the details of the changes found in the repository, or +nil+ if no
|
45
|
+
# changes were found.
|
46
|
+
def find_changes(diff)
|
47
|
+
diff.stats[:files].each do |file, _changes|
|
48
|
+
next if mtr_files.include?(file) # Changes to MTR files are ignored.
|
49
|
+
|
50
|
+
return Dragnet::VerificationResult.new(
|
51
|
+
status: :skipped,
|
52
|
+
reason: "Changes detected in the repository: #{shorten_sha1(sha1)}..#{shorten_sha1(repository.head.sha)}"\
|
53
|
+
" # -- #{file}"
|
54
|
+
)
|
55
|
+
end
|
56
|
+
|
57
|
+
nil
|
58
|
+
end
|
59
|
+
|
60
|
+
# @return [Array<Strings>] An array of strings with the paths to all the
|
61
|
+
# known MTR files. These will be excluded when checking from changes in
|
62
|
+
# the repository.
|
63
|
+
def mtr_files
|
64
|
+
@mtr_files ||= test_records.map do |test_record|
|
65
|
+
test_record.source_file.relative_path_from(path).to_s
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../verification_result'
|
4
|
+
require_relative 'repository_verifier'
|
5
|
+
|
6
|
+
module Dragnet
|
7
|
+
module Verifiers
|
8
|
+
# Checks if any of the files listed in the MTR have changed since the MTR
|
9
|
+
# was created.
|
10
|
+
class FilesVerifier < Dragnet::Verifiers::RepositoryVerifier
|
11
|
+
# Executes the verification process.
|
12
|
+
# Checks the changes in the repository. If a change in one of the files
|
13
|
+
# is detected a +:result+ key is added to the MTR, including the detected
|
14
|
+
# change.
|
15
|
+
# @return [Dragnet::VerificationResult, nil] A +VerificationResult+ object
|
16
|
+
# with the detected changes to the listed files or +nil+ if no changes
|
17
|
+
# are found.
|
18
|
+
def verify
|
19
|
+
changes = []
|
20
|
+
|
21
|
+
files.each do |file|
|
22
|
+
diff = repository.diff(sha1, 'HEAD').path(file.to_s)
|
23
|
+
next unless diff.size.positive?
|
24
|
+
|
25
|
+
changes << file
|
26
|
+
end
|
27
|
+
|
28
|
+
result_from(changes) if changes.any?
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
# @return [Array<String>] The paths to the files listed in the MTR file.
|
34
|
+
def files
|
35
|
+
@files ||= test_record.files.map do |file|
|
36
|
+
file.relative_path_from(path)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Stores the detected changes on the Test Record
|
41
|
+
# @param [Array<String>] changes The array of changed files.
|
42
|
+
def result_from(changes)
|
43
|
+
Dragnet::VerificationResult.new(
|
44
|
+
status: :skipped,
|
45
|
+
reason: "Changes detected in listed file(s): #{shorten_sha1(sha1)}..#{shorten_sha1(repository.head.sha)}"\
|
46
|
+
" -- #{changes.join(' ')}"
|
47
|
+
)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|