masamune 0.13.0 → 0.13.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.
- 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
|