simmer 1.0.0.pre.alpha.3 → 1.0.0.pre.alpha.4

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 (55) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +5 -0
  4. data/lib/simmer.rb +103 -9
  5. data/lib/simmer/configuration.rb +7 -17
  6. data/lib/simmer/database.rb +10 -0
  7. data/lib/simmer/{util → database}/fixture.rb +7 -3
  8. data/lib/simmer/{util → database}/fixture_set.rb +10 -4
  9. data/lib/simmer/externals/aws_file_system.rb +30 -23
  10. data/lib/simmer/externals/mysql_database.rb +17 -10
  11. data/lib/simmer/externals/spoon_client.rb +5 -19
  12. data/lib/simmer/runner.rb +2 -2
  13. data/lib/simmer/specification/act.rb +1 -6
  14. data/lib/simmer/specification/assert/assertions/table.rb +1 -6
  15. data/lib/simmer/spoon_mock.rb +35 -0
  16. data/lib/simmer/suite.rb +49 -43
  17. data/lib/simmer/{session → suite}/reporter.rb +1 -1
  18. data/lib/simmer/{session → suite}/result.rb +1 -1
  19. data/lib/simmer/util.rb +0 -1
  20. data/lib/simmer/util/evaluator.rb +4 -5
  21. data/lib/simmer/util/record.rb +2 -0
  22. data/lib/simmer/util/record_set.rb +5 -1
  23. data/lib/simmer/util/resolver.rb +2 -2
  24. data/lib/simmer/util/yaml_reader.rb +9 -12
  25. data/lib/simmer/version.rb +1 -1
  26. data/spec/config/simmer.yaml.ci +7 -0
  27. data/spec/db/database.sql +1 -0
  28. data/spec/db/tables.sql +20 -0
  29. data/spec/db_helper.rb +26 -0
  30. data/spec/fixtures/agent_fixtures.yaml +14 -0
  31. data/spec/fixtures/configuration.yaml +11 -0
  32. data/spec/fixtures/noc_list.csv +3 -0
  33. data/spec/fixtures/specifications/load_noc_list.yaml +30 -0
  34. data/spec/fixtures/yaml_reader/bar.yaml +2 -0
  35. data/spec/fixtures/yaml_reader/baz/baz.yaml +2 -0
  36. data/spec/fixtures/yaml_reader/foo.yaml +2 -0
  37. data/spec/simmer/configuration_spec.rb +46 -0
  38. data/spec/simmer/database/fixture_set_spec.rb +75 -0
  39. data/spec/simmer/database/fixture_spec.rb +57 -0
  40. data/spec/simmer/externals/aws_file_system_spec.rb +75 -0
  41. data/spec/simmer/externals/mysql_database_spec.rb +79 -0
  42. data/spec/simmer/externals/spoon_client_spec.rb +67 -0
  43. data/spec/simmer/specification/act/params_spec.rb +38 -0
  44. data/spec/simmer/specification/act_spec.rb +37 -0
  45. data/spec/simmer/specification/assert_spec.rb +27 -0
  46. data/spec/simmer/specification/stage_spec.rb +32 -0
  47. data/spec/simmer/specification_spec.rb +28 -0
  48. data/spec/simmer/util/evaluator_spec.rb +82 -0
  49. data/spec/simmer/util/record_set_spec.rb +41 -0
  50. data/spec/simmer/util/record_spec.rb +218 -0
  51. data/spec/simmer/util/yaml_reader_spec.rb +49 -0
  52. data/spec/spec_helper.rb +21 -0
  53. metadata +60 -8
  54. data/lib/simmer/externals/spoon_client/mock.rb +0 -39
  55. data/lib/simmer/session.rb +0 -79
@@ -64,7 +64,7 @@ module Simmer
64
64
 
65
65
  def clean_file_system
66
66
  print_waiting('Stage', 'Cleaning File System')
67
- count = file_system.clean
67
+ count = file_system.clean!
68
68
  print("#{count} file(s) deleted")
69
69
 
70
70
  count
@@ -72,7 +72,7 @@ module Simmer
72
72
 
73
73
  def seed_file_system(specification)
74
74
  print_waiting('Stage', 'Seeding File System')
75
- count = file_system.write(specification)
75
+ count = file_system.write!(specification)
76
76
  print("#{count} file(s) uploaded")
77
77
 
78
78
  count
@@ -16,11 +16,6 @@ module Simmer
16
16
  extend Forwardable
17
17
  acts_as_hashable
18
18
 
19
- module Type
20
- JOB = :job
21
- TRANSFORMATION = :transformation
22
- end
23
-
24
19
  attr_reader :repository, :name, :type, :params
25
20
 
26
21
  def_delegator :params, :compile, :compiled_params
@@ -32,7 +27,7 @@ module Simmer
32
27
 
33
28
  @repository = repository.to_s
34
29
  @name = name.to_s
35
- @type = Type.const_get(type.to_s.to_s.upcase.to_sym)
30
+ @type = type.to_s
36
31
  @params = Params.make(params)
37
32
 
38
33
  freeze
@@ -27,6 +27,7 @@ module Simmer
27
27
  end
28
28
 
29
29
  def assert(database, _output)
30
+ keys = record_set.keys
30
31
  actual_records = database.records(name, keys)
31
32
  actual_record_set = Util::RecordSet.new(actual_records)
32
33
 
@@ -34,12 +35,6 @@ module Simmer
34
35
 
35
36
  BadTableAssertion.new(name, record_set, actual_record_set)
36
37
  end
37
-
38
- private
39
-
40
- def keys
41
- record_set.keys
42
- end
43
38
  end
44
39
  end
45
40
  end
@@ -0,0 +1,35 @@
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
+ # Provides a simple mock for the underlying Pdi::Spoon class.
12
+ class SpoonMock
13
+ attr_reader :pass
14
+
15
+ def initialize(pass = true)
16
+ @pass = pass
17
+
18
+ freeze
19
+ end
20
+
21
+ def run(*)
22
+ raise Pdi::Spoon::KitchenError, 'mocked' unless pass
23
+
24
+ Pdi::Executor::Result.new(
25
+ args: [],
26
+ status: {
27
+ code: 0,
28
+ err: 'Some error output from PDI',
29
+ out: 'Some output from PDI',
30
+ pid: 123
31
+ }
32
+ )
33
+ end
34
+ end
35
+ end
@@ -7,67 +7,73 @@
7
7
  # LICENSE file in the root directory of this source tree.
8
8
  #
9
9
 
10
- require_relative 'configuration'
11
- require_relative 'externals'
12
- require_relative 'runner'
13
- require_relative 'session'
14
- require_relative 'specification'
10
+ require_relative 'suite/reporter'
11
+ require_relative 'suite/result'
15
12
 
16
- # Entrypoint to the library
17
13
  module Simmer
18
- # The main object entrypoint that brings the entire codebase together.
14
+ # Runs a collection of specifications and then writes down the results to disk.
19
15
  class Suite
20
- attr_reader :configuration, :session
21
-
22
- def initialize(config_path:, out:, results_dir:, simmer_dir:)
23
- @configuration = Configuration.new(
24
- config_path: config_path,
25
- results_dir: results_dir,
26
- simmer_dir: simmer_dir
27
- )
28
-
29
- runner = Runner.new(
30
- database: database,
31
- file_system: file_system,
32
- out: out,
33
- spoon_client: spoon_client
34
- )
35
-
36
- @session = Session.new(
37
- config: configuration.config,
38
- out: out,
39
- results_dir: results_dir,
40
- runner: runner
41
- )
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
42
28
 
43
29
  freeze
44
30
  end
45
31
 
46
- def run(path)
47
- session.run(specifications(path))
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
48
46
  end
49
47
 
50
48
  private
51
49
 
52
- def specifications(path)
53
- path = path.to_s.empty? ? configuration.tests_dir : path
50
+ attr_reader :config, :out, :results_dir, :resolver, :runner
51
+
52
+ def run_all_specs(specifications)
53
+ out.puts('Simmer suite started')
54
54
 
55
- Util::YamlReader.new.all(path).map do |file, config|
56
- config = (config || {}).merge(path: file)
57
- Specification.make(config)
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)
58
62
  end
59
63
  end
60
64
 
61
- def database
62
- Externals::MysqlDatabase.new(configuration.database_config, configuration.fixture_set)
63
- end
65
+ def run_single_spec(specification, index, count)
66
+ id = SecureRandom.uuid
64
67
 
65
- def file_system
66
- Externals::AwsFileSystem.new(configuration.file_system_config, configuration.files_dir)
68
+ out.puts("Test #{index} of #{count}: #{id} (#{specification.act.type})")
69
+
70
+ runner.run(specification, id: id, config: config).tap do
71
+ print_line
72
+ end
67
73
  end
68
74
 
69
- def spoon_client
70
- Externals::SpoonClient.new(configuration.spoon_client_config, configuration.files_dir)
75
+ def print_line
76
+ out.puts('-' * 60)
71
77
  end
72
78
  end
73
79
  end
@@ -8,7 +8,7 @@
8
8
  #
9
9
 
10
10
  module Simmer
11
- class Session
11
+ class Suite
12
12
  # Understands how to write a SessionResult instance to disk.
13
13
  class Reporter
14
14
  DATA_FILE = 'data.yaml'
@@ -8,7 +8,7 @@
8
8
  #
9
9
 
10
10
  module Simmer
11
- class Session
11
+ class Suite
12
12
  # The return object for a Session#run call.
13
13
  class Result
14
14
  attr_reader :runner_results
@@ -8,6 +8,5 @@
8
8
  #
9
9
 
10
10
  require_relative 'util/evaluator'
11
- require_relative 'util/fixture_set'
12
11
  require_relative 'util/record_set'
13
12
  require_relative 'util/yaml_reader'
@@ -11,17 +11,16 @@ require_relative 'resolver'
11
11
 
12
12
  module Simmer
13
13
  module Util
14
- # Text template renderer. It knows how to take a string and object as an input and
15
- # output a compiled string.
14
+ # Glues together Objectable and Stringento libraries to form a text template renderer.
16
15
  class Evaluator
17
- def initialize
18
- @resolver = Objectable.resolver
16
+ def initialize(resolver = Resolver.new)
17
+ @resolver = resolver
19
18
 
20
19
  freeze
21
20
  end
22
21
 
23
22
  def evaluate(string, input = {})
24
- Stringento.evaluate(string, input, resolver: Resolver.new)
23
+ Stringento.evaluate(string, input, resolver: resolver)
25
24
  end
26
25
 
27
26
  private
@@ -19,6 +19,8 @@ module Simmer
19
19
  def_delegators :data, :to_h
20
20
 
21
21
  def initialize(data = {})
22
+ data = data.respond_to?(:to_h) ? data.to_h : data
23
+
22
24
  @data = sorted_string_hash(data)
23
25
  end
24
26
 
@@ -14,6 +14,10 @@ module Simmer
14
14
  # A less-strict comparable collection of Record instances.
15
15
  # It does not depend on Record ordering.
16
16
  class RecordSet
17
+ extend Forwardable
18
+
19
+ def_delegators :records, :length
20
+
17
21
  attr_reader :records
18
22
 
19
23
  def initialize(records = [])
@@ -34,7 +38,7 @@ module Simmer
34
38
  end
35
39
 
36
40
  def keys
37
- records.first&.keys || []
41
+ records.flat_map(&:keys)
38
42
  end
39
43
 
40
44
  private
@@ -14,8 +14,8 @@ module Simmer
14
14
  class Resolver
15
15
  attr_reader :objectable_resolver
16
16
 
17
- def initialize
18
- @objectable_resolver = Objectable.resolver
17
+ def initialize(objectable_resolver: Objectable.resolver)
18
+ @objectable_resolver = objectable_resolver
19
19
 
20
20
  freeze
21
21
  end
@@ -17,26 +17,22 @@ module Simmer
17
17
  private_constant :EXTENSIONS
18
18
 
19
19
  def smash(path)
20
- files = all(path).values
21
-
22
- files.each_with_object({}) do |config, memo|
23
- memo.merge!(config)
24
- end
20
+ read(path).each_with_object({}) { |file, memo| memo.merge!(file.data || {}) }
25
21
  end
26
22
 
27
- def all(path)
28
- expand(path).map { |file| [file, read(file)] }.to_h
23
+ def read(path)
24
+ expand(path).map { |file| OpenStruct.new(path: file, data: raw(file)) }
29
25
  end
30
26
 
31
- def read(path)
27
+ private
28
+
29
+ def raw(path)
32
30
  path = File.expand_path(path)
33
31
  contents = File.read(path)
34
32
 
35
- YAML.safe_load(contents) || {}
33
+ YAML.safe_load(contents)
36
34
  end
37
35
 
38
- private
39
-
40
36
  def wildcard_name
41
37
  "*.{#{EXTENSIONS.join(',')}}"
42
38
  end
@@ -48,13 +44,14 @@ module Simmer
48
44
  def expand(path)
49
45
  path = File.expand_path(path.to_s)
50
46
 
47
+ # The sort will ensure it is deterministic (lexicographic by path)
51
48
  if File.directory?(path)
52
49
  glob = full_path(path)
53
50
 
54
51
  Dir[glob].to_a
55
52
  else
56
53
  Array(path)
57
- end
54
+ end.sort
58
55
  end
59
56
  end
60
57
  end
@@ -8,5 +8,5 @@
8
8
  #
9
9
 
10
10
  module Simmer
11
- VERSION = '1.0.0-alpha.3'
11
+ VERSION = '1.0.0-alpha.4'
12
12
  end
@@ -0,0 +1,7 @@
1
+ mysql_database:
2
+ init_command: "SET @@SESSION.sql_mode = 'TRADITIONAL,NO_AUTO_VALUE_ON_ZERO'"
3
+ database: simmer_test
4
+ username: root
5
+ host: 127.0.0.1
6
+ port: 3306
7
+ flags: MULTI_STATEMENTS
@@ -0,0 +1 @@
1
+ CREATE DATABASE IF NOT EXISTS simmer_test;
@@ -0,0 +1,20 @@
1
+ DROP TABLE IF EXISTS `simmer_test`.`notes`;
2
+ DROP TABLE IF EXISTS `simmer_test`.`agents`;
3
+
4
+ CREATE TABLE `simmer_test`.`agents` (
5
+ `id` int(11) NOT NULL AUTO_INCREMENT,
6
+ `call_sign` varchar(150) NOT NULL,
7
+ `first` varchar(255),
8
+ `last` varchar(255),
9
+ PRIMARY KEY (`id`),
10
+ UNIQUE INDEX (`call_sign`)
11
+ );
12
+
13
+ CREATE TABLE `simmer_test`.`notes` (
14
+ `id` int(11) NOT NULL AUTO_INCREMENT,
15
+ `agent_id` int(11) NOT NULL,
16
+ `note` varchar(255),
17
+ PRIMARY KEY (`id`),
18
+ INDEX (`agent_id`),
19
+ FOREIGN KEY (`agent_id`) REFERENCES `simmer_test`.`agents`(`id`)
20
+ );
@@ -0,0 +1,26 @@
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
+ CLEAN_SQL_STATEMENTS = [
11
+ 'DELETE FROM `simmer_test`.`notes`',
12
+ 'DELETE FROM `simmer_test`.`agents`'
13
+ ].freeze
14
+
15
+ def db_helper_config
16
+ simmer_config['mysql_database']
17
+ end
18
+
19
+ def db_helper_client
20
+ @db_helper_client ||= Mysql2::Client.new(db_helper_config)
21
+ end
22
+
23
+ def db_helper_clean_schema
24
+ CLEAN_SQL_STATEMENTS.each { |sql| db_helper_client.query(sql) }
25
+ nil
26
+ end
@@ -0,0 +1,14 @@
1
+ hulk:
2
+ table: agents
3
+ fields:
4
+ call_sign: hulk
5
+ first: CLASSIFIED
6
+ last: CLASSIFIED
7
+
8
+ iron_man:
9
+ table: agents
10
+ fields:
11
+ call_sign: iron_man
12
+ first: CLASSIFIED
13
+ last: CLASSIFIED
14
+
@@ -0,0 +1,11 @@
1
+ aws_file_system:
2
+ aws_file_system_key: aws_file_system_value
3
+
4
+ mysql_database:
5
+ mysql_database_key: mysql_database_value
6
+
7
+ spoon_client:
8
+ spoon_client_key: spoon_client_value
9
+
10
+ other:
11
+ other_key: other_value