leda 0.0.1

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.
@@ -0,0 +1,3 @@
1
+ module Leda
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,101 @@
1
+ require 'spec_helper'
2
+
3
+ module Leda
4
+ describe Configuration do
5
+ let(:configuration) { Configuration.new }
6
+
7
+ describe 'defined from DSL' do
8
+ let(:actual) do
9
+ Configuration.new do |leda|
10
+ leda.data_unit 'providers' do |c|
11
+ c.postgresql tables: %w(practices offices practitioners)
12
+ c.elasticsearch indexes: %w(sst-practitioners)
13
+ end
14
+
15
+ leda.data_unit 'groups' do |c|
16
+ c.postgresql tables: %w(groups mentioned practitioners)
17
+ end
18
+ end
19
+ end
20
+
21
+ it 'produces the expected data units' do
22
+ expect(actual.data_units.map(&:name)).to eq(%w(providers groups))
23
+ end
24
+
25
+ it 'produces appropriate stores for each data unit' do
26
+ providers_data_unit = actual.data_units.first
27
+
28
+ expect(providers_data_unit.stores.map(&:class)).
29
+ to eq([Stores::Postgresql, Stores::Elasticsearch])
30
+ end
31
+
32
+ it 'passes the configuration parameters to each store' do
33
+ providers_postgresql_store = actual.data_units.first.stores.first
34
+
35
+ expect(providers_postgresql_store.options).to eq({ tables: %w(practices offices practitioners) })
36
+ end
37
+ end
38
+
39
+ describe '#update' do
40
+ it 'adds to the existing configuration' do
41
+ configuration.update do |leda|
42
+ leda.data_unit 'lookups' do |d|
43
+ d.postgresql tables: %w(zip_codes)
44
+ end
45
+ end
46
+
47
+ configuration.update do |leda|
48
+ leda.data_unit 'people' do |d|
49
+ d.postgresql tables: %w(people phone_numbers street_addresses)
50
+ end
51
+ end
52
+
53
+ expect(configuration.data_units.map(&:name)).to eq(%w(lookups people))
54
+ end
55
+
56
+ it 'returns the configuration' do
57
+ expect(configuration.update { }).to eql(configuration)
58
+ end
59
+ end
60
+
61
+ describe '#project_root_dir=' do
62
+ it 'coerces a string into a Pathname' do
63
+ configuration.project_root_dir = '/foo/quux'
64
+
65
+ expect(configuration.project_root_dir).to eq(Pathname.new('/foo/quux'))
66
+ end
67
+
68
+ it 'leaves a Pathname alone' do
69
+ configuration.project_root_dir = Pathname.new('/bar/baz')
70
+ expect(configuration.project_root_dir).to eq(Pathname.new('/bar/baz'))
71
+ end
72
+ end
73
+
74
+ describe '#base_path' do
75
+ it 'defaults to db/leda' do
76
+ expect(configuration.base_path).to eq(Pathname.new('db/leda'))
77
+ end
78
+ end
79
+
80
+ describe '#base_path=' do
81
+ it 'coerces a string into a Pathname' do
82
+ configuration.base_path = 'foo/quux'
83
+
84
+ expect(configuration.base_path).to eq(Pathname.new('foo/quux'))
85
+ end
86
+
87
+ it 'leaves a Pathname alone' do
88
+ configuration.base_path = Pathname.new('bar/baz')
89
+ expect(configuration.base_path).to eq(Pathname.new('bar/baz'))
90
+ end
91
+ end
92
+
93
+ describe '#base_dir' do
94
+ it 'is the combination of the project root and the base path' do
95
+ configuration.project_root_dir = '/app-root'
96
+ configuration.base_path = 'db-data'
97
+ expect(configuration.base_dir).to eq(Pathname.new('/app-root/db-data'))
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,86 @@
1
+ require 'spec_helper'
2
+ require 'rake'
3
+
4
+ module Leda
5
+ describe Rake do
6
+ let(:configuration) {
7
+ Configuration.new do |leda|
8
+ leda.data_unit 'tlus' do |du|
9
+ du.mock_c
10
+ end
11
+
12
+ leda.data_unit 'people' do |du|
13
+ du.mock_a
14
+ du.mock_b
15
+ end
16
+ end
17
+ }
18
+
19
+ before do
20
+ ::Rake.application = ::Rake::Application.new
21
+ Leda::Rake.define_tasks(configuration, [:outside_prereq])
22
+ end
23
+
24
+ after do
25
+ ::Rake.application.clear
26
+ end
27
+
28
+ shared_examples 'a Leda task' do
29
+ it 'exists' do
30
+ expect { task }.to_not raise_error
31
+ end
32
+
33
+ it 'has a description' do
34
+ expect(task.comment).not_to be_nil
35
+ end
36
+
37
+ it 'depends on the supplied prereqs' do
38
+ expect(task.prerequisites).to eq(%w(outside_prereq))
39
+ end
40
+ end
41
+
42
+ shared_examples 'a restore_from task' do
43
+ it_behaves_like 'a Leda task'
44
+
45
+ it 'has a source_env argument' do
46
+ expect(task.arg_names).to eq([:source_env])
47
+ end
48
+ end
49
+
50
+ describe 'the all:dump task' do
51
+ let(:task) { ::Rake::Task['dump'] }
52
+
53
+ it_behaves_like 'a Leda task'
54
+ end
55
+
56
+ describe 'an individual unit dump task' do
57
+ let(:task) { ::Rake::Task['people:dump'] }
58
+
59
+ it_behaves_like 'a Leda task'
60
+ end
61
+
62
+ describe 'an individual store dump task' do
63
+ let(:task) { ::Rake::Task['tlus:mock_c:dump'] }
64
+
65
+ it_behaves_like 'a Leda task'
66
+ end
67
+
68
+ describe 'the all:restore_from task' do
69
+ let(:task) { ::Rake::Task['restore_from'] }
70
+
71
+ it_behaves_like 'a restore_from task'
72
+ end
73
+
74
+ describe 'an individual unit restore_from task' do
75
+ let(:task) { ::Rake::Task['tlus:restore_from'] }
76
+
77
+ it_behaves_like 'a restore_from task'
78
+ end
79
+
80
+ describe 'an individual store restore_from task' do
81
+ let(:task) { ::Rake::Task['people:mock_b:restore_from'] }
82
+
83
+ it_behaves_like 'a restore_from task'
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,194 @@
1
+ require 'spec_helper'
2
+
3
+ module Leda
4
+ describe Runner do
5
+ let(:root) { spec_tmpdir }
6
+ let(:root_s) { root.to_s }
7
+
8
+ let(:configuration) {
9
+ Configuration.new do |leda|
10
+ leda.project_root_dir = root
11
+ leda.base_path = 'base'
12
+
13
+ leda.data_unit 'tlus' do |du|
14
+ du.mock_c
15
+ du.mock_b
16
+ end
17
+
18
+ leda.data_unit 'people' do |du|
19
+ du.mock_a
20
+ du.mock_b
21
+ end
22
+ end
23
+ }
24
+
25
+ let(:runner) { Runner.new('dev', configuration) }
26
+
27
+ describe '#dump' do
28
+ let(:actual_calls) {
29
+ calls = []
30
+ configuration.data_units.each do |data_unit|
31
+ data_unit.stores.each do |store|
32
+ unless store.dump_directories.empty?
33
+ calls << [data_unit.name, store.name, store.dump_directories.map(&:to_s)]
34
+ end
35
+ end
36
+ end
37
+ calls
38
+ }
39
+
40
+ describe 'with no args' do
41
+ before do
42
+ runner.dump
43
+ end
44
+
45
+ it 'runs dump on every configured store' do
46
+ expect(actual_calls).to eq([
47
+ ['tlus', 'mock_c', [root_s + '/base/dev/tlus/mock_c']],
48
+ ['tlus', 'mock_b', [root_s + '/base/dev/tlus/mock_b']],
49
+ ['people', 'mock_a', [root_s + '/base/dev/people/mock_a']],
50
+ ['people', 'mock_b', [root_s + '/base/dev/people/mock_b']]
51
+ ])
52
+ end
53
+ end
54
+
55
+ describe 'with just a data unit name' do
56
+ before do
57
+ runner.dump('people')
58
+ end
59
+
60
+ it 'runs dump on every store in that unit' do
61
+ expect(actual_calls).to eq([
62
+ ['people', 'mock_a', [root_s + '/base/dev/people/mock_a']],
63
+ ['people', 'mock_b', [root_s + '/base/dev/people/mock_b']]
64
+ ])
65
+ end
66
+ end
67
+
68
+ describe 'with just a store name' do
69
+ before do
70
+ runner.dump(nil, 'mock_b')
71
+ end
72
+
73
+ it 'runs dump on every store of that type' do
74
+ expect(actual_calls).to eq([
75
+ ['tlus', 'mock_b', [root_s + '/base/dev/tlus/mock_b']],
76
+ ['people', 'mock_b', [root_s + '/base/dev/people/mock_b']]
77
+ ])
78
+ end
79
+ end
80
+
81
+ describe 'with both a data unit and a store name' do
82
+ before do
83
+ runner.dump('tlus', 'mock_b')
84
+ end
85
+
86
+ it 'runs dump on just that combination' do
87
+ expect(actual_calls).to eq([
88
+ ['tlus', 'mock_b', [root_s + '/base/dev/tlus/mock_b']]
89
+ ])
90
+ end
91
+ end
92
+
93
+ describe 'with an unknown data unit' do
94
+ it 'throws an exception' do
95
+ expect { runner.dump('frogs', 'mock_a') }.to raise_error(/No data configured that matches frogs:mock_a/)
96
+ end
97
+ end
98
+
99
+ describe 'with an unused or unknown store' do
100
+ it 'throws an exception' do
101
+ expect { runner.dump('people', 'mock_c') }.to raise_error(/No data configured that matches people:mock_c/)
102
+ end
103
+ end
104
+ end
105
+
106
+ describe '#dump_relative_paths' do
107
+ it 'returns the set of paths for the selected parameters' do
108
+ expect(runner.dump_relative_paths('people').map(&:to_s)).to eq([
109
+ 'base/dev/people/mock_a',
110
+ 'base/dev/people/mock_b'
111
+ ])
112
+ end
113
+ end
114
+
115
+ describe '#restore_from' do
116
+ let(:actual_calls) {
117
+ calls = []
118
+ configuration.data_units.each do |data_unit|
119
+ data_unit.stores.each do |store|
120
+ unless store.restore_from_directories.empty?
121
+ calls << [data_unit.name, store.name, store.restore_from_directories.map(&:to_s)]
122
+ end
123
+ end
124
+ end
125
+ calls
126
+ }
127
+
128
+ describe 'with no args' do
129
+ before do
130
+ runner.restore_from('prod')
131
+ end
132
+
133
+ it 'runs restore_from on every configured store' do
134
+ expect(actual_calls).to eq([
135
+ ['tlus', 'mock_c', [root_s + '/base/prod/tlus/mock_c']],
136
+ ['tlus', 'mock_b', [root_s + '/base/prod/tlus/mock_b']],
137
+ ['people', 'mock_a', [root_s + '/base/prod/people/mock_a']],
138
+ ['people', 'mock_b', [root_s + '/base/prod/people/mock_b']]
139
+ ])
140
+ end
141
+ end
142
+
143
+ describe 'with just a data unit name' do
144
+ before do
145
+ runner.restore_from('stg', 'people')
146
+ end
147
+
148
+ it 'runs restore_from on every store in that unit' do
149
+ expect(actual_calls).to eq([
150
+ ['people', 'mock_a', [root_s + '/base/stg/people/mock_a']],
151
+ ['people', 'mock_b', [root_s + '/base/stg/people/mock_b']]
152
+ ])
153
+ end
154
+ end
155
+
156
+ describe 'with just a store name' do
157
+ before do
158
+ runner.restore_from('local', nil, 'mock_b')
159
+ end
160
+
161
+ it 'runs restore_from on every store of that type' do
162
+ expect(actual_calls).to eq([
163
+ ['tlus', 'mock_b', [root_s + '/base/local/tlus/mock_b']],
164
+ ['people', 'mock_b', [root_s + '/base/local/people/mock_b']]
165
+ ])
166
+ end
167
+ end
168
+
169
+ describe 'with both a data unit and a store name' do
170
+ before do
171
+ runner.restore_from('super-prod', 'tlus', 'mock_b')
172
+ end
173
+
174
+ it 'runs restore_from on just that combination' do
175
+ expect(actual_calls).to eq([
176
+ ['tlus', 'mock_b', [root_s + '/base/super-prod/tlus/mock_b']]
177
+ ])
178
+ end
179
+ end
180
+
181
+ describe 'with an unknown data unit' do
182
+ it 'throws an exception' do
183
+ expect { runner.restore_from('prod', 'frogs', 'mock_a') }.to raise_error(/No data configured that matches frogs:mock_a/)
184
+ end
185
+ end
186
+
187
+ describe 'with an unused or unknown store' do
188
+ it 'throws an exception' do
189
+ expect { runner.restore_from('prod', 'people', 'mock_c') }.to raise_error(/No data configured that matches people:mock_c/)
190
+ end
191
+ end
192
+ end
193
+ end
194
+ end
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ describe Leda, "::VERSION" do
4
+ it "exists" do
5
+ expect { Leda::VERSION }.not_to raise_error
6
+ end
7
+
8
+ it "has 3 or 4 dot separated parts" do
9
+ expect(Leda::VERSION.split('.').size).to be_between(3, 4)
10
+ end
11
+ end
@@ -0,0 +1,14 @@
1
+ require 'rspec'
2
+
3
+ $LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
4
+ require 'leda'
5
+
6
+ Dir[File.expand_path('../support/*.rb', __FILE__)].each do |support|
7
+ require support
8
+ end
9
+
10
+ RSpec.configure do |config|
11
+ config.include Leda::Spec::Tmpdir
12
+
13
+ config.after { rm_tmpdir }
14
+ end
@@ -0,0 +1,29 @@
1
+ class RecordingStore
2
+ include Leda::Store
3
+
4
+ def dump_directories
5
+ @dump_directories ||= []
6
+ end
7
+
8
+ def restore_from_directories
9
+ @restore_from_directories ||= []
10
+ end
11
+
12
+ def dump(directory)
13
+ dump_directories << directory
14
+ end
15
+
16
+ def restore_from(directory)
17
+ restore_from_directories << directory
18
+ end
19
+ end
20
+
21
+ %w(mock_a mock_b mock_c).each do |mock_name|
22
+ store = Class.new(RecordingStore)
23
+ store.class_eval <<-DEF
24
+ def name
25
+ #{mock_name.inspect}
26
+ end
27
+ DEF
28
+ Leda::Store.register_store(store, mock_name)
29
+ end
@@ -0,0 +1,18 @@
1
+ require 'pathname'
2
+
3
+ module Leda::Spec
4
+ module Tmpdir
5
+ def spec_tmpdir(path=nil)
6
+ @spec_tmpdir ||= Pathname.new(File.expand_path("../../spec/tmp", __FILE__))
7
+ full = path ? @spec_tmpdir.join(path) : @spec_tmpdir
8
+ full.mkpath
9
+ full
10
+ end
11
+
12
+ def rm_tmpdir
13
+ if @spec_tempdir
14
+ @spec_tempdir.rmtree
15
+ end
16
+ end
17
+ end
18
+ end