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

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