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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5f39dfd0f306f15f008f9074944a8a9f2180ba1188f45eda8568317c0a6f235d
4
- data.tar.gz: 41c1d9dd94a31a6fce03ec37ba6b9fc7067672bf05047babd1858ea336055756
3
+ metadata.gz: 1197e913b7b6a7b9a814fb2474aa9d89844af7c4efe872ae001116354a3b6cdb
4
+ data.tar.gz: 6e24db3887b3abb23489642547f64ce4c68af85493b06c54d0c9bc15c637cc44
5
5
  SHA512:
6
- metadata.gz: e659dde01a157945a3c7f64159384eee954696b1905200b5b1fdc3ff908f5c079ddf6dbfe2f46b3654b9ce045f504b21eff4a31eac951b54f465ba76b0dbe713
7
- data.tar.gz: ef419cbe1aa6dbc729522d63b11d2e2657c2c039ecde09efafcf62619ad1e6a263dae3082be2951c0e85a243e9375fbf3bf37b66df92469144d5ac6ca25d768d
6
+ metadata.gz: 3e994e8d2f87598a9baa31211e5baeae2210c8dc8e5e8337579ea2417c835162b12c59dbbd5e84d34d5f969bbe5770dc02ec8017c3e45fb0a1af6572a07f5916
7
+ data.tar.gz: 4f15f5aadaff3d595969aee68ad8c0689f879b1f6c0fde5fc7febe0f4aeff0fa25cc04c0cfeaa263fcca9e3e33ea20598d8d586803e34db68fd58bbf1739eb19
data/.gitignore CHANGED
@@ -5,3 +5,4 @@
5
5
  Gemfile.lock
6
6
  /pkg
7
7
  /bin/di
8
+ /spec/config/simmer.yaml
@@ -2,6 +2,8 @@ env:
2
2
  global:
3
3
  - CC_TEST_REPORTER_ID=48c3a48cc3c203ac365190a30b3c0a9aae0d2c10c9a86735e654f23b8660bb02
4
4
  language: ruby
5
+ services:
6
+ - mysql
5
7
  rvm:
6
8
  # Build on the latest stable of all supported Rubies (https://www.ruby-lang.org/en/downloads/):
7
9
  - 2.4.6
@@ -13,6 +15,9 @@ before_script:
13
15
  - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
14
16
  - chmod +x ./cc-test-reporter
15
17
  - ./cc-test-reporter before-build
18
+ - cp spec/config/simmer.yaml.ci spec/config/simmer.yaml
19
+ - cat spec/db/database.sql | mysql
20
+ - cat spec/db/tables.sql | mysql
16
21
  script:
17
22
  - bundle exec rubocop
18
23
  - bundle exec rspec spec --format documentation
@@ -30,25 +30,119 @@ Hash.include Simmer::CoreExt::Hash
30
30
  require_relative 'simmer/util'
31
31
 
32
32
  # Core code
33
+ require_relative 'simmer/configuration'
34
+ require_relative 'simmer/database'
35
+ require_relative 'simmer/externals'
36
+ require_relative 'simmer/runner'
37
+ require_relative 'simmer/specification'
38
+ require_relative 'simmer/spoon_mock'
33
39
  require_relative 'simmer/suite'
34
40
 
35
41
  # The main entry-point API for the library.
36
42
  module Simmer
37
43
  DEFAULT_CONFIG_PATH = File.join('config', 'simmer.yaml')
38
- DEFAULT_RESULTS_DIR = 'results'
39
44
  DEFAULT_SIMMER_DIR = 'simmer'
45
+
40
46
  class << self
41
- def run(path)
42
- suite.run(path)
47
+ def run(
48
+ path,
49
+ config_path: DEFAULT_CONFIG_PATH,
50
+ out: $stdout,
51
+ simmer_dir: DEFAULT_SIMMER_DIR
52
+ )
53
+ # Get configuration
54
+ yaml_reader = Util::YamlReader.new
55
+ raw_config = yaml_reader.smash(config_path)
56
+ configuration = Configuration.new(raw_config, simmer_dir)
57
+
58
+ # Get fixtures
59
+ raw_fixtures = yaml_reader.smash(configuration.fixtures_dir)
60
+ fixtures = Database::FixtureSet.new(raw_fixtures)
61
+
62
+ # Get specifications to run
63
+ specs = make_specifications(path, configuration.tests_dir)
64
+
65
+ # Make main executable instances
66
+ runner = make_runner(configuration, out, fixtures)
67
+ suite = Suite.new(
68
+ config: configuration.config,
69
+ out: out,
70
+ results_dir: configuration.results_dir,
71
+ runner: runner
72
+ )
73
+
74
+ suite.run(specs)
75
+ end
76
+
77
+ private
78
+
79
+ def make_specifications(path, tests_dir)
80
+ path = path.to_s.empty? ? tests_dir : path
81
+
82
+ Util::YamlReader.new.read(path).map do |file|
83
+ config = (file.data || {}).merge(path: file.path)
84
+
85
+ Specification.make(config)
86
+ end
87
+ end
88
+
89
+ def make_runner(configuration, out, fixtures)
90
+ database = make_mysql_database(configuration, fixtures)
91
+ file_system = make_aws_file_system(configuration)
92
+ spoon_client = make_spoon_client(configuration)
93
+
94
+ Runner.new(
95
+ database: database,
96
+ file_system: file_system,
97
+ out: out,
98
+ spoon_client: spoon_client
99
+ )
100
+ end
101
+
102
+ def make_fixture_set(configuration)
103
+ config = Util::YamlReader.new.smash(configuration.fixtures_dir)
104
+
105
+ Database::FixtureSet.new(config)
106
+ end
107
+
108
+ def make_mysql_database(configuration, fixtures)
109
+ config = (configuration.mysql_database_config || {}).symbolize_keys
110
+ client = Mysql2::Client.new(config)
111
+ exclude_tables = config[:exclude_tables]
112
+
113
+ Externals::MysqlDatabase.new(client, exclude_tables, fixtures)
43
114
  end
44
115
 
45
- def suite
46
- Suite.new(
47
- out: $stdout,
48
- config_path: DEFAULT_CONFIG_PATH,
49
- results_dir: DEFAULT_RESULTS_DIR,
50
- simmer_dir: DEFAULT_SIMMER_DIR
116
+ def make_aws_file_system(configuration)
117
+ config = (configuration.aws_file_system_config || {}).symbolize_keys
118
+
119
+ client = Aws::S3::Client.new(
120
+ access_key_id: config[:access_key_id],
121
+ secret_access_key: config[:secret_access_key],
122
+ region: config[:region]
123
+ )
124
+
125
+ Externals::AwsFileSystem.new(
126
+ client,
127
+ config[:bucket],
128
+ config[:encryption],
129
+ configuration.files_dir
51
130
  )
52
131
  end
132
+
133
+ def make_spoon_client(configuration)
134
+ config = (configuration.spoon_client_config || {}).symbolize_keys
135
+
136
+ spoon =
137
+ if config[:mock]
138
+ SpoonMock.new
139
+ elsif config[:mock_err]
140
+ SpoonMock.new(false)
141
+ else
142
+ Pdi::Spoon.new(dir: config[:dir])
143
+ end
144
+
145
+ Externals::SpoonClient.new(configuration.files_dir, spoon)
146
+ end
53
147
  end
54
148
  end
@@ -19,6 +19,7 @@ module Simmer
19
19
  # Paths
20
20
  FILES = 'files'
21
21
  FIXTURES = 'fixtures'
22
+ RESULTS = 'results'
22
23
  TESTS = 'specs'
23
24
 
24
25
  private_constant :AWS_FILE_SYSTEM_KEY,
@@ -30,27 +31,19 @@ module Simmer
30
31
 
31
32
  attr_reader :config
32
33
 
33
- def initialize(
34
- config_path:,
35
- resolver: Objectable.resolver,
36
- results_dir:,
37
- simmer_dir:,
38
- yaml_reader: Util::YamlReader.new
39
- )
40
- @config = yaml_reader.read(config_path)
34
+ def initialize(config, simmer_dir, resolver: Objectable.resolver)
35
+ @config = config || {}
41
36
  @resolver = resolver
42
- @results_dir = results_dir
43
37
  @simmer_dir = simmer_dir
44
- @yaml_reader = yaml_reader
45
38
 
46
39
  freeze
47
40
  end
48
41
 
49
- def database_config
42
+ def mysql_database_config
50
43
  get(MYSQL_DATABASE_KEY) || {}
51
44
  end
52
45
 
53
- def file_system_config
46
+ def aws_file_system_config
54
47
  get(AWS_FILE_SYSTEM_KEY) || {}
55
48
  end
56
49
 
@@ -70,16 +63,13 @@ module Simmer
70
63
  File.join(simmer_dir, FILES)
71
64
  end
72
65
 
73
- def fixture_set
74
- config = yaml_reader.smash(fixtures_dir)
75
-
76
- Util::FixtureSet.new(config)
66
+ def results_dir
67
+ File.join(simmer_dir, RESULTS)
77
68
  end
78
69
 
79
70
  private
80
71
 
81
72
  attr_reader :resolver,
82
- :results_dir,
83
73
  :simmer_dir,
84
74
  :yaml_reader
85
75
 
@@ -0,0 +1,10 @@
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 'database/fixture_set'
@@ -8,7 +8,7 @@
8
8
  #
9
9
 
10
10
  module Simmer
11
- module Util
11
+ module Database
12
12
  # A fixture is a database record that can be inserted in the Stage phase of a specification
13
13
  # execution.
14
14
  class Fixture
@@ -24,9 +24,13 @@ module Simmer
24
24
  @table = table.to_s
25
25
  end
26
26
 
27
- def to_s
28
- "#{name} (#{table}) #{fields}"
27
+ def ==(other)
28
+ other.instance_of?(self.class) &&
29
+ fields == other.fields &&
30
+ name == other.name &&
31
+ table == other.table
29
32
  end
33
+ alias eql? ==
30
34
  end
31
35
  end
32
36
  end
@@ -10,13 +10,11 @@
10
10
  require_relative 'fixture'
11
11
 
12
12
  module Simmer
13
- module Util
13
+ module Database
14
14
  # Hydrate a collection of Fixture instances from configuration.
15
15
  class FixtureSet
16
16
  def initialize(config = {})
17
- @fixtures_by_name = config.each_with_object({}) do |(name, fixture_config), memo|
18
- memo[name.to_s] = Fixture.make((fixture_config || {}).merge('name' => name))
19
- end
17
+ @fixtures_by_name = config_to_fixures_by_name(config)
20
18
 
21
19
  freeze
22
20
  end
@@ -36,6 +34,14 @@ module Simmer
36
34
  private
37
35
 
38
36
  attr_reader :fixtures_by_name
37
+
38
+ def config_to_fixures_by_name(config)
39
+ (config || {}).each_with_object({}) do |(name, fixture_config), memo|
40
+ full_config = (fixture_config || {}).merge(name: name)
41
+
42
+ memo[name.to_s] = Fixture.make(full_config)
43
+ end
44
+ end
39
45
  end
40
46
  end
41
47
  end
@@ -15,26 +15,21 @@ module Simmer
15
15
 
16
16
  private_constant :BUCKET_SUFFIX
17
17
 
18
- def initialize(config, files_dir)
19
- config = (config || {}).symbolize_keys
18
+ def initialize(aws_s3_client, bucket, encryption, files_dir)
19
+ raise ArgumentError, 'aws_s3_client is required' unless aws_s3_client
20
+ raise ArgumentError, 'bucket is required' if bucket.to_s.empty?
20
21
 
21
- client = Aws::S3::Client.new(
22
- access_key_id: config[:access_key_id],
23
- secret_access_key: config[:secret_access_key],
24
- region: config[:region]
25
- )
26
-
27
- bucket_name = config[:bucket].to_s
28
- assert_bucket_name(bucket_name)
22
+ assert_bucket_name(bucket)
29
23
 
30
- @bucket = Aws::S3::Bucket.new(name: bucket_name, client: client)
31
- @encryption = config[:encryption]
32
- @files_dir = files_dir
24
+ @aws_s3_client = aws_s3_client
25
+ @bucket = bucket.to_s
26
+ @encryption = encryption
27
+ @files_dir = files_dir
33
28
 
34
29
  freeze
35
30
  end
36
31
 
37
- def write(specification)
32
+ def write!(specification)
38
33
  files = specification.stage.files
39
34
 
40
35
  files.each do |file|
@@ -46,24 +41,36 @@ module Simmer
46
41
  files.length
47
42
  end
48
43
 
49
- def clean
50
- bucket.objects.inject(0) do |memo, object|
51
- object.delete
44
+ def clean!
45
+ response = aws_s3_client.list_objects(bucket: bucket)
46
+ objects = response.contents
47
+ keys = objects.map(&:key)
48
+ delete_keys = keys.map { |key| { key: key } }
52
49
 
53
- memo + 1
54
- end
50
+ return 0 if objects.length.zero?
51
+
52
+ aws_s3_client.delete_objects(
53
+ bucket: bucket,
54
+ delete: {
55
+ objects: delete_keys
56
+ }
57
+ )
58
+
59
+ delete_keys.length
55
60
  end
56
61
 
57
62
  private
58
63
 
59
- attr_reader :bucket, :encryption, :files_dir
64
+ attr_reader :aws_s3_client, :bucket, :encryption, :files_dir
60
65
 
61
66
  def write_single(dest, src)
62
67
  src = File.expand_path(src)
63
68
 
64
69
  File.open(src, 'rb') do |file|
65
- bucket.object(dest).put(
66
- body: file,
70
+ aws_s3_client.put_object(
71
+ body: file.read,
72
+ bucket: bucket,
73
+ key: dest,
67
74
  server_side_encryption: encryption
68
75
  )
69
76
  end
@@ -72,7 +79,7 @@ module Simmer
72
79
  end
73
80
 
74
81
  def assert_bucket_name(name)
75
- return if name.end_with?(BUCKET_SUFFIX)
82
+ return if name.to_s.end_with?(BUCKET_SUFFIX)
76
83
 
77
84
  raise ArgumentError, "bucket (#{name}) must end in #{BUCKET_SUFFIX}"
78
85
  end
@@ -15,17 +15,14 @@ module Simmer
15
15
  class MysqlDatabase
16
16
  DATABASE_SUFFIX = 'test'
17
17
 
18
- def initialize(config, fixture_set)
19
- config = (config || {}).symbolize_keys
20
-
21
- database = config[:database].to_s
22
- assert_database_name(database)
23
-
24
- @client = Mysql2::Client.new(config)
18
+ def initialize(client, exclude_tables, fixture_set)
19
+ @client = client
25
20
  @fixture_set = fixture_set
26
- exclude_tables = Array(config[:exclude_tables]).map(&:to_s)
21
+ exclude_tables = Array(exclude_tables).map(&:to_s)
27
22
  @table_names = retrieve_table_names - exclude_tables
28
23
 
24
+ assert_database_name(schema)
25
+
29
26
  freeze
30
27
  end
31
28
 
@@ -97,9 +94,19 @@ module Simmer
97
94
  'SET @@foreign_key_checks = 1'
98
95
  end
99
96
 
97
+ def schema
98
+ client.query_options[:database].to_s
99
+ end
100
+
100
101
  def retrieve_table_names
101
- schema = client.escape(client.query_options[:database].to_s)
102
- sql = "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '#{schema}'"
102
+ escaped_schema = client.escape(schema)
103
+
104
+ sql = <<~SQL
105
+ SELECT TABLE_NAME
106
+ FROM INFORMATION_SCHEMA.TABLES
107
+ WHERE TABLE_SCHEMA = '#{escaped_schema}'
108
+ AND TABLE_TYPE = 'BASE TABLE'
109
+ SQL
103
110
 
104
111
  client.query(sql).to_a.map { |v| v['TABLE_NAME'].to_s }
105
112
  end
@@ -7,36 +7,22 @@
7
7
  # LICENSE file in the root directory of this source tree.
8
8
  #
9
9
 
10
- require_relative 'spoon_client/mock'
11
10
  require_relative 'spoon_client/result'
12
11
 
13
12
  module Simmer
14
13
  module Externals
15
14
  # Wraps up Pdi::Spoon at a higher-level for Simmer to consume.
16
15
  class SpoonClient
17
- MOCK_KEY = :mock
18
- MOCK_ERR_KEY = :mock_err
16
+ def initialize(files_dir, spoon)
17
+ raise ArgumentError, 'spoon is required' unless spoon
19
18
 
20
- private_constant :MOCK_KEY, :MOCK_ERR_KEY
21
-
22
- def initialize(config, files_dir)
23
- @files_dir = files_dir
24
-
25
- config = (config || {}).symbolize_keys
26
-
27
- @spoon =
28
- if config[MOCK_KEY]
29
- Mock.new
30
- elsif config[MOCK_ERR_KEY]
31
- Mock.new(false)
32
- else
33
- Pdi::Spoon.new(dir: config[:dir])
34
- end
19
+ @files_dir = files_dir.to_s
20
+ @spoon = spoon
35
21
 
36
22
  freeze
37
23
  end
38
24
 
39
- def run(specification, config = {})
25
+ def run(specification, config)
40
26
  execution_result = nil
41
27
  time_in_seconds = nil
42
28