leda 0.0.1

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