masamune 0.13.0 → 0.13.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/masamune/actions/date_parse.rb +1 -1
- data/lib/masamune/commands/postgres_admin.rb +19 -3
- data/lib/masamune/data_plan/rule.rb +14 -5
- data/lib/masamune/schema/fact.rb +14 -3
- data/lib/masamune/schema/table.rb +7 -2
- data/lib/masamune/tasks/dump_thor.rb +12 -5
- data/lib/masamune/template.rb +1 -1
- data/lib/masamune/transform/define_inheritance.psql.erb +28 -0
- data/lib/masamune/transform/define_schema.rb +5 -2
- data/lib/masamune/transform/define_table.psql.erb +23 -8
- data/lib/masamune/transform/define_table.rb +95 -4
- data/lib/masamune/transform/denormalize_table.rb +3 -0
- data/lib/masamune/transform/operator.rb +10 -1
- data/lib/masamune/transform/replace_table.psql.erb +2 -6
- data/lib/masamune/version.rb +1 -1
- data/spec/masamune/commands/postgres_admin_spec.rb +16 -1
- data/spec/masamune/data_plan/engine_spec.rb +2 -2
- data/spec/masamune/data_plan/rule_spec.rb +25 -10
- data/spec/masamune/schema/fact_spec.rb +84 -44
- data/spec/masamune/tasks/dump_thor_spec.rb +46 -6
- data/spec/masamune/thor_spec.rb +12 -27
- data/spec/masamune/transform/define_schema_spec.rb +30 -6
- data/spec/masamune/transform/define_table.fact_spec.rb +11 -0
- data/spec/masamune/transform/define_table.table_spec.rb +106 -18
- data/spec/masamune/transform/denormalize_table_spec.rb +71 -2
- data/spec/masamune/transform/rollup_fact_spec.rb +3 -0
- data/spec/masamune/transform/stage_fact_spec.rb +1 -0
- data/spec/support/rspec/example/task_example_group.rb +17 -0
- metadata +3 -2
@@ -29,6 +29,8 @@ module Masamune::Transform
|
|
29
29
|
columns = options[:include] || []
|
30
30
|
columns += options[:columns] || target.denormalized_column_names
|
31
31
|
columns -= options[:except] || []
|
32
|
+
columns -= ['last_modified_at']
|
33
|
+
columns.uniq!
|
32
34
|
order_by = options[:order] || columns
|
33
35
|
Operator.new(__method__, target: target, columns: columns, order_by: order_by, presenters: { postgres: Common, hive: Common })
|
34
36
|
end
|
@@ -63,6 +65,7 @@ module Masamune::Transform
|
|
63
65
|
column_names.each do |column_name|
|
64
66
|
next unless column = dereference_column_name(column_name)
|
65
67
|
next unless column.reference
|
68
|
+
next if column.reference.degenerate
|
66
69
|
adjacent_reference = references[column.reference.id]
|
67
70
|
next unless adjacent_reference
|
68
71
|
adjacent_column = columns[adjacent_reference.foreign_key_name]
|
@@ -28,6 +28,7 @@ module Masamune::Transform
|
|
28
28
|
@source = options.delete(:source)
|
29
29
|
@target = options.delete(:target)
|
30
30
|
@presenters = options.delete(:presenters) || {}
|
31
|
+
@helper = options.delete(:helper)
|
31
32
|
@locals = options
|
32
33
|
end
|
33
34
|
|
@@ -41,6 +42,14 @@ module Masamune::Transform
|
|
41
42
|
@presenters.key?(target_store.try(:type)) ? @presenters[target_store.try(:type)].new(@target) : @target
|
42
43
|
end
|
43
44
|
|
45
|
+
def helper
|
46
|
+
(@helper || SimpleDelegator).new(self)
|
47
|
+
end
|
48
|
+
|
49
|
+
def locals
|
50
|
+
@locals
|
51
|
+
end
|
52
|
+
|
44
53
|
def to_s
|
45
54
|
result = []
|
46
55
|
@templates.each do |template|
|
@@ -76,7 +85,7 @@ module Masamune::Transform
|
|
76
85
|
def template_eval(template)
|
77
86
|
return File.read(template) if File.exists?(template.to_s) && template.to_s !~ /erb\Z/
|
78
87
|
template_file = File.exists?(template.to_s) ? template : template_file(template)
|
79
|
-
Masamune::Template.render_to_string(template_file, @locals.merge(source: source, target: target))
|
88
|
+
Masamune::Template.render_to_string(template_file, @locals.merge(source: source, target: target, helper: helper))
|
80
89
|
end
|
81
90
|
|
82
91
|
def template_file(template_prefix)
|
@@ -43,12 +43,8 @@ DROP INDEX IF EXISTS <%= index_name %>;
|
|
43
43
|
ALTER TABLE <%= target.name %> RENAME TO <%= target_tmp.name %>;
|
44
44
|
ALTER TABLE <%= source.name %> RENAME TO <%= target.name %>;
|
45
45
|
|
46
|
-
|
47
|
-
|
48
|
-
<%- end -%>
|
49
|
-
<%- if target.constraints -%>
|
50
|
-
ALTER TABLE <%= target.name %> ADD CONSTRAINT <%= target.name %>_time_key_check <%= target.constraints %>;
|
51
|
-
<%- end -%>
|
46
|
+
<%= render 'define_inheritance.psql.erb', target: target %>
|
47
|
+
|
52
48
|
<%= render 'define_foreign_key.psql.erb', target: target, skip_check_exist: true, skip_check_valid: true %>
|
53
49
|
|
54
50
|
<%= render 'define_index.psql.erb', target: target, skip_check_exist: true %>
|
data/lib/masamune/version.rb
CHANGED
@@ -54,6 +54,21 @@ describe Masamune::Commands::PostgresAdmin do
|
|
54
54
|
it { is_expected.to eq(['dropdb', '--if-exists', '--host=localhost', '--username=postgres', '--no-password', 'zombo']) }
|
55
55
|
end
|
56
56
|
|
57
|
+
context 'action :drop with database and :output' do
|
58
|
+
let(:attrs) { {action: :drop, database: 'zombo', output: 'zombo.csv'} }
|
59
|
+
it { is_expected.to eq(['dropdb', '--if-exists', '--host=localhost', '--username=postgres', '--no-password', 'zombo']) }
|
60
|
+
end
|
61
|
+
|
62
|
+
context 'action :dump with database' do
|
63
|
+
let(:attrs) { {action: :dump, database: 'zombo'} }
|
64
|
+
it { is_expected.to eq(['pg_dump', '--no-owner', '--no-privileges', '--oids', '--schema=public', '--host=localhost', '--username=postgres', '--no-password', '--dbname=zombo']) }
|
65
|
+
end
|
66
|
+
|
67
|
+
context 'action :dump with database and :output' do
|
68
|
+
let(:attrs) { {action: :dump, database: 'zombo', output: 'zombo.csv'} }
|
69
|
+
it { is_expected.to eq(['pg_dump', '--no-owner', '--no-privileges', '--oids', '--schema=public', '--host=localhost', '--username=postgres', '--no-password', '--dbname=zombo', '--file=zombo.csv']) }
|
70
|
+
end
|
71
|
+
|
57
72
|
context 'action :drop without database' do
|
58
73
|
let(:attrs) { {action: :drop} }
|
59
74
|
it { expect { subject }.to raise_error ArgumentError, ':database must be given' }
|
@@ -61,7 +76,7 @@ describe Masamune::Commands::PostgresAdmin do
|
|
61
76
|
|
62
77
|
context 'action unfuddle with database' do
|
63
78
|
let(:attrs) { {action: :unfuddle, database: 'zombo'} }
|
64
|
-
it { expect { subject }.to raise_error ArgumentError, ':action must be :create or :
|
79
|
+
it { expect { subject }.to raise_error ArgumentError, ':action must be :create, :drop, or :dump' }
|
65
80
|
end
|
66
81
|
end
|
67
82
|
|
@@ -177,7 +177,7 @@ describe Masamune::DataPlan::Engine do
|
|
177
177
|
context 'invalid target' do
|
178
178
|
let(:rule) { 'derived_daily' }
|
179
179
|
let(:target) { '/table/y=2013/m=01/d=01' }
|
180
|
-
it { expect { subject }.to raise_error }
|
180
|
+
it { expect { subject }.to raise_error /Cannot bind_input/ }
|
181
181
|
end
|
182
182
|
end
|
183
183
|
|
@@ -206,7 +206,7 @@ describe Masamune::DataPlan::Engine do
|
|
206
206
|
|
207
207
|
context 'invalid target' do
|
208
208
|
let(:target) { '/daily' }
|
209
|
-
it { expect { subject }.to raise_error }
|
209
|
+
it { expect { subject }.to raise_error /No rule matches/ }
|
210
210
|
end
|
211
211
|
end
|
212
212
|
|
@@ -47,30 +47,45 @@ describe Masamune::DataPlan::Rule do
|
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
50
|
-
describe '#
|
51
|
-
subject(:elem) { instance.
|
50
|
+
describe '#bind_date_or_time' do
|
51
|
+
subject(:elem) { instance.bind_date_or_time(input) }
|
52
52
|
|
53
|
-
context 'with
|
54
|
-
let(:
|
53
|
+
context 'with nil input' do
|
54
|
+
let(:input) { nil }
|
55
|
+
it { expect { elem }.to raise_error ArgumentError }
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'with unknown input type' do
|
59
|
+
let(:input) { 1 }
|
60
|
+
it { expect { elem }.to raise_error ArgumentError }
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'with DateTime input' do
|
64
|
+
let(:input) { DateTime.civil(2013,04,05,23,13) }
|
55
65
|
|
56
66
|
describe '#path' do
|
57
67
|
subject { elem.path }
|
58
68
|
it { is_expected.to eq('report/2013-04-05/23') }
|
59
69
|
end
|
60
|
-
let(:start_time) { DateTime.civil(2013,04,05,23) }
|
61
|
-
let(:stop_time) { DateTime.civil(2013,04,05,0) }
|
62
70
|
end
|
63
71
|
|
64
|
-
context 'with unix timestamp pattern' do
|
72
|
+
context 'with DateTime input and unix timestamp pattern' do
|
65
73
|
let(:pattern) { 'logs/%H-s.log' }
|
66
|
-
let(:
|
74
|
+
let(:input) { DateTime.civil(2013,04,05,23,13) }
|
67
75
|
|
68
76
|
describe '#path' do
|
69
77
|
subject { elem.path }
|
70
78
|
it { is_expected.to eq('logs/1365202800.log') }
|
71
79
|
end
|
72
|
-
|
73
|
-
|
80
|
+
end
|
81
|
+
|
82
|
+
context 'with Date input' do
|
83
|
+
let(:input) { Date.civil(2013,04,05) }
|
84
|
+
|
85
|
+
describe '#path' do
|
86
|
+
subject { elem.path }
|
87
|
+
it { is_expected.to eq('report/2013-04-05/00') }
|
88
|
+
end
|
74
89
|
end
|
75
90
|
end
|
76
91
|
|
@@ -40,7 +40,18 @@ describe Masamune::Schema::Fact do
|
|
40
40
|
]
|
41
41
|
end
|
42
42
|
|
43
|
-
let(:
|
43
|
+
let(:fact_without_partition) do
|
44
|
+
described_class.new id: 'visits', store: store,
|
45
|
+
references: [
|
46
|
+
Masamune::Schema::TableReference.new(date_dimension),
|
47
|
+
Masamune::Schema::TableReference.new(user_dimension)
|
48
|
+
],
|
49
|
+
columns: [
|
50
|
+
Masamune::Schema::Column.new(id: 'total', type: :integer)
|
51
|
+
]
|
52
|
+
end
|
53
|
+
|
54
|
+
let(:fact_with_partition) do
|
44
55
|
described_class.new id: 'visits', store: store, partition: 'y%Ym%m',
|
45
56
|
references: [
|
46
57
|
Masamune::Schema::TableReference.new(date_dimension),
|
@@ -53,36 +64,22 @@ describe Masamune::Schema::Fact do
|
|
53
64
|
]
|
54
65
|
end
|
55
66
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
it { expect(partition_table.range.start_date).to eq(date.utc.to_date) }
|
66
|
-
|
67
|
-
describe '#stage_table' do
|
68
|
-
subject(:stage_table) { partition_table.stage_table }
|
69
|
-
|
70
|
-
it { expect(stage_table.store.id).to eq(store.id) }
|
71
|
-
it { expect(stage_table.name).to eq('visits_fact_y2015m01_stage') }
|
72
|
-
it { expect(stage_table.range.start_date).to eq(date.utc.to_date) }
|
73
|
-
|
74
|
-
context 'with optional suffix' do
|
75
|
-
subject(:stage_table) { partition_table.stage_table(suffix: 'tmp') }
|
76
|
-
|
77
|
-
it 'should append suffix to id' do
|
78
|
-
expect(stage_table.store.id).to eq(store.id)
|
79
|
-
expect(stage_table.name).to eq('visits_fact_y2015m01_stage_tmp')
|
80
|
-
expect(stage_table.range.start_date).to eq(date.utc.to_date)
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
67
|
+
let(:fact_with_partition_and_hourly_grain) do
|
68
|
+
described_class.new id: 'visits', store: store, grain: :hourly, partition: 'y%Ym%m',
|
69
|
+
references: [
|
70
|
+
Masamune::Schema::TableReference.new(date_dimension),
|
71
|
+
Masamune::Schema::TableReference.new(user_dimension)
|
72
|
+
],
|
73
|
+
columns: [
|
74
|
+
Masamune::Schema::Column.new(id: 'total', type: :integer)
|
75
|
+
]
|
84
76
|
end
|
85
77
|
|
78
|
+
it { expect(fact_without_partition.name).to eq('visits_fact') }
|
79
|
+
it { expect(fact_with_partition.name).to eq('visits_fact') }
|
80
|
+
it { expect(fact_with_partition_and_hourly_grain.id).to eq(:visits_hourly) }
|
81
|
+
it { expect(fact_with_partition_and_hourly_grain.name).to eq('visits_hourly_fact') }
|
82
|
+
|
86
83
|
context 'fact with unknown grain' do
|
87
84
|
subject(:fact) do
|
88
85
|
described_class.new id: 'visits', grain: :quarterly
|
@@ -91,25 +88,44 @@ describe Masamune::Schema::Fact do
|
|
91
88
|
it { expect { fact }.to raise_error ArgumentError, "unknown grain 'quarterly'" }
|
92
89
|
end
|
93
90
|
|
94
|
-
|
95
|
-
let(:
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
Masamune::Schema::Column.new(id: 'total', type: :integer)
|
103
|
-
]
|
91
|
+
describe '#partition_table' do
|
92
|
+
let(:date) { Chronic.parse('2015-01-01') }
|
93
|
+
subject(:partition_table) { fact.partition_table(date) }
|
94
|
+
|
95
|
+
context 'fact without partition' do
|
96
|
+
let(:fact) { fact_without_partition }
|
97
|
+
|
98
|
+
it { expect(partition_table).to be_nil }
|
104
99
|
end
|
105
100
|
|
106
|
-
|
107
|
-
|
101
|
+
context 'fact with partition' do
|
102
|
+
let(:fact) { fact_with_partition }
|
103
|
+
|
104
|
+
it { expect(partition_table.store.id).to eq(store.id) }
|
105
|
+
it { expect(partition_table.name).to eq('visits_fact_y2015m01') }
|
106
|
+
it { expect(partition_table.range.start_date).to eq(date.utc.to_date) }
|
107
|
+
|
108
|
+
describe '#stage_table' do
|
109
|
+
subject(:stage_table) { partition_table.stage_table }
|
110
|
+
|
111
|
+
it { expect(stage_table.store.id).to eq(store.id) }
|
112
|
+
it { expect(stage_table.name).to eq('visits_fact_y2015m01_stage') }
|
113
|
+
it { expect(stage_table.range.start_date).to eq(date.utc.to_date) }
|
114
|
+
|
115
|
+
context 'with optional suffix' do
|
116
|
+
subject(:stage_table) { partition_table.stage_table(suffix: 'tmp') }
|
108
117
|
|
109
|
-
|
110
|
-
|
118
|
+
it 'should append suffix to id' do
|
119
|
+
expect(stage_table.store.id).to eq(store.id)
|
120
|
+
expect(stage_table.name).to eq('visits_fact_y2015m01_stage_tmp')
|
121
|
+
expect(stage_table.range.start_date).to eq(date.utc.to_date)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
111
126
|
|
112
|
-
|
127
|
+
context 'fact with partition and hourly grain' do
|
128
|
+
let(:fact) { fact_with_partition_and_hourly_grain }
|
113
129
|
|
114
130
|
it { expect(partition_table.store.id).to eq(store.id) }
|
115
131
|
it { expect(partition_table.name).to eq('visits_hourly_fact_y2015m01') }
|
@@ -126,4 +142,28 @@ describe Masamune::Schema::Fact do
|
|
126
142
|
end
|
127
143
|
end
|
128
144
|
end
|
145
|
+
|
146
|
+
describe '#partition_tables' do
|
147
|
+
let(:start_date) { Date.civil(2015, 01, 01) }
|
148
|
+
let(:stop_date) { Date.civil(2015, 03, 15) }
|
149
|
+
|
150
|
+
subject(:partition_tables) { fact.partition_tables(start_date, stop_date) }
|
151
|
+
|
152
|
+
context 'fact without partition' do
|
153
|
+
let(:fact) { fact_without_partition }
|
154
|
+
|
155
|
+
it { expect(partition_tables).to be_nil }
|
156
|
+
end
|
157
|
+
|
158
|
+
context 'fact with partition' do
|
159
|
+
let(:fact) { fact_with_partition }
|
160
|
+
|
161
|
+
it 'yields partition tables' do
|
162
|
+
expect { |b| fact.partition_tables(start_date, stop_date, &b) }.to yield_successive_args \
|
163
|
+
fact.partition_table(Date.civil(2015, 01, 01)),
|
164
|
+
fact.partition_table(Date.civil(2015, 02, 01)),
|
165
|
+
fact.partition_table(Date.civil(2015, 03, 01))
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
129
169
|
end
|
@@ -32,11 +32,51 @@ describe Masamune::Tasks::DumpThor do
|
|
32
32
|
end
|
33
33
|
|
34
34
|
context 'with no arguments' do
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
35
|
+
it_behaves_like 'executes with success'
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'with --type=psql' do
|
39
|
+
let(:options) { ['--type=psql'] }
|
40
|
+
it_behaves_like 'executes with success'
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'with --type=hql' do
|
44
|
+
let(:options) { ['--type=hql'] }
|
45
|
+
it_behaves_like 'executes with success'
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'with --type=unknown' do
|
49
|
+
let(:options) { ['--type=unknown'] }
|
50
|
+
it_behaves_like 'raises Thor::MalformattedArgumentError', %q{Expected '--type' to be one of psql, hql; got unknown}
|
51
|
+
end
|
52
|
+
|
53
|
+
context 'with --section=pre' do
|
54
|
+
let(:options) { ['--section=pre'] }
|
55
|
+
it_behaves_like 'executes with success'
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'with --section=post' do
|
59
|
+
let(:options) { ['--section=post'] }
|
60
|
+
it_behaves_like 'executes with success'
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'with --section=all' do
|
64
|
+
let(:options) { ['--section=all'] }
|
65
|
+
it_behaves_like 'executes with success'
|
66
|
+
end
|
67
|
+
|
68
|
+
context 'with --section=unknown' do
|
69
|
+
let(:options) { ['--section=unknown'] }
|
70
|
+
it_behaves_like 'raises Thor::MalformattedArgumentError', %q{Expected '--section' to be one of pre, post, all; got unknown}
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'with --start=yesterday' do
|
74
|
+
let(:options) { ['--start=yesterday'] }
|
75
|
+
it_behaves_like 'executes with success'
|
76
|
+
end
|
77
|
+
|
78
|
+
context 'with --stop=today' do
|
79
|
+
let(:options) { ['--stop=today'] }
|
80
|
+
it_behaves_like 'executes with success'
|
41
81
|
end
|
42
82
|
end
|
data/spec/masamune/thor_spec.rb
CHANGED
@@ -99,43 +99,44 @@ describe Masamune::Thor do
|
|
99
99
|
|
100
100
|
context 'with command and no input options' do
|
101
101
|
let(:command) { 'command' }
|
102
|
-
|
102
|
+
it_behaves_like 'raises Thor::RequiredArgumentMissingError', /No value provided for required options '--start'/
|
103
103
|
end
|
104
104
|
|
105
105
|
context 'with command and invalid --start' do
|
106
106
|
let(:command) { 'command' }
|
107
107
|
let(:options) { ['--start', 'xxx'] }
|
108
|
-
|
108
|
+
it_behaves_like 'raises Thor::MalformattedArgumentError', /Expected date time value for '--start'; got/
|
109
109
|
end
|
110
110
|
|
111
111
|
context 'with command and invalid --stop' do
|
112
112
|
let(:command) { 'command' }
|
113
113
|
let(:options) { ['--start', '2013-01-01', '--stop', 'xxx'] }
|
114
|
-
|
114
|
+
it_behaves_like 'raises Thor::MalformattedArgumentError', /Expected date time value for '--stop'; got/
|
115
115
|
end
|
116
116
|
|
117
117
|
context 'with command and invalid --sources' do
|
118
118
|
let(:command) { 'command' }
|
119
119
|
let(:options) { ['--sources', 'foo'] }
|
120
|
-
|
120
|
+
it_behaves_like 'raises Thor::MalformattedArgumentError', /Expected file value for '--sources'; got/
|
121
121
|
end
|
122
122
|
|
123
123
|
context 'with command and invalid --targets' do
|
124
124
|
let(:command) { 'command' }
|
125
125
|
let(:options) { ['--targets', 'foo'] }
|
126
|
-
|
126
|
+
it_behaves_like 'raises Thor::MalformattedArgumentError', /Expected file value for '--targets'; got/
|
127
127
|
end
|
128
128
|
|
129
129
|
context 'with command and both --sources and --targets' do
|
130
130
|
let(:command) { 'command' }
|
131
131
|
let(:options) { ['--sources', 'sources', '--targets', 'targets'] }
|
132
|
-
|
132
|
+
|
133
|
+
it_behaves_like 'raises Thor::MalformattedArgumentError', /Cannot specify both option '--sources' and option '--targets'/
|
133
134
|
end
|
134
135
|
|
135
136
|
context 'with command and --start and bad --config file' do
|
136
137
|
let(:command) { 'command' }
|
137
138
|
let(:options) { ['--start', '2013-01-01', '--config', 'xxx'] }
|
138
|
-
|
139
|
+
it_behaves_like 'raises Thor::MalformattedArgumentError', /Could not load file provided for '--config'/
|
139
140
|
end
|
140
141
|
|
141
142
|
context 'with command and --start and missing system --config file' do
|
@@ -144,7 +145,7 @@ describe Masamune::Thor do
|
|
144
145
|
before do
|
145
146
|
expect_any_instance_of(Masamune::Filesystem).to receive(:resolve_file)
|
146
147
|
end
|
147
|
-
|
148
|
+
it_behaves_like 'raises Thor::RequiredArgumentMissingError', /Option --config or valid system configuration file required/
|
148
149
|
end
|
149
150
|
|
150
151
|
context 'with command and -- --extra --args' do
|
@@ -153,35 +154,19 @@ describe Masamune::Thor do
|
|
153
154
|
before do
|
154
155
|
expect_any_instance_of(thor_class).to receive(:extra=).with(['--extra', '--args'])
|
155
156
|
end
|
156
|
-
|
157
|
-
expect { cli_invocation }.to raise_error SystemExit
|
158
|
-
end
|
157
|
+
it_behaves_like 'executes with success'
|
159
158
|
end
|
160
159
|
|
161
160
|
context 'with command and --start' do
|
162
161
|
let(:command) { 'command' }
|
163
162
|
let(:options) { ['--start', '2013-01-01'] }
|
164
|
-
|
165
|
-
expect { cli_invocation }.to raise_error { |e|
|
166
|
-
expect(e).to be_a(SystemExit)
|
167
|
-
expect(e.status).to eq(0)
|
168
|
-
}
|
169
|
-
expect(stdout.string).to match(/\AUsing '.*' for --start/)
|
170
|
-
expect(stderr.string).to eq('')
|
171
|
-
end
|
163
|
+
it_behaves_like 'executes with success'
|
172
164
|
end
|
173
165
|
|
174
166
|
context 'with command and natural language --start' do
|
175
167
|
let(:command) { 'command' }
|
176
168
|
let(:options) { ['--start', 'yesterday'] }
|
177
|
-
|
178
|
-
expect { cli_invocation }.to raise_error { |e|
|
179
|
-
expect(e).to be_a(SystemExit)
|
180
|
-
expect(e.status).to eq(0)
|
181
|
-
}
|
182
|
-
expect(stdout.string).to match(/\AUsing '.*' for --start/)
|
183
|
-
expect(stderr.string).to eq('')
|
184
|
-
end
|
169
|
+
it_behaves_like 'executes with success'
|
185
170
|
end
|
186
171
|
|
187
172
|
context 'with command that raises exception before initialization' do
|