simmer 1.0.0.pre.alpha.2

Sign up to get free protection for your applications and to get access to all the features.
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