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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +5 -0
- data/lib/simmer.rb +103 -9
- data/lib/simmer/configuration.rb +7 -17
- data/lib/simmer/database.rb +10 -0
- data/lib/simmer/{util → database}/fixture.rb +7 -3
- data/lib/simmer/{util → database}/fixture_set.rb +10 -4
- data/lib/simmer/externals/aws_file_system.rb +30 -23
- data/lib/simmer/externals/mysql_database.rb +17 -10
- data/lib/simmer/externals/spoon_client.rb +5 -19
- data/lib/simmer/runner.rb +2 -2
- data/lib/simmer/specification/act.rb +1 -6
- data/lib/simmer/specification/assert/assertions/table.rb +1 -6
- data/lib/simmer/spoon_mock.rb +35 -0
- data/lib/simmer/suite.rb +49 -43
- data/lib/simmer/{session → suite}/reporter.rb +1 -1
- data/lib/simmer/{session → suite}/result.rb +1 -1
- data/lib/simmer/util.rb +0 -1
- data/lib/simmer/util/evaluator.rb +4 -5
- data/lib/simmer/util/record.rb +2 -0
- data/lib/simmer/util/record_set.rb +5 -1
- data/lib/simmer/util/resolver.rb +2 -2
- data/lib/simmer/util/yaml_reader.rb +9 -12
- data/lib/simmer/version.rb +1 -1
- data/spec/config/simmer.yaml.ci +7 -0
- data/spec/db/database.sql +1 -0
- data/spec/db/tables.sql +20 -0
- data/spec/db_helper.rb +26 -0
- data/spec/fixtures/agent_fixtures.yaml +14 -0
- data/spec/fixtures/configuration.yaml +11 -0
- data/spec/fixtures/noc_list.csv +3 -0
- data/spec/fixtures/specifications/load_noc_list.yaml +30 -0
- data/spec/fixtures/yaml_reader/bar.yaml +2 -0
- data/spec/fixtures/yaml_reader/baz/baz.yaml +2 -0
- data/spec/fixtures/yaml_reader/foo.yaml +2 -0
- data/spec/simmer/configuration_spec.rb +46 -0
- data/spec/simmer/database/fixture_set_spec.rb +75 -0
- data/spec/simmer/database/fixture_spec.rb +57 -0
- data/spec/simmer/externals/aws_file_system_spec.rb +75 -0
- data/spec/simmer/externals/mysql_database_spec.rb +79 -0
- data/spec/simmer/externals/spoon_client_spec.rb +67 -0
- data/spec/simmer/specification/act/params_spec.rb +38 -0
- data/spec/simmer/specification/act_spec.rb +37 -0
- data/spec/simmer/specification/assert_spec.rb +27 -0
- data/spec/simmer/specification/stage_spec.rb +32 -0
- data/spec/simmer/specification_spec.rb +28 -0
- data/spec/simmer/util/evaluator_spec.rb +82 -0
- data/spec/simmer/util/record_set_spec.rb +41 -0
- data/spec/simmer/util/record_spec.rb +218 -0
- data/spec/simmer/util/yaml_reader_spec.rb +49 -0
- data/spec/spec_helper.rb +21 -0
- metadata +60 -8
- data/lib/simmer/externals/spoon_client/mock.rb +0 -39
- data/lib/simmer/session.rb +0 -79
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1197e913b7b6a7b9a814fb2474aa9d89844af7c4efe872ae001116354a3b6cdb
|
4
|
+
data.tar.gz: 6e24db3887b3abb23489642547f64ce4c68af85493b06c54d0c9bc15c637cc44
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3e994e8d2f87598a9baa31211e5baeae2210c8dc8e5e8337579ea2417c835162b12c59dbbd5e84d34d5f969bbe5770dc02ec8017c3e45fb0a1af6572a07f5916
|
7
|
+
data.tar.gz: 4f15f5aadaff3d595969aee68ad8c0689f879b1f6c0fde5fc7febe0f4aeff0fa25cc04c0cfeaa263fcca9e3e33ea20598d8d586803e34db68fd58bbf1739eb19
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
@@ -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
|
data/lib/simmer.rb
CHANGED
@@ -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(
|
42
|
-
|
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
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
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
|
data/lib/simmer/configuration.rb
CHANGED
@@ -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
|
-
|
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
|
42
|
+
def mysql_database_config
|
50
43
|
get(MYSQL_DATABASE_KEY) || {}
|
51
44
|
end
|
52
45
|
|
53
|
-
def
|
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
|
74
|
-
|
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
|
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
|
28
|
-
|
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
|
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
|
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(
|
19
|
-
|
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
|
-
|
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
|
-
@
|
31
|
-
@
|
32
|
-
@
|
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
|
-
|
51
|
-
|
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
|
-
|
54
|
-
|
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
|
-
|
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(
|
19
|
-
|
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(
|
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
|
-
|
102
|
-
|
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
|
-
|
18
|
-
|
16
|
+
def initialize(files_dir, spoon)
|
17
|
+
raise ArgumentError, 'spoon is required' unless spoon
|
19
18
|
|
20
|
-
|
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
|
|