simmer 1.0.0.pre.alpha.5 → 1.0.0.pre.alpha.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c70362d593331adc1b9499d1292f6a3c43d06a556eddfcc5d52c203d1f5081e0
4
- data.tar.gz: edd212d1fc90f57a06bf8594793ac7c574a40e5ac39b3b25ce2dd1abed2a0b9f
3
+ metadata.gz: d7bb744ed6c7545eff9608e7b4548b5b71afbc219d75cba872f93b6fb0e7db31
4
+ data.tar.gz: ab9487df40d1d7dd7030c09e9d35398cf45169ec5c1ac322165728ee40bdaa8a
5
5
  SHA512:
6
- metadata.gz: 40e8856733adf93d0602bad3e06a8d7da6a304a2a0856efcd43a279318441c836311630fcfa9ee5e4b75c8ddf7d261c34c8d6c23cd69b5adccc87591cb59a3ce
7
- data.tar.gz: f67b95adfb5bddd49996306b540621b79fd1430c5cd82a1310b80ab6652657e52b4bf297b2e42c6dabe4a2d15f7fd48c26f25337bef12d511819add50ea85ad4
6
+ metadata.gz: da855ec25b4bccb880dc974abab073cadd22467f36451320c1bf550599f818c72684c5c2b01e61453a8d498e46beb949c21035b1a012009c4ee37f9e36ef59ad
7
+ data.tar.gz: e906e083ade596051e93e5a67f64faa5c306ac112eaafa0dabb507c2e42d0daec0baa3434645ee39675b0b05ff9657db331ef435ff36417dc4d40294ce3f7023
data/.gitignore CHANGED
@@ -4,5 +4,6 @@
4
4
  /coverage
5
5
  Gemfile.lock
6
6
  /pkg
7
- /bin/di
8
7
  /spec/config/simmer.yaml
8
+ /spec/simmer_spec/results
9
+
data/.rubocop.yml CHANGED
@@ -16,7 +16,7 @@ Metrics/MethodLength:
16
16
  Max: 25
17
17
 
18
18
  AllCops:
19
- TargetRubyVersion: 2.4
19
+ TargetRubyVersion: 2.5
20
20
 
21
21
  Metrics/AbcSize:
22
22
  Max: 16
data/.travis.yml CHANGED
@@ -6,7 +6,6 @@ services:
6
6
  - mysql
7
7
  rvm:
8
8
  # Build on the latest stable of all supported Rubies (https://www.ruby-lang.org/en/downloads/):
9
- - 2.4.6
10
9
  - 2.5.5
11
10
  - 2.6.5
12
11
  - 2.7.0
@@ -12,9 +12,10 @@ module Simmer
12
12
  # Simmer implementation.
13
13
  class Configuration
14
14
  # Configuration Keys
15
- AWS_FILE_SYSTEM_KEY = :aws_file_system
16
- MYSQL_DATABASE_KEY = :mysql_database
17
- SPOON_CLIENT_KEY = :spoon_client
15
+ AWS_FILE_SYSTEM_KEY = :aws_file_system
16
+ LOCAL_FILE_SYSTEM_KEY = :local_file_system
17
+ MYSQL_DATABASE_KEY = :mysql_database
18
+ SPOON_CLIENT_KEY = :spoon_client
18
19
 
19
20
  # Paths
20
21
  FILES = 'files'
@@ -47,6 +48,18 @@ module Simmer
47
48
  get(AWS_FILE_SYSTEM_KEY) || {}
48
49
  end
49
50
 
51
+ def local_file_system_config
52
+ get(LOCAL_FILE_SYSTEM_KEY) || {}
53
+ end
54
+
55
+ def aws_file_system?
56
+ config.key?(AWS_FILE_SYSTEM_KEY.to_s)
57
+ end
58
+
59
+ def local_file_system?
60
+ config.key?(LOCAL_FILE_SYSTEM_KEY.to_s)
61
+ end
62
+
50
63
  def spoon_client_config
51
64
  get(SPOON_CLIENT_KEY) || {}
52
65
  end
@@ -27,10 +27,6 @@ module Simmer
27
27
  fixtures_by_name[key]
28
28
  end
29
29
 
30
- def all
31
- fixtures_by_name.values
32
- end
33
-
34
30
  private
35
31
 
36
32
  attr_reader :fixtures_by_name
@@ -7,42 +7,37 @@
7
7
  # LICENSE file in the root directory of this source tree.
8
8
  #
9
9
 
10
+ require_relative 'file_system'
11
+
10
12
  module Simmer
11
13
  module Externals
12
14
  # Provides the implementation for using AWS S3 as a destination file store.
13
- class AwsFileSystem
14
- BUCKET_SUFFIX = 'test'
15
-
16
- private_constant :BUCKET_SUFFIX
17
-
15
+ class AwsFileSystem < FileSystem
18
16
  def initialize(aws_s3_client, bucket, encryption, files_dir)
19
17
  raise ArgumentError, 'aws_s3_client is required' unless aws_s3_client
20
18
  raise ArgumentError, 'bucket is required' if bucket.to_s.empty?
21
19
 
22
- assert_bucket_name(bucket)
20
+ super(bucket)
23
21
 
24
22
  @aws_s3_client = aws_s3_client
25
- @bucket = bucket.to_s
26
23
  @encryption = encryption
27
24
  @files_dir = files_dir
28
25
 
29
26
  freeze
30
27
  end
31
28
 
32
- def write!(specification)
33
- files = specification.stage.files
34
-
35
- files.each do |file|
36
- src = File.join(files_dir, file.src)
29
+ def write!(input_files)
30
+ input_files.each do |input_file|
31
+ src = File.join(files_dir, input_file.src)
37
32
 
38
- write_single(file.dest, src)
33
+ write_single(input_file.dest, src)
39
34
  end
40
35
 
41
- files.length
36
+ input_files.length
42
37
  end
43
38
 
44
39
  def clean!
45
- response = aws_s3_client.list_objects(bucket: bucket)
40
+ response = aws_s3_client.list_objects(bucket: root)
46
41
  objects = response.contents
47
42
  keys = objects.map(&:key)
48
43
  delete_keys = keys.map { |key| { key: key } }
@@ -50,7 +45,7 @@ module Simmer
50
45
  return 0 if objects.length.zero?
51
46
 
52
47
  aws_s3_client.delete_objects(
53
- bucket: bucket,
48
+ bucket: root,
54
49
  delete: {
55
50
  objects: delete_keys
56
51
  }
@@ -61,7 +56,7 @@ module Simmer
61
56
 
62
57
  private
63
58
 
64
- attr_reader :aws_s3_client, :bucket, :encryption, :files_dir
59
+ attr_reader :aws_s3_client, :encryption, :files_dir
65
60
 
66
61
  def write_single(dest, src)
67
62
  src = File.expand_path(src)
@@ -69,7 +64,7 @@ module Simmer
69
64
  File.open(src, 'rb') do |file|
70
65
  aws_s3_client.put_object(
71
66
  body: file.read,
72
- bucket: bucket,
67
+ bucket: root,
73
68
  key: dest,
74
69
  server_side_encryption: encryption
75
70
  )
@@ -77,12 +72,6 @@ module Simmer
77
72
 
78
73
  nil
79
74
  end
80
-
81
- def assert_bucket_name(name)
82
- return if name.to_s.end_with?(BUCKET_SUFFIX)
83
-
84
- raise ArgumentError, "bucket (#{name}) must end in #{BUCKET_SUFFIX}"
85
- end
86
75
  end
87
76
  end
88
77
  end
@@ -0,0 +1,29 @@
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
+ module Externals
12
+ # Provides the shared basics of all file systems.
13
+ class FileSystem
14
+ SUFFIX = 'test'
15
+
16
+ private_constant :SUFFIX
17
+
18
+ def initialize(root)
19
+ @root = root.to_s
20
+
21
+ raise ArgumentError, "root: #{root} must end in #{SUFFIX}" unless root.end_with?(SUFFIX)
22
+ end
23
+
24
+ private
25
+
26
+ attr_reader :root
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,56 @@
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 'file_system'
11
+
12
+ module Simmer
13
+ module Externals
14
+ # Provides the implementation for using a local directory
15
+ class LocalFileSystem < FileSystem
16
+ def initialize(root, files_dir)
17
+ root = File.expand_path(root.to_s)
18
+
19
+ super(root)
20
+
21
+ @files_dir = files_dir.to_s
22
+
23
+ freeze
24
+ end
25
+
26
+ def write!(input_files)
27
+ input_files.each do |input_file|
28
+ src = File.join(files_dir, input_file.src)
29
+
30
+ write_single(input_file.dest, src)
31
+ end
32
+
33
+ input_files.length
34
+ end
35
+
36
+ def clean!
37
+ glob = File.join(root, '**', '*')
38
+ all_files = Dir[glob].reject { |p| File.directory?(p) }
39
+
40
+ all_files.each { |path| FileUtils.rm(path) }
41
+ all_files.length
42
+ end
43
+
44
+ private
45
+
46
+ attr_reader :files_dir
47
+
48
+ def write_single(dest, src)
49
+ full_dest = File.join(root, dest)
50
+ dest_dir = File.dirname(full_dest)
51
+ FileUtils.mkdir_p(dest_dir)
52
+ FileUtils.cp(src, full_dest)
53
+ end
54
+ end
55
+ end
56
+ end
@@ -15,14 +15,14 @@ module Simmer
15
15
  class MysqlDatabase
16
16
  DATABASE_SUFFIX = 'test'
17
17
 
18
- def initialize(client, exclude_tables, fixture_set)
19
- @client = client
20
- @fixture_set = fixture_set
21
- exclude_tables = Array(exclude_tables).map(&:to_s)
22
- @table_names = retrieve_table_names - exclude_tables
18
+ def initialize(client, exclude_tables = [])
19
+ @client = client
23
20
 
24
21
  assert_database_name(schema)
25
22
 
23
+ exclude_tables = Array(exclude_tables).map(&:to_s)
24
+ @table_names = retrieve_table_names - exclude_tables
25
+
26
26
  freeze
27
27
  end
28
28
 
@@ -32,8 +32,8 @@ module Simmer
32
32
  client.query(query).to_a
33
33
  end
34
34
 
35
- def seed!(specification)
36
- sql_statements = seed_sql_statements(specification)
35
+ def seed!(fixtures)
36
+ sql_statements = seed_sql_statements(fixtures)
37
37
 
38
38
  shameless_execute(sql_statements)
39
39
 
@@ -56,14 +56,8 @@ module Simmer
56
56
  Array(columns).any? ? Array(columns).map { |c| client.escape(c) }.join(',') : '*'
57
57
  end
58
58
 
59
- def seed_sql_statements(specification)
60
- fixture_names = specification.stage.fixtures
61
-
62
- fixture_names.map do |fixture_name|
63
- fixture = fixture_set.get!(fixture_name)
64
-
65
- SqlFixture.new(client, fixture).to_sql
66
- end
59
+ def seed_sql_statements(fixtures)
60
+ fixtures.map { |fixture| SqlFixture.new(client, fixture).to_sql }
67
61
  end
68
62
 
69
63
  def clean_sql_statements
@@ -8,5 +8,6 @@
8
8
  #
9
9
 
10
10
  require_relative 'externals/aws_file_system'
11
+ require_relative 'externals/local_file_system'
11
12
  require_relative 'externals/mysql_database'
12
13
  require_relative 'externals/spoon_client'
data/lib/simmer/runner.rb CHANGED
@@ -13,9 +13,10 @@ require_relative 'runner/result'
13
13
  module Simmer
14
14
  # Runs a single specification.
15
15
  class Runner
16
- def initialize(database:, file_system:, out:, spoon_client:)
16
+ def initialize(database:, file_system:, fixture_set:, out:, spoon_client:)
17
17
  @database = database
18
18
  @file_system = file_system
19
+ @fixture_set = fixture_set
19
20
  @judge = Judge.new(database)
20
21
  @out = out
21
22
  @spoon_client = spoon_client
@@ -44,7 +45,7 @@ module Simmer
44
45
 
45
46
  private
46
47
 
47
- attr_reader :database, :file_system, :judge, :out, :spoon_client
48
+ attr_reader :database, :file_system, :fixture_set, :judge, :out, :spoon_client
48
49
 
49
50
  def clean_db
50
51
  print_waiting('Stage', 'Cleaning database')
@@ -56,7 +57,10 @@ module Simmer
56
57
 
57
58
  def seed_db(specification)
58
59
  print_waiting('Stage', 'Seeding database')
59
- count = database.seed!(specification)
60
+
61
+ fixtures = specification.stage.fixtures.map { |f| fixture_set.get!(f) }
62
+ count = database.seed!(fixtures)
63
+
60
64
  print("#{count} record(s) inserted")
61
65
 
62
66
  count
@@ -72,7 +76,7 @@ module Simmer
72
76
 
73
77
  def seed_file_system(specification)
74
78
  print_waiting('Stage', 'Seeding File System')
75
- count = file_system.write!(specification)
79
+ count = file_system.write!(specification.stage.files)
76
80
  print("#{count} file(s) uploaded")
77
81
 
78
82
  count
@@ -39,14 +39,6 @@ module Simmer
39
39
  self
40
40
  end
41
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
42
  private
51
43
 
52
44
  attr_reader :session_result
@@ -8,5 +8,5 @@
8
8
  #
9
9
 
10
10
  module Simmer
11
- VERSION = '1.0.0-alpha.5'
11
+ VERSION = '1.0.0-alpha.6'
12
12
  end
data/lib/simmer.rb CHANGED
@@ -35,7 +35,6 @@ require_relative 'simmer/database'
35
35
  require_relative 'simmer/externals'
36
36
  require_relative 'simmer/runner'
37
37
  require_relative 'simmer/specification'
38
- require_relative 'simmer/spoon_mock'
39
38
  require_relative 'simmer/suite'
40
39
 
41
40
  # The main entry-point API for the library.
@@ -51,9 +50,8 @@ module Simmer
51
50
  simmer_dir: DEFAULT_SIMMER_DIR
52
51
  )
53
52
  configuration = make_configuration(config_path: config_path, simmer_dir: simmer_dir)
54
- fixtures = make_fixtures(configuration)
55
53
  specs = make_specifications(path, configuration.tests_dir)
56
- runner = make_runner(configuration, out, fixtures)
54
+ runner = make_runner(configuration, out)
57
55
  suite = make_suite(configuration, out, runner)
58
56
 
59
57
  suite.run(specs)
@@ -84,14 +82,16 @@ module Simmer
84
82
  end
85
83
  end
86
84
 
87
- def make_runner(configuration, out, fixtures)
88
- database = make_mysql_database(configuration, fixtures)
89
- file_system = make_aws_file_system(configuration)
85
+ def make_runner(configuration, out)
86
+ database = make_mysql_database(configuration)
87
+ file_system = make_file_system(configuration)
88
+ fixture_set = make_fixture_set(configuration)
90
89
  spoon_client = make_spoon_client(configuration)
91
90
 
92
91
  Runner.new(
93
92
  database: database,
94
93
  file_system: file_system,
94
+ fixture_set: fixture_set,
95
95
  out: out,
96
96
  spoon_client: spoon_client
97
97
  )
@@ -103,22 +103,28 @@ module Simmer
103
103
  Database::FixtureSet.new(config)
104
104
  end
105
105
 
106
- def make_mysql_database(configuration, fixtures)
107
- config = (configuration.mysql_database_config || {}).symbolize_keys
106
+ def make_mysql_database(configuration)
107
+ config = configuration.mysql_database_config.symbolize_keys
108
108
  client = Mysql2::Client.new(config)
109
109
  exclude_tables = config[:exclude_tables]
110
110
 
111
- Externals::MysqlDatabase.new(client, exclude_tables, fixtures)
111
+ Externals::MysqlDatabase.new(client, exclude_tables)
112
112
  end
113
113
 
114
- def make_aws_file_system(configuration)
115
- config = (configuration.aws_file_system_config || {}).symbolize_keys
114
+ def make_file_system(configuration)
115
+ if configuration.aws_file_system?
116
+ make_aws_file_system(configuration)
117
+ elsif configuration.local_file_system?
118
+ make_local_file_system(configuration)
119
+ else
120
+ raise ArgumentError, 'cannot determine file system'
121
+ end
122
+ end
116
123
 
117
- client = Aws::S3::Client.new(
118
- access_key_id: config[:access_key_id],
119
- secret_access_key: config[:secret_access_key],
120
- region: config[:region]
121
- )
124
+ def make_aws_file_system(configuration)
125
+ config = configuration.aws_file_system_config.symbolize_keys
126
+ client_args = config.slice(:access_key_id, :secret_access_key, :region)
127
+ client = Aws::S3::Client.new(client_args)
122
128
 
123
129
  Externals::AwsFileSystem.new(
124
130
  client,
@@ -128,25 +134,18 @@ module Simmer
128
134
  )
129
135
  end
130
136
 
131
- def make_spoon_client(configuration)
132
- config = (configuration.spoon_client_config || {}).symbolize_keys
133
-
134
- spoon =
135
- if config[:mock]
136
- SpoonMock.new
137
- elsif config[:mock_err]
138
- SpoonMock.new(false)
139
- else
140
- Pdi::Spoon.new(dir: config[:dir])
141
- end
137
+ def make_local_file_system(configuration)
138
+ config = configuration.local_file_system_config.symbolize_keys
142
139
 
143
- Externals::SpoonClient.new(configuration.files_dir, spoon)
140
+ Externals::LocalFileSystem.new(config[:dir], configuration.files_dir)
144
141
  end
145
142
 
146
- def make_fixtures(configuration)
147
- raw_fixtures = yaml_reader.smash(configuration.fixtures_dir)
143
+ def make_spoon_client(configuration)
144
+ config = (configuration.spoon_client_config || {}).symbolize_keys
145
+ spoon_args = config.slice(:args, :dir, :kitchen, :pan)
146
+ spoon = Pdi::Spoon.new(spoon_args)
148
147
 
149
- Database::FixtureSet.new(raw_fixtures)
148
+ Externals::SpoonClient.new(configuration.files_dir, spoon)
150
149
  end
151
150
 
152
151
  def make_suite(configuration, out, runner)
data/simmer.gemspec CHANGED
@@ -19,7 +19,7 @@ Gem::Specification.new do |s|
19
19
  s.homepage = 'https://github.com/bluemarblepayroll/simmer'
20
20
  s.license = 'MIT'
21
21
 
22
- s.required_ruby_version = '>= 2.4.6'
22
+ s.required_ruby_version = '>= 2.5'
23
23
 
24
24
  s.add_dependency('acts_as_hashable', '~>1')
25
25
  s.add_dependency('aws-sdk-s3', '~>1.6')
@@ -5,3 +5,18 @@ mysql_database:
5
5
  host: 127.0.0.1
6
6
  port: 3306
7
7
  flags: MULTI_STATEMENTS
8
+
9
+ spoon_client:
10
+ dir: spec/mocks/spoon
11
+ args: 0
12
+
13
+ local_file_system:
14
+ dir: tmp/store_test
15
+
16
+ # aws_file_system:
17
+ # access_key_id:
18
+ # bucket:
19
+ # default_expires_in_seconds: 3600
20
+ # encryption: AES256
21
+ # region:
22
+ # secret_access_key:
@@ -27,4 +27,4 @@ assert:
27
27
  first: bruce
28
28
  last: banner
29
29
  - type: output
30
- value: Decoding Agents
30
+ value: output to stdout
@@ -0,0 +1,56 @@
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
+ class AwsS3Client
11
+ extend Forwardable
12
+
13
+ def_delegators :client,
14
+ :list_objects,
15
+ :delete_objects,
16
+ :put_object
17
+
18
+ attr_reader :client, :store
19
+
20
+ def initialize(store = {})
21
+ @store = store
22
+ @client = make_client
23
+
24
+ freeze
25
+ end
26
+
27
+ private
28
+
29
+ # rubocop:disable Metrics/AbcSize
30
+ def make_client
31
+ Aws::S3::Client.new(stub_responses: true).tap do |client|
32
+ client.stub_responses(:get_object, lambda { |context|
33
+ obj = store[context.params[:key]]
34
+ obj || 'NoSuchKey'
35
+ })
36
+
37
+ client.stub_responses(:put_object, lambda { |context|
38
+ store[context.params[:key]] = { body: context.params[:body] }
39
+ {}
40
+ })
41
+
42
+ client.stub_responses(:list_objects, lambda { |_context|
43
+ contents = store.keys.map { |k| OpenStruct.new(key: k) }
44
+
45
+ OpenStruct.new(contents: contents)
46
+ })
47
+
48
+ client.stub_responses(:delete_objects, lambda { |context|
49
+ keys = context.params.dig(:delete, :objects).map { |k| k[:key] }
50
+
51
+ keys.each { |key| store.delete(key) }
52
+ })
53
+ end
54
+ end
55
+ # rubocop:enable Metrics/AbcSize
56
+ end
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require './spec/spec_helper'
5
+ require './spec/db_helper'
6
+
7
+ puts 'output to stdout'
8
+
9
+ db_helper_client.query("UPDATE agents SET first = 'bruce', last = 'banner' WHERE call_sign = 'hulk'")
10
+ db_helper_client.query("UPDATE agents SET first = 'tony', last = 'stark' WHERE call_sign = 'iron_man'")
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require './spec/spec_helper'
5
+ require './spec/db_helper'
6
+
7
+ puts 'bad output!'
8
+
9
+ db_helper_client.query("UPDATE agents SET first = 'bruce', last = 'banner' WHERE call_sign = 'hulk'")
10
+ db_helper_client.query("UPDATE agents SET first = 'tony', last = 'stark' WHERE call_sign = 'iron_man'")
data/spec/mocks/out.rb ADDED
@@ -0,0 +1,14 @@
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
+ class Out
11
+ def puts(msg); end
12
+
13
+ def print(msg); end
14
+ end
@@ -0,0 +1,14 @@
1
+ #!/bin/bash
2
+
3
+ error(){
4
+ echo "$1" >&2
5
+ }
6
+
7
+ output(){
8
+ echo "$1"
9
+ }
10
+
11
+ output "output to stdout"
12
+ error "output to sterr"
13
+
14
+ exit $1
@@ -0,0 +1,14 @@
1
+ #!/bin/bash
2
+
3
+ error(){
4
+ echo "$1" >&2
5
+ }
6
+
7
+ output(){
8
+ echo "$1"
9
+ }
10
+
11
+ output "output to stdout"
12
+ error "output to sterr"
13
+
14
+ exit $1
@@ -8,46 +8,29 @@
8
8
  #
9
9
 
10
10
  require 'spec_helper'
11
+ require 'mocks/aws_s3_client'
11
12
 
12
13
  describe Simmer::Externals::AwsFileSystem do
13
- let(:bucket_store) { {} }
14
14
  let(:bucket_name) { 'test' }
15
15
  let(:encryption) { 'AES256' }
16
16
  let(:files_dir) { File.join('spec', 'fixtures') }
17
17
  let(:specification_path) { File.join('specifications', 'load_noc_list.yaml') }
18
18
  let(:specification_config) { yaml_fixture(specification_path).merge(path: specification_path) }
19
19
  let(:specification) { Simmer::Specification.make(specification_config) }
20
+ let(:aws_s3_client_stub) { AwsS3Client.new }
20
21
 
21
- let(:aws_s3_client_stub) do
22
- Aws::S3::Client.new(stub_responses: true).tap do |client|
23
- client.stub_responses(:get_object, lambda { |context|
24
- obj = bucket_store[context.params[:key]]
25
- obj || 'NoSuchKey'
26
- })
27
-
28
- client.stub_responses(:put_object, lambda { |context|
29
- bucket_store[context.params[:key]] = { body: context.params[:body] }
30
- {}
31
- })
32
-
33
- client.stub_responses(:list_objects, lambda { |_context|
34
- contents = bucket_store.keys.map { |k| OpenStruct.new(key: k) }
35
-
36
- OpenStruct.new(contents: contents)
37
- })
38
-
39
- client.stub_responses(:delete_objects, lambda { |context|
40
- keys = context.params.dig(:delete, :objects).map { |k| k[:key] }
22
+ subject { described_class.new(aws_s3_client_stub, bucket_name, encryption, files_dir) }
41
23
 
42
- keys.each { |key| bucket_store.delete(key) }
43
- })
24
+ describe 'initialization' do
25
+ it "requires bucket ends in 'test'" do
26
+ expect do
27
+ described_class.new(aws_s3_client_stub, 'hehe', encryption, files_dir)
28
+ end.to raise_error(ArgumentError)
44
29
  end
45
30
  end
46
31
 
47
- subject { described_class.new(aws_s3_client_stub, bucket_name, encryption, files_dir) }
48
-
49
32
  specify '#write transfers all files' do
50
- subject.write!(specification)
33
+ subject.write!(specification.stage.files)
51
34
 
52
35
  expected = {
53
36
  'input/noc_list.csv' => {
@@ -55,7 +38,7 @@ describe Simmer::Externals::AwsFileSystem do
55
38
  }
56
39
  }
57
40
 
58
- expect(bucket_store).to eq(expected)
41
+ expect(aws_s3_client_stub.store).to eq(expected)
59
42
  end
60
43
 
61
44
  specify '#clean! deletes all files' do
@@ -70,6 +53,6 @@ describe Simmer::Externals::AwsFileSystem do
70
53
 
71
54
  expected = {}
72
55
 
73
- expect(bucket_store).to eq(expected)
56
+ expect(aws_s3_client_stub.store).to eq(expected)
74
57
  end
75
58
  end
@@ -18,14 +18,24 @@ describe Simmer::Externals::MysqlDatabase do
18
18
  let(:spec_config) { yaml_fixture(spec_path).merge(path: spec_path) }
19
19
  let(:specification) { Simmer::Specification.make(spec_config) }
20
20
 
21
- subject { described_class.new(db_helper_client, exclude_tables, fixture_set) }
21
+ subject { described_class.new(db_helper_client, exclude_tables) }
22
22
 
23
23
  before(:each) do
24
24
  db_helper_clean_schema
25
25
  end
26
26
 
27
+ describe 'initialization' do
28
+ it "requires database ends in 'test'" do
29
+ expect do
30
+ described_class.new(OpenStruct.new(query_options: { database: 'hehe' }))
31
+ end.to raise_error(ArgumentError)
32
+ end
33
+ end
34
+
27
35
  specify '#seed! adds records' do
28
- subject.seed!(specification)
36
+ fixtures = specification.stage.fixtures.map { |f| fixture_set.get!(f) }
37
+
38
+ subject.seed!(fixtures)
29
39
 
30
40
  actual = db_helper_client.query('SELECT * FROM agents ORDER BY call_sign').to_a
31
41
 
@@ -11,57 +11,37 @@ require 'spec_helper'
11
11
  require 'db_helper'
12
12
 
13
13
  describe Simmer::Externals::SpoonClient do
14
- class Mock
15
- attr_reader :result
16
-
17
- def initialize(result)
18
- @result = result
19
- end
20
-
21
- def run(*)
22
- raise Pdi::Spoon::KitchenError, OpenStruct.new(code: 1) if result == 'KitchenError'
23
- raise Pdi::Spoon::PanError, OpenStruct.new(code: 1) if result == 'PanError'
24
-
25
- Pdi::Executor::Result.new(result)
26
- end
27
- end
28
-
29
14
  let(:files_dir) { File.join('spec', 'fixtures') }
30
15
  let(:specification_path) { File.join('specifications', 'load_noc_list.yaml') }
31
16
  let(:specification_config) { yaml_fixture(specification_path).merge(path: specification_path) }
32
17
  let(:specification) { Simmer::Specification.make(specification_config) }
33
18
 
19
+ let(:spoon) do
20
+ Pdi::Spoon.new(
21
+ dir: File.join('spec', 'mocks', 'spoon'),
22
+ args: arg
23
+ )
24
+ end
25
+
34
26
  subject { described_class.new(files_dir, spoon) }
35
27
 
36
28
  context 'when PDI executes successfully' do
37
- let(:spoon) do
38
- Mock.new(
39
- args: [],
40
- status: {
41
- code: 0,
42
- err: 'Some error output from PDI',
43
- out: 'Some output from PDI',
44
- pid: 123
45
- }
46
- )
47
- end
29
+ let(:arg) { 0 }
48
30
 
49
- specify '#run is called with the right arguments' do
50
- expected_path = File.expand_path(File.join(files_dir, 'noc_list.csv'))
31
+ specify '#run returns code 0 from executor' do
32
+ result = subject.run(specification, simmer_config)
33
+
34
+ expect(result.execution_result.code).to eq(0)
35
+ end
36
+ end
51
37
 
52
- args = {
53
- repository: 'top_secret',
54
- name: 'load_noc_list',
55
- params: {
56
- 'input_file' => expected_path,
57
- 'code' => 'The secret code is: '
58
- },
59
- type: 'transformation'
60
- }
38
+ context 'when PDI executes un-successfully' do
39
+ let(:arg) { 1 }
61
40
 
62
- expect(spoon).to receive(:run).with(args)
41
+ specify '#run returns non-zero code from executor' do
42
+ result = subject.run(specification, simmer_config)
63
43
 
64
- subject.run(specification, simmer_config)
44
+ expect(result.execution_result.code).to eq(1)
65
45
  end
66
46
  end
67
47
  end
@@ -21,7 +21,7 @@ describe Simmer::Specification::Assert do
21
21
  expect(subject.assertions.length).to eq(2)
22
22
  expect(subject.assertions.first.name).to eq('agents')
23
23
  expect(subject.assertions.first.record_set.length).to eq(2)
24
- expect(subject.assertions.last.value).to eq('Decoding Agents')
24
+ expect(subject.assertions.last.value).to eq('output to stdout')
25
25
  end
26
26
  end
27
27
  end
@@ -17,6 +17,13 @@ describe Simmer::Util::RecordSet do
17
17
  }
18
18
  end
19
19
 
20
+ let(:string_hash1) do
21
+ {
22
+ 'a' => 'a',
23
+ 'b' => 'b'
24
+ }
25
+ end
26
+
20
27
  let(:hash2) do
21
28
  {
22
29
  c: 'c',
@@ -24,6 +31,13 @@ describe Simmer::Util::RecordSet do
24
31
  }
25
32
  end
26
33
 
34
+ let(:string_hash2) do
35
+ {
36
+ 'c' => 'c',
37
+ 'd' => 'd'
38
+ }
39
+ end
40
+
27
41
  subject { described_class.new([hash1, hash2]) }
28
42
 
29
43
  describe 'equality' do
@@ -38,4 +52,16 @@ describe Simmer::Util::RecordSet do
38
52
  specify '#keys includes all record keys' do
39
53
  expect(subject.keys).to eq(%w[a b c d])
40
54
  end
55
+
56
+ specify '#to_h includes record hashes' do
57
+ expect(subject.to_h).to eq('records' => [string_hash1, string_hash2])
58
+ end
59
+
60
+ describe 'initialization' do
61
+ specify 'can accept a hash' do
62
+ subject = described_class.new(hash1)
63
+
64
+ expect(subject.records.length).to eq(1)
65
+ end
66
+ end
41
67
  end
@@ -0,0 +1,3 @@
1
+ call_sign,first,last
2
+ iron_man,Tony,Stark
3
+ hulk,Bruce,Banner
@@ -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,104 @@
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 'spec_helper'
11
+ require './spec/mocks/out'
12
+
13
+ describe Simmer do
14
+ def stage_simmer_config(spoon_dir, args)
15
+ src_config_path = File.join('spec', 'config', 'simmer.yaml')
16
+ dest_config_dir = File.join('tmp')
17
+ dest_config_path = File.join(dest_config_dir, 'simmer.yaml')
18
+
19
+ FileUtils.rm(dest_config_path) if File.exist?(dest_config_path)
20
+ FileUtils.mkdir_p(dest_config_dir)
21
+
22
+ config = yaml_read(src_config_path)
23
+
24
+ new_config = config.merge('spoon_client' => {
25
+ 'dir' => spoon_dir,
26
+ 'args' => args
27
+ })
28
+
29
+ IO.write(dest_config_path, new_config.to_yaml)
30
+
31
+ dest_config_path
32
+ end
33
+
34
+ context 'when externally mocking pdi and using local file system' do
35
+ let(:spec_path) { File.join('spec', 'fixtures', 'specifications', 'load_noc_list.yaml') }
36
+ let(:simmer_dir) { File.join('spec', 'simmer_spec') }
37
+ let(:out) { Out.new }
38
+ let(:config_path) { stage_simmer_config(spoon_path, args) }
39
+
40
+ context 'when pdi does not do anything but does not fail' do
41
+ let(:spoon_path) { File.join('spec', 'mocks', 'spoon') }
42
+ let(:args) { 0 }
43
+
44
+ specify 'judge determines it does not pass' do
45
+ results = described_class.run(
46
+ spec_path,
47
+ config_path: config_path,
48
+ out: out,
49
+ simmer_dir: simmer_dir
50
+ )
51
+
52
+ expect(results.pass?).to be false
53
+ end
54
+ end
55
+
56
+ context 'when pdi fails' do
57
+ let(:spoon_path) { File.join('spec', 'mocks', 'spoon') }
58
+ let(:args) { 1 }
59
+
60
+ specify 'judge determines it does not pass' do
61
+ results = described_class.run(
62
+ spec_path,
63
+ config_path: config_path,
64
+ out: out,
65
+ simmer_dir: simmer_dir
66
+ )
67
+
68
+ expect(results.pass?).to be false
69
+ end
70
+ end
71
+
72
+ context 'when pdi acts correctly' do
73
+ let(:spoon_path) { File.join('spec', 'mocks', 'load_noc_list') }
74
+ let(:args) { '' }
75
+
76
+ specify 'judge determines it to pass' do
77
+ results = described_class.run(
78
+ spec_path,
79
+ config_path: config_path,
80
+ out: out,
81
+ simmer_dir: simmer_dir
82
+ )
83
+
84
+ expect(results.pass?).to be true
85
+ end
86
+ end
87
+
88
+ context 'when pdi accts correctly but judge fails on output assert' do
89
+ let(:spoon_path) { File.join('spec', 'mocks', 'load_noc_list_bad_output') }
90
+ let(:args) { '' }
91
+
92
+ specify 'judge determines it to pass' do
93
+ results = described_class.run(
94
+ spec_path,
95
+ config_path: config_path,
96
+ out: out,
97
+ simmer_dir: simmer_dir
98
+ )
99
+
100
+ expect(results.pass?).to be false
101
+ end
102
+ end
103
+ end
104
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simmer
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.pre.alpha.5
4
+ version: 1.0.0.pre.alpha.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthew Ruggio
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-03-04 00:00:00.000000000 Z
11
+ date: 2020-03-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: acts_as_hashable
@@ -223,6 +223,8 @@ files:
223
223
  - lib/simmer/database/fixture_set.rb
224
224
  - lib/simmer/externals.rb
225
225
  - lib/simmer/externals/aws_file_system.rb
226
+ - lib/simmer/externals/file_system.rb
227
+ - lib/simmer/externals/local_file_system.rb
226
228
  - lib/simmer/externals/mysql_database.rb
227
229
  - lib/simmer/externals/mysql_database/sql_fixture.rb
228
230
  - lib/simmer/externals/spoon_client.rb
@@ -242,7 +244,6 @@ files:
242
244
  - lib/simmer/specification/assert/assertions/table.rb
243
245
  - lib/simmer/specification/stage.rb
244
246
  - lib/simmer/specification/stage/input_file.rb
245
- - lib/simmer/spoon_mock.rb
246
247
  - lib/simmer/suite.rb
247
248
  - lib/simmer/suite/reporter.rb
248
249
  - lib/simmer/suite/result.rb
@@ -265,6 +266,12 @@ files:
265
266
  - spec/fixtures/yaml_reader/bar.yaml
266
267
  - spec/fixtures/yaml_reader/baz/baz.yaml
267
268
  - spec/fixtures/yaml_reader/foo.yaml
269
+ - spec/mocks/aws_s3_client.rb
270
+ - spec/mocks/load_noc_list/pan.sh
271
+ - spec/mocks/load_noc_list_bad_output/pan.sh
272
+ - spec/mocks/out.rb
273
+ - spec/mocks/spoon/kitchen.sh
274
+ - spec/mocks/spoon/pan.sh
268
275
  - spec/simmer/configuration_spec.rb
269
276
  - spec/simmer/core_ext/hash_spec.rb
270
277
  - spec/simmer/database/fixture_set_spec.rb
@@ -281,6 +288,9 @@ files:
281
288
  - spec/simmer/util/record_set_spec.rb
282
289
  - spec/simmer/util/record_spec.rb
283
290
  - spec/simmer/util/yaml_reader_spec.rb
291
+ - spec/simmer_spec.rb
292
+ - spec/simmer_spec/files/noc_list.csv
293
+ - spec/simmer_spec/fixtures/agent_fixtures.yaml
284
294
  - spec/spec_helper.rb
285
295
  homepage: https://github.com/bluemarblepayroll/simmer
286
296
  licenses:
@@ -294,7 +304,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
294
304
  requirements:
295
305
  - - ">="
296
306
  - !ruby/object:Gem::Version
297
- version: 2.4.6
307
+ version: '2.5'
298
308
  required_rubygems_version: !ruby/object:Gem::Requirement
299
309
  requirements:
300
310
  - - ">"
@@ -317,6 +327,12 @@ test_files:
317
327
  - spec/fixtures/yaml_reader/bar.yaml
318
328
  - spec/fixtures/yaml_reader/baz/baz.yaml
319
329
  - spec/fixtures/yaml_reader/foo.yaml
330
+ - spec/mocks/aws_s3_client.rb
331
+ - spec/mocks/load_noc_list/pan.sh
332
+ - spec/mocks/load_noc_list_bad_output/pan.sh
333
+ - spec/mocks/out.rb
334
+ - spec/mocks/spoon/kitchen.sh
335
+ - spec/mocks/spoon/pan.sh
320
336
  - spec/simmer/configuration_spec.rb
321
337
  - spec/simmer/core_ext/hash_spec.rb
322
338
  - spec/simmer/database/fixture_set_spec.rb
@@ -333,4 +349,7 @@ test_files:
333
349
  - spec/simmer/util/record_set_spec.rb
334
350
  - spec/simmer/util/record_spec.rb
335
351
  - spec/simmer/util/yaml_reader_spec.rb
352
+ - spec/simmer_spec.rb
353
+ - spec/simmer_spec/files/noc_list.csv
354
+ - spec/simmer_spec/fixtures/agent_fixtures.yaml
336
355
  - spec/spec_helper.rb
@@ -1,35 +0,0 @@
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