simmer 1.0.0.pre.alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. checksums.yaml +7 -0
  2. data/.editorconfig +8 -0
  3. data/.gitignore +7 -0
  4. data/.rubocop.yml +25 -0
  5. data/.ruby-version +1 -0
  6. data/.travis.yml +25 -0
  7. data/CHANGELOG.md +1 -0
  8. data/CODE_OF_CONDUCT.md +74 -0
  9. data/Gemfile +5 -0
  10. data/Guardfile +16 -0
  11. data/LICENSE +7 -0
  12. data/README.md +5 -0
  13. data/Rakefile +17 -0
  14. data/bin/console +18 -0
  15. data/bin/simmer +11 -0
  16. data/lib/simmer.rb +50 -0
  17. data/lib/simmer/configuration.rb +90 -0
  18. data/lib/simmer/core_ext/hash.rb +21 -0
  19. data/lib/simmer/externals.rb +12 -0
  20. data/lib/simmer/externals/aws_file_system.rb +81 -0
  21. data/lib/simmer/externals/mysql_database.rb +114 -0
  22. data/lib/simmer/externals/mysql_database/sql_fixture.rb +43 -0
  23. data/lib/simmer/externals/spoon_client.rb +77 -0
  24. data/lib/simmer/externals/spoon_client/mock.rb +39 -0
  25. data/lib/simmer/externals/spoon_client/result.rb +48 -0
  26. data/lib/simmer/judge.rb +38 -0
  27. data/lib/simmer/judge/result.rb +34 -0
  28. data/lib/simmer/runner.rb +125 -0
  29. data/lib/simmer/runner/result.rb +52 -0
  30. data/lib/simmer/session.rb +79 -0
  31. data/lib/simmer/session/reporter.rb +100 -0
  32. data/lib/simmer/session/result.rb +45 -0
  33. data/lib/simmer/specification.rb +34 -0
  34. data/lib/simmer/specification/act.rb +48 -0
  35. data/lib/simmer/specification/act/params.rb +55 -0
  36. data/lib/simmer/specification/assert.rb +27 -0
  37. data/lib/simmer/specification/assert/assertions.rb +27 -0
  38. data/lib/simmer/specification/assert/assertions/bad_output_assertion.rb +34 -0
  39. data/lib/simmer/specification/assert/assertions/bad_table_assertion.rb +38 -0
  40. data/lib/simmer/specification/assert/assertions/output.rb +37 -0
  41. data/lib/simmer/specification/assert/assertions/table.rb +47 -0
  42. data/lib/simmer/specification/stage.rb +28 -0
  43. data/lib/simmer/specification/stage/input_file.rb +33 -0
  44. data/lib/simmer/suite.rb +73 -0
  45. data/lib/simmer/util.rb +13 -0
  46. data/lib/simmer/util/evaluator.rb +32 -0
  47. data/lib/simmer/util/fixture.rb +32 -0
  48. data/lib/simmer/util/fixture_set.rb +41 -0
  49. data/lib/simmer/util/record.rb +54 -0
  50. data/lib/simmer/util/record_set.rb +51 -0
  51. data/lib/simmer/util/resolver.rb +28 -0
  52. data/lib/simmer/util/yaml_reader.rb +61 -0
  53. data/lib/simmer/version.rb +12 -0
  54. data/simmer.gemspec +38 -0
  55. data/spec/simmer/core_ext/hash_spec.rb +16 -0
  56. data/spec/spec_helper.rb +22 -0
  57. metadata +284 -0
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2020-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ module Simmer
11
+ class Runner
12
+ # Return object from a Runner#run call.
13
+ class Result
14
+ extend Forwardable
15
+
16
+ attr_reader :id, :judge_result, :specification, :spoon_client_result
17
+
18
+ def_delegators :spoon_client_result, :time_in_seconds
19
+
20
+ def_delegators :specification, :name
21
+
22
+ def initialize(id, judge_result, specification, spoon_client_result)
23
+ @id = id.to_s
24
+ @judge_result = judge_result
25
+ @specification = specification
26
+ @spoon_client_result = spoon_client_result
27
+
28
+ freeze
29
+ end
30
+
31
+ def pass?
32
+ judge_result&.pass? && spoon_client_result&.pass?
33
+ end
34
+
35
+ def fail?
36
+ !pass?
37
+ end
38
+
39
+ def to_h
40
+ {
41
+ 'name' => specification.name,
42
+ 'id' => id,
43
+ 'path' => specification.path,
44
+ 'time_in_seconds' => time_in_seconds,
45
+ 'pass' => pass?,
46
+ 'spoon_client_result' => spoon_client_result.to_h,
47
+ 'judge_result' => judge_result.to_h
48
+ }
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2020-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ require_relative 'session/reporter'
11
+ require_relative 'session/result'
12
+
13
+ module Simmer
14
+ # Runs a collection of specifications and then writes down the results to disk.
15
+ class Session
16
+ def initialize(
17
+ config:,
18
+ out:,
19
+ resolver: Objectable.resolver,
20
+ results_dir:,
21
+ runner:
22
+ )
23
+ @config = config || {}
24
+ @out = out
25
+ @resolver = resolver
26
+ @results_dir = results_dir
27
+ @runner = runner
28
+
29
+ freeze
30
+ end
31
+
32
+ def run(specifications)
33
+ runner_results = run_all_specs(specifications)
34
+
35
+ Result.new(runner_results).tap do |result|
36
+ if result.pass?
37
+ out.puts('Suite ended successfully')
38
+ else
39
+ out.puts('Suite ended but was not successful')
40
+ end
41
+
42
+ Reporter.new(result).write!(results_dir)
43
+
44
+ out.puts("Results can be viewed at #{results_dir}")
45
+ end
46
+ end
47
+
48
+ private
49
+
50
+ attr_reader :config, :out, :results_dir, :resolver, :runner
51
+
52
+ def run_all_specs(specifications)
53
+ out.puts('Simmer suite started')
54
+
55
+ count = specifications.length
56
+
57
+ out.puts("Running #{count} specification(s)")
58
+ print_line
59
+
60
+ specifications.map.with_index(1) do |specification, index|
61
+ run_single_spec(specification, index, count)
62
+ end
63
+ end
64
+
65
+ def run_single_spec(specification, index, count)
66
+ id = SecureRandom.uuid
67
+
68
+ out.puts("Test #{index} of #{count}: #{id}")
69
+
70
+ runner.run(specification, id: id, config: config).tap do
71
+ print_line
72
+ end
73
+ end
74
+
75
+ def print_line
76
+ out.puts('-' * 60)
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2020-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ module Simmer
11
+ class Session
12
+ # Understands how to write a SessionResult instance to disk.
13
+ class Reporter
14
+ DATA_FILE = 'data.yaml'
15
+ PDI_OUT_FILE = 'pdi_out.txt'
16
+ PDI_ERR_FILE = 'pdi_err.txt'
17
+
18
+ def initialize(session_result)
19
+ raise ArgumentError, 'session_result is required' unless session_result
20
+
21
+ @session_result = session_result
22
+
23
+ freeze
24
+ end
25
+
26
+ def write!(dir)
27
+ dir = setup_directory(dir)
28
+
29
+ IO.write(data_path(dir), session_result.to_h.to_yaml)
30
+
31
+ pdi_out_file = File.open(pdi_out_path(dir), 'w')
32
+ pdi_err_file = File.open(pdi_err_path(dir), 'w')
33
+
34
+ write_part(session_result.runner_results, pdi_out_file, pdi_err_file)
35
+
36
+ pdi_out_file.close
37
+ pdi_err_file.close
38
+
39
+ self
40
+ end
41
+
42
+ def to_h
43
+ {
44
+ 'pass' => pass?,
45
+ 'time_in_seconds' => time_in_seconds,
46
+ 'runner_results' => runner_results.map(&:to_h)
47
+ }
48
+ end
49
+
50
+ private
51
+
52
+ attr_reader :session_result
53
+
54
+ def data_path(dir)
55
+ File.join(dir, DATA_FILE)
56
+ end
57
+
58
+ def pdi_out_path(dir)
59
+ File.join(dir, PDI_OUT_FILE)
60
+ end
61
+
62
+ def pdi_err_path(dir)
63
+ File.join(dir, PDI_ERR_FILE)
64
+ end
65
+
66
+ def setup_directory(dir)
67
+ File.expand_path(dir).tap do |expanded_dir|
68
+ FileUtils.mkdir_p(expanded_dir)
69
+ end
70
+ end
71
+
72
+ def write_part(runner_results, pdi_out_file, pdi_err_file)
73
+ runner_results.each do |runner_result|
74
+ name = runner_result.name
75
+ runner_id = runner_result.id
76
+ out_contents = runner_result.spoon_client_result.execution_result.out
77
+ err_contents = runner_result.spoon_client_result.execution_result.err
78
+
79
+ write_block(pdi_out_file, name, runner_id, out_contents)
80
+ write_block(pdi_err_file, name, runner_id, err_contents)
81
+ end
82
+
83
+ nil
84
+ end
85
+
86
+ def write_block(file, name, runner_id, contents)
87
+ hyphens = '-' * 80
88
+
89
+ file.write("#{hyphens}\n")
90
+ file.write("Name: #{name}\n")
91
+ file.write("Runner ID: #{runner_id}\n")
92
+ file.write("#{hyphens}\n")
93
+ file.write("#{contents}\n")
94
+ file.write("\n")
95
+
96
+ nil
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2020-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ module Simmer
11
+ class Session
12
+ # The return object for a Session#run call.
13
+ class Result
14
+ attr_reader :runner_results
15
+
16
+ def initialize(runner_results = [])
17
+ @runner_results = Array(runner_results)
18
+
19
+ freeze
20
+ end
21
+
22
+ def pass?
23
+ !fail?
24
+ end
25
+
26
+ def fail?
27
+ runner_results.any?(&:fail?)
28
+ end
29
+
30
+ def time_in_seconds
31
+ runner_results.inject(0.0) do |memo, runner_result|
32
+ memo + runner_result.time_in_seconds
33
+ end
34
+ end
35
+
36
+ def to_h
37
+ {
38
+ 'pass' => pass?,
39
+ 'time_in_seconds' => time_in_seconds,
40
+ 'runner_results' => runner_results.map(&:to_h)
41
+ }
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2020-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ require_relative 'specification/act'
11
+ require_relative 'specification/assert'
12
+ require_relative 'specification/stage'
13
+
14
+ module Simmer
15
+ # Describes a specification at the highest of levels.
16
+ class Specification
17
+ acts_as_hashable
18
+
19
+ attr_reader :act, :assert, :name, :path, :stage
20
+
21
+ def initialize(act: {}, assert: {}, name:, path:, stage: {})
22
+ raise ArgumentError, 'name is required' if name.to_s.empty?
23
+ raise ArgumentError, 'path is required' if path.to_s.empty?
24
+
25
+ @act = Act.make(act)
26
+ @assert = Assert.make(assert)
27
+ @name = name.to_s
28
+ @path = path.to_s
29
+ @stage = Stage.make(stage)
30
+
31
+ freeze
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2020-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ require_relative 'act/params'
11
+
12
+ module Simmer
13
+ class Specification
14
+ # Describes everything necessary to execute Pdi::Spoon.
15
+ class Act
16
+ extend Forwardable
17
+ acts_as_hashable
18
+
19
+ module Type
20
+ JOB = :job
21
+ TRANSFORMATION = :transformation
22
+ end
23
+
24
+ attr_reader :repository, :name, :type, :params
25
+
26
+ def_delegator :params, :compile, :compiled_params
27
+
28
+ def initialize(repository:, name:, type:, params: {})
29
+ assert_presence(repository, 'repository')
30
+ assert_presence(name, 'name')
31
+ assert_presence(type, 'type')
32
+
33
+ @repository = repository.to_s
34
+ @name = name.to_s
35
+ @type = Type.const_get(type.to_s.to_s.upcase.to_sym)
36
+ @params = Params.make(params)
37
+
38
+ freeze
39
+ end
40
+
41
+ private
42
+
43
+ def assert_presence(value, name)
44
+ raise ArgumentError, "#{name} is required" if value.to_s.empty?
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2020-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ module Simmer
11
+ class Specification
12
+ class Act
13
+ # Understands how to compile a list of files and key value pairs for Pdi::Spoon
14
+ # consumption.
15
+ class Params
16
+ acts_as_hashable
17
+
18
+ attr_reader :files, :keys
19
+
20
+ def initialize(files: {}, keys: {})
21
+ @files = files || {}
22
+ @keys = keys || {}
23
+ @evaluator = Util::Evaluator.new
24
+
25
+ freeze
26
+ end
27
+
28
+ def compile(files_path, config = {})
29
+ compiled_file_params(files_path, config).merge(compiled_key_params(config))
30
+ end
31
+
32
+ private
33
+
34
+ attr_reader :evaluator
35
+
36
+ def compiled_file_params(files_path, config)
37
+ files.map do |key, value|
38
+ evaluated_value = evaluator.evaluate(value, config)
39
+ expanded_value = File.expand_path(File.join(files_path, evaluated_value))
40
+
41
+ [key, expanded_value]
42
+ end.to_h
43
+ end
44
+
45
+ def compiled_key_params(config)
46
+ keys.map do |key, value|
47
+ evaluated_value = evaluator.evaluate(value, config)
48
+
49
+ [key, evaluated_value]
50
+ end.to_h
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2020-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ require_relative 'assert/assertions'
11
+
12
+ module Simmer
13
+ class Specification
14
+ # Describes what should be expected after a Pdi::Spoon execution.
15
+ class Assert
16
+ acts_as_hashable
17
+
18
+ attr_reader :assertions
19
+
20
+ def initialize(assertions: [])
21
+ @assertions = Assertions.array(assertions)
22
+
23
+ freeze
24
+ end
25
+ end
26
+ end
27
+ end