data_task 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,249 @@
1
+ require_relative './helper.rb'
2
+ require 'data_task/adapters/postgres'
3
+
4
+ module Rake
5
+ module DataTask
6
+
7
+ describe Postgres do
8
+
9
+ right_schema = "test_schema_1"
10
+ wrong_schema = "test_schema_2"
11
+ test_table = "test_table"
12
+ test_view = "test_view"
13
+ test_role = "test_role"
14
+
15
+ test_table_right_schema = "#{right_schema}.#{test_table}"
16
+ test_table_wrong_schema = "#{wrong_schema}.#{test_table}"
17
+
18
+ test_view_right_schema = "#{right_schema}.#{test_view}"
19
+ test_view_wrong_schema = "#{wrong_schema}.#{test_view}"
20
+
21
+ around do |test|
22
+ @adapter = get_adapter
23
+ if !@adapter.kind_of?(Rake::DataTask::Postgres)
24
+ skip("Using adapter #{@adapter}, so skipping #{self.class} tests.")
25
+ end
26
+
27
+ @adapter.with_transaction_rollback do
28
+ @adapter.execute <<-EOSQL
29
+ create schema #{right_schema};
30
+ create schema #{wrong_schema};
31
+ EOSQL
32
+ test.call
33
+ @adapter.execute <<-EOSQL
34
+ drop schema #{right_schema} cascade;
35
+ drop schema #{wrong_schema} cascade;
36
+ EOSQL
37
+ end
38
+ end
39
+
40
+ it "returns the current user name when called to" do
41
+ @adapter.execute "create role #{test_role}"
42
+ @adapter.with_role(test_role) do
43
+ @adapter.send(:current_user).must_equal test_role
44
+ end
45
+ end
46
+
47
+ it "returns the current search path when called to" do
48
+ @adapter.execute "set search_path to #{right_schema}, public"
49
+ @adapter.send(:search_path).must_equal [right_schema, 'public']
50
+ end
51
+
52
+ it "resets the search path after exiting a with_search_path block" do
53
+ @adapter.execute "set search_path to #{right_schema}, public"
54
+ @adapter.with_search_path([wrong_schema,'public']) do
55
+ @adapter.send(:search_path).must_equal [wrong_schema, 'public']
56
+ end
57
+ @adapter.send(:search_path).must_equal [right_schema, 'public']
58
+ end
59
+
60
+ it "returns the first schema in the search path that contains a table when called to" do
61
+ @adapter.execute "create table #{right_schema}.#{test_table} (var1 integer)"
62
+ @adapter.execute "set search_path to #{wrong_schema}, #{right_schema}, 'public'"
63
+ @adapter.send(:first_schema_for, test_table).must_equal right_schema
64
+ end
65
+
66
+ it "finds a table when it exists in the right schema" do
67
+ @adapter.execute "create table #{test_table_right_schema} (var1 integer)"
68
+ @adapter.table_exists?(test_table_right_schema).must_equal true
69
+ end
70
+
71
+ it "does not find a table when it does not exist in the right schema" do
72
+ @adapter.table_exists?(test_table_right_schema).must_equal false
73
+ end
74
+
75
+ it "does not find a table when it exists in the wrong schema" do
76
+ @adapter.execute "create table #{test_table_wrong_schema} (var1 integer)"
77
+ @adapter.table_exists?(test_table_right_schema).must_equal false
78
+ end
79
+
80
+ it "creates a table in the right schema when called to" do
81
+ @adapter.with_search_path([right_schema,'public']) do
82
+ @adapter.with_tracking do
83
+ @adapter.create_table test_table_right_schema, nil, '(var1 text)'
84
+ @adapter.table_exists?(test_table_right_schema).must_equal true
85
+ end
86
+ end
87
+ end
88
+
89
+ it "drops a table in the right schema when called to" do
90
+ @adapter.with_search_path([right_schema,'public']) do
91
+ @adapter.with_tracking do
92
+
93
+ @adapter.execute "create table #{test_table_right_schema} (var1 text)"
94
+ @adapter.execute "create table #{test_table_wrong_schema} (var1 text)"
95
+ @adapter.drop_table test_table_right_schema
96
+ @adapter.table_exists?(test_table_right_schema).must_equal false
97
+ @adapter.table_exists?(test_table_wrong_schema).must_equal true
98
+
99
+ end
100
+ end
101
+ end
102
+
103
+ it "creates a view in the right schema when called to" do
104
+ @adapter.with_search_path([right_schema,'public']) do
105
+ @adapter.with_tracking do
106
+
107
+ @adapter.create_view test_view_right_schema, "select * from information_schema.tables limit 0"
108
+ @adapter.view_exists?(test_view_right_schema).must_equal true
109
+
110
+ end
111
+ end
112
+ end
113
+
114
+ it "drops a view in the right schema when called to" do
115
+ @adapter.with_search_path([right_schema,'public']) do
116
+ @adapter.with_tracking do
117
+
118
+ @adapter.create_view test_view_right_schema, "select * from information_schema.tables limit 0"
119
+ @adapter.drop_view test_view_right_schema
120
+ @adapter.view_exists?(test_view_right_schema).must_equal false
121
+
122
+ end
123
+ end
124
+ end
125
+
126
+ it "updates the tracking table in the right schema when it creates a table" do
127
+ @adapter.with_search_path([right_schema,'public']) do
128
+ @adapter.with_tracking do
129
+
130
+ @adapter.create_table test_table_right_schema, nil, '(var1 integer)'
131
+ tracked_create = Sql.get_single_int(
132
+ @adapter.execute <<-EOSQL
133
+ select 1 from #{right_schema}.#{Db::TABLE_TRACKER_NAME}
134
+ where
135
+ relation_name = '#{test_table}' and
136
+ relation_type = '#{@adapter.relation_type_values[:table]}' and
137
+ operation = '#{@adapter.operation_values[:create]}'
138
+ EOSQL
139
+ )
140
+ tracked_create.must_equal 1
141
+
142
+ end
143
+ end
144
+ end
145
+
146
+ it "updates the tracking table in the right schema when it drops a table" do
147
+ @adapter.with_search_path([right_schema,'public']) do
148
+ @adapter.with_tracking do
149
+
150
+ @adapter.create_table test_table_right_schema, nil, '(var1 text)'
151
+ @adapter.drop_table test_table_right_schema
152
+ still_tracking_table = Sql.get_single_int(
153
+ @adapter.execute <<-EOSQL
154
+ select 1 from #{right_schema}.#{Db::TABLE_TRACKER_NAME}
155
+ where
156
+ relation_name = '#{test_table}' and
157
+ relation_type = '#{@adapter.relation_type_values[:table]}'
158
+ EOSQL
159
+ )
160
+ still_tracking_table.must_be_nil
161
+
162
+ end
163
+ end
164
+ end
165
+
166
+ it "updates the tracking table in the right schema on insert to a tracked table" do
167
+ @adapter.with_search_path([right_schema,'public']) do
168
+ @adapter.with_tracking do
169
+
170
+ @adapter.create_table test_table_right_schema, nil, '(var1 text)'
171
+ @adapter.execute "insert into #{test_table_right_schema} values ('a')"
172
+ tracked_insert = Sql.get_single_int(
173
+ @adapter.execute <<-EOSQL
174
+ select 1 from #{right_schema}.#{Db::TABLE_TRACKER_NAME}
175
+ where
176
+ relation_name = '#{test_table}' and
177
+ relation_type = '#{@adapter.relation_type_values[:table]}' and
178
+ operation = '#{@adapter.operation_values[:insert]}'
179
+ EOSQL
180
+ )
181
+ tracked_insert.must_equal 1
182
+
183
+ end
184
+ end
185
+ end
186
+
187
+ it "updates the tracking table in the right schema on update on a tracked table" do
188
+ @adapter.with_search_path([right_schema,'public']) do
189
+ @adapter.with_tracking do
190
+
191
+ @adapter.create_table test_table_right_schema, nil, '(var1 text, var2 text)'
192
+ @adapter.execute "insert into #{test_table_right_schema} values ('a', 'a')"
193
+ @adapter.execute "update #{test_table_right_schema} set var2 = 'b' where var1 = 'a'"
194
+
195
+ tracked_insert = Sql.get_single_int(
196
+ @adapter.execute <<-EOSQL
197
+ select 1 from #{right_schema}.#{Db::TABLE_TRACKER_NAME}
198
+ where
199
+ relation_name = '#{test_table}' and
200
+ relation_type = '#{@adapter.relation_type_values[:table]}' and
201
+ operation = '#{@adapter.operation_values[:update]}'
202
+ EOSQL
203
+ )
204
+ tracked_insert.must_equal 1
205
+
206
+ end
207
+ end
208
+ end
209
+
210
+ it "updates the tracking table in the right schema on truncate of a tracked table" do
211
+ @adapter.with_search_path([right_schema,'public']) do
212
+ @adapter.with_tracking do
213
+
214
+ @adapter.create_table test_table_right_schema, nil, '(var1 text)'
215
+ @adapter.truncate_table test_table_right_schema
216
+ tracked_truncate = Sql.get_single_int(
217
+ @adapter.execute <<-EOSQL
218
+ select 1 from #{right_schema}.#{Db::TABLE_TRACKER_NAME}
219
+ where
220
+ relation_name = '#{test_table}' and
221
+ relation_type = '#{@adapter.relation_type_values[:table]}' and
222
+ operation = '#{@adapter.operation_values[:truncate]}'
223
+ EOSQL
224
+ )
225
+ tracked_truncate.must_equal 1
226
+
227
+ end
228
+ end
229
+ end
230
+
231
+ it "says it is tracking tables after tracking is set up in the right schema" do
232
+ @adapter.with_search_path([right_schema,'public']) do
233
+ @adapter.tear_down_tracking
234
+ @adapter.set_up_tracking
235
+ (@adapter.tracking_tables?).must_equal true
236
+ end
237
+ end
238
+
239
+ it "says it is not tracking tables after tracking is torn down in the right schema" do
240
+ @adapter.with_search_path([right_schema,'public']) do
241
+ @adapter.tear_down_tracking
242
+ (@adapter.tracking_tables?).must_equal false
243
+ end
244
+ end
245
+
246
+ end
247
+
248
+ end
249
+ end
data/test/sql_spec.rb ADDED
@@ -0,0 +1,46 @@
1
+ require_relative './helper.rb'
2
+
3
+ module Rake
4
+ module DataTask
5
+
6
+ describe Sql do
7
+
8
+ around do |test|
9
+ @adapter = get_adapter
10
+ @adapter.with_transaction_rollback do
11
+ test.call
12
+ end
13
+ end
14
+
15
+ context "when asked to parse a single value" do
16
+ it "raises an error if the results array contains more than one column" do
17
+ r = @adapter.execute('select 1,2')
18
+ lambda {Sql.parse_single_value(r)}.must_raise(TypeError)
19
+ end
20
+ it "raises an error if the results array contains more than one row" do
21
+ r = @adapter.execute('select 1 union all select 2')
22
+ lambda {Sql.parse_single_value(r)}.must_raise(TypeError)
23
+ end
24
+ it "returns nil if the results array contains no rows" do
25
+ r = @adapter.execute("select 1 where #{@adapter.falsey_value}")
26
+ Sql.parse_single_value(r).must_be_nil
27
+ end
28
+ it "returns nil if the results array contains a null value" do
29
+ r = @adapter.execute('select NULL')
30
+ Sql.parse_single_value(r).must_be_nil
31
+ end
32
+ end
33
+
34
+ context "when asked for a single integer" do
35
+ it "returns a single integer if the query result is a single value convertible to an integer" do
36
+ Sql.get_single_int(@adapter.execute('select 1')).must_be_kind_of Integer
37
+ end
38
+ it "raises an error if the query results in a single non-integer" do
39
+ lambda {Sql.get_single_int(@adapter.execute("select 'a'"))}.must_raise(ArgumentError)
40
+ end
41
+ end
42
+
43
+ end
44
+
45
+ end
46
+ end
@@ -0,0 +1,34 @@
1
+ module Rake
2
+ module DataTask
3
+ module DataCreation
4
+ OLDDATA = "old_data"
5
+ NEWDATA = "new_data"
6
+
7
+ def create_timed_data(adapter, old_data_name, *new_data_names)
8
+ old_data = Data.new(old_data_name, adapter)
9
+ return if (old_data.exists? &&
10
+ new_data_names.all? do |new_data_name|
11
+ new_data = Data.new(new_data_name, adapter)
12
+ new_data.exists? && new_data.mtime > old_data.mtime
13
+ end)
14
+ now = Time.now
15
+
16
+ create_data(adapter, old_data_name)
17
+ sleep(1.0)
18
+
19
+ new_data_names.each do |new_data_name|
20
+ create_data(adapter, new_data_name)
21
+ end
22
+ end
23
+
24
+ def create_data(adapter, name)
25
+ adapter.create_data name, nil, '(var1 integer, var2 integer)' unless adapter.data_exists?(name)
26
+ adapter.data_mtime(name)
27
+ end
28
+
29
+ def drop_data(adapter, name)
30
+ adapter.drop_data(name) rescue nil
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,207 @@
1
+ require File.expand_path(
2
+ File.join(Gem::Specification.find_by_name('rake').gem_dir,'test/helper.rb'), __FILE__)
3
+ require 'minitest/around/unit'
4
+ require_relative './table_creation.rb'
5
+ require_relative './helper.rb'
6
+
7
+ module Rake
8
+ module DataTask
9
+
10
+ class TestRakeDataTask < Rake::TestCase
11
+ include Rake
12
+ include DataCreation
13
+
14
+ def around(&block)
15
+ @adapter = get_adapter
16
+ @adapter.with_transaction_rollback do
17
+ yield
18
+ end
19
+ end
20
+
21
+ def setup
22
+ super
23
+
24
+ Task.clear
25
+ @runs = Array.new
26
+ end
27
+
28
+ def test_data_need
29
+ @adapter.with_tracking do
30
+ name = "dummy"
31
+ data @adapter[name]
32
+ ttask = Task[name]
33
+
34
+ Data.drop(ttask.name) rescue nil
35
+ assert ttask.needed?, "data should be needed"
36
+
37
+ @adapter.create_data name, nil, '(var1 integer)'
38
+
39
+ assert_equal nil, ttask.prerequisites.collect{|n| Task[n].timestamp}.max
40
+ assert ! ttask.needed?, "data should not be needed"
41
+ end
42
+ end
43
+
44
+ def test_data_times_new_depends_on_old
45
+ @adapter.with_tracking do
46
+ create_timed_data(@adapter, OLDDATA, NEWDATA)
47
+
48
+ t1 = Rake.application.intern(DataTask, @adapter[NEWDATA]).enhance([@adapter[OLDDATA]])
49
+ t2 = Rake.application.intern(DataTask, @adapter[OLDDATA])
50
+ assert ! t2.needed?, "Should not need to build old data"
51
+ assert ! t1.needed?, "Should not need to rebuild new data because of old"
52
+ end
53
+ end
54
+
55
+ def test_data_times_new_depend_on_regular_task_timestamps
56
+ @adapter.with_tracking do
57
+ load_phony
58
+
59
+ name = "dummy"
60
+ task name
61
+
62
+ create_timed_data(@adapter, NEWDATA)
63
+
64
+ t1 = Rake.application.intern(DataTask, @adapter[NEWDATA]).enhance([name])
65
+
66
+ assert t1.needed?, "depending on non-data task uses Time.now"
67
+
68
+ task(name => :phony)
69
+
70
+ assert t1.needed?, "unless the non-data task has a timestamp"
71
+ end
72
+ end
73
+
74
+ def test_data_times_old_depends_on_new
75
+ @adapter.with_tracking do
76
+ create_timed_data(@adapter, OLDDATA, NEWDATA)
77
+
78
+ t1 = Rake.application.intern(DataTask, @adapter[OLDDATA]).enhance([@adapter[NEWDATA]])
79
+ t2 = Rake.application.intern(DataTask, @adapter[NEWDATA])
80
+ assert ! t2.needed?, "Should not need to build new data"
81
+ preq_stamp = t1.prerequisites.collect{|t| Task[t].timestamp}.max
82
+ assert_equal t2.timestamp, preq_stamp
83
+ assert t1.timestamp < preq_stamp, "T1 should be older"
84
+ assert t1.needed?, "Should need to rebuild old data because of new"
85
+ end
86
+ end
87
+
88
+ def test_data_depends_on_task_depend_on_data
89
+ @adapter.with_tracking do
90
+ create_timed_data(@adapter, OLDDATA, NEWDATA)
91
+
92
+ data @adapter[NEWDATA] => [:obj] do |t| @runs << t.name end
93
+ task :obj => [OLDDATA] do |t| @runs << t.name end
94
+ data @adapter[OLDDATA] do |t| @runs << t.name end
95
+
96
+ Task[:obj].invoke
97
+ Task[NEWDATA].invoke
98
+ assert @runs.include?(NEWDATA)
99
+ end
100
+ end
101
+
102
+ def test_existing_data_depends_on_non_existing_data
103
+ @adapter.with_tracking do
104
+ @ran = false
105
+
106
+ create_data(@adapter, OLDDATA)
107
+ drop_data(@adapter, NEWDATA)
108
+ data @adapter[NEWDATA] do
109
+ @ran = true
110
+ end
111
+
112
+ data @adapter[OLDDATA] => NEWDATA
113
+
114
+ Task[OLDDATA].invoke
115
+
116
+ assert @ran
117
+ end
118
+ end
119
+
120
+ def test_data_depends_on_new_file
121
+ @adapter.with_tracking do
122
+ create_timed_data(@adapter, OLDDATA, NEWDATA)
123
+ sleep(1)
124
+
125
+ file NEWFILE do
126
+ create_file(NEWFILE)
127
+ end
128
+ Task[NEWFILE].invoke
129
+
130
+ @ran = false
131
+ data NEWDATA => NEWFILE do
132
+ @ran = true
133
+ end
134
+
135
+ Task[NEWDATA].invoke
136
+ assert @ran, "Should have run the data task with an updated file dependency."
137
+ end
138
+ end
139
+
140
+ def test_data_depends_on_new_file
141
+ @adapter.with_tracking do
142
+ file NEWFILE do
143
+ create_file(NEWFILE)
144
+ end
145
+ Task[NEWFILE].invoke
146
+
147
+ sleep(1)
148
+ create_timed_data(@adapter, OLDDATA, NEWDATA)
149
+
150
+ @ran = false
151
+ data @adapter[NEWDATA] => NEWFILE do
152
+ @ran = true
153
+ end
154
+
155
+ Task[@adapter[NEWDATA]].invoke
156
+ assert !@ran, "Should not have run the data task with an old file dependency."
157
+ end
158
+ end
159
+
160
+ def test_file_depends_on_new_data
161
+ @adapter.with_tracking do
162
+ create_file(NEWFILE)
163
+ sleep(1)
164
+
165
+ data @adapter[NEWDATA] do
166
+ create_timed_data(@adapter, OLDDATA, NEWDATA)
167
+ end
168
+ Task[@adapter[NEWDATA]].invoke
169
+
170
+ @ran = false
171
+ file NEWFILE => @adapter[NEWDATA] do
172
+ @ran = true
173
+ end
174
+
175
+ Task[@adapter[NEWFILE]].invoke
176
+ assert @ran, "Should have run the file task with an updated data dependency."
177
+ end
178
+ end
179
+
180
+ def test_file_depends_on_old_data
181
+ @adapter.with_tracking do
182
+ data @adapter[NEWDATA] do
183
+ create_timed_data(@adapter, OLDDATA, NEWDATA)
184
+ end
185
+ Task[@adapter[NEWDATA]].invoke
186
+
187
+ sleep(1)
188
+ create_file(NEWFILE)
189
+
190
+ @ran = false
191
+ file NEWFILE => @adapter[NEWDATA] do
192
+ @ran = true
193
+ end
194
+
195
+ Task[@adapter[NEWFILE]].invoke
196
+ assert !@ran, "Should not have run the file task with an old data dependency."
197
+ end
198
+ end
199
+
200
+ def load_phony
201
+ load File.join(@rake_lib, "rake/phony.rb")
202
+ end
203
+
204
+ end
205
+
206
+ end
207
+ end