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

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