coupler 0.0.7-java → 0.0.8-java

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.
Files changed (46) hide show
  1. data/VERSION +1 -1
  2. data/coupler.gemspec +11 -2
  3. data/db/migrate/024_add_error_msg_to_jobs.rb +5 -0
  4. data/db/migrate/025_add_notifications.rb +16 -0
  5. data/db/migrate/026_add_status_to_resources.rb +7 -0
  6. data/db/migrate/027_add_notification_id_to_jobs.rb +8 -0
  7. data/lib/coupler.rb +6 -2
  8. data/lib/coupler/base.rb +1 -0
  9. data/lib/coupler/extensions.rb +3 -1
  10. data/lib/coupler/extensions/imports.rb +11 -14
  11. data/lib/coupler/extensions/notifications.rb +26 -0
  12. data/lib/coupler/models.rb +1 -0
  13. data/lib/coupler/models/comparison.rb +0 -1
  14. data/lib/coupler/models/connection.rb +0 -1
  15. data/lib/coupler/models/field.rb +6 -6
  16. data/lib/coupler/models/import.rb +9 -3
  17. data/lib/coupler/models/job.rb +64 -20
  18. data/lib/coupler/models/matcher.rb +0 -1
  19. data/lib/coupler/models/notification.rb +7 -0
  20. data/lib/coupler/models/project.rb +0 -1
  21. data/lib/coupler/models/resource.rb +52 -31
  22. data/lib/coupler/models/result.rb +0 -1
  23. data/lib/coupler/models/scenario.rb +0 -1
  24. data/lib/coupler/models/transformation.rb +2 -3
  25. data/lib/coupler/models/transformer.rb +0 -1
  26. data/lib/coupler/scheduler.rb +8 -0
  27. data/tasks/db.rake +2 -2
  28. data/test/functional/test_imports.rb +21 -13
  29. data/test/functional/test_notifications.rb +38 -0
  30. data/test/integration/test_import.rb +25 -1
  31. data/test/unit/models/test_field.rb +2 -13
  32. data/test/unit/models/test_import.rb +4 -0
  33. data/test/unit/models/test_job.rb +59 -6
  34. data/test/unit/models/test_notification.rb +17 -0
  35. data/test/unit/models/test_resource.rb +114 -29
  36. data/test/unit/models/test_transformation.rb +4 -4
  37. data/test/unit/test_base.rb +1 -1
  38. data/test/unit/test_scheduler.rb +11 -0
  39. data/webroot/public/css/style.css +23 -0
  40. data/webroot/public/js/application.js +31 -10
  41. data/webroot/views/jobs/list.erb +2 -0
  42. data/webroot/views/layout.erb +3 -1
  43. data/webroot/views/notifications/index.erb +16 -0
  44. data/webroot/views/resources/list.erb +12 -7
  45. data/webroot/views/sidebar.erb +2 -0
  46. metadata +11 -2
@@ -1,4 +1,3 @@
1
- pp caller
2
1
  module Coupler
3
2
  module Models
4
3
  class Result < Sequel::Model
@@ -1,4 +1,3 @@
1
- pp caller
2
1
  module Coupler
3
2
  module Models
4
3
  class Scenario < Sequel::Model
@@ -1,4 +1,3 @@
1
- pp caller
2
1
  module Coupler
3
2
  module Models
4
3
  class Transformation < Sequel::Model
@@ -93,7 +92,7 @@ module Coupler
93
92
 
94
93
  def after_save
95
94
  super
96
- resource.refresh_fields!
95
+ resource.transformations_updated!
97
96
  end
98
97
 
99
98
  def before_destroy
@@ -111,7 +110,7 @@ module Coupler
111
110
  if result_field && result_field.is_generated && self.class.filter(:result_field_id => result_field.id).count == 0
112
111
  result_field.destroy
113
112
  end
114
- resource.refresh_fields! if resource
113
+ resource.transformations_updated! if resource
115
114
  end
116
115
  end
117
116
  end
@@ -1,4 +1,3 @@
1
- pp caller
2
1
  module Coupler
3
2
  module Models
4
3
  class Transformer < Sequel::Model
@@ -23,6 +23,14 @@ module Coupler
23
23
  })
24
24
  end
25
25
 
26
+ def schedule_import_job(import)
27
+ Models::Job.create({
28
+ :name => "import",
29
+ :import => import,
30
+ :status => "scheduled"
31
+ })
32
+ end
33
+
26
34
  def run_jobs
27
35
  @mutex.synchronize do
28
36
  count = Models::Job.filter(:status => 'running').count
@@ -16,7 +16,7 @@ namespace :db do
16
16
  desc "Run migrations"
17
17
  task :migrate => :environment do
18
18
  version = ENV['VERSION']
19
- Coupler::Database.instance.migrate!(version ? version.to_i : nil)
19
+ Coupler::Database.migrate!(version ? version.to_i : nil)
20
20
  end
21
21
 
22
22
  namespace :migrate do
@@ -26,7 +26,7 @@ namespace :db do
26
26
 
27
27
  desc "Roll the database back a version"
28
28
  task :rollback => [:start, :environment] do
29
- Coupler::Database.instance.rollback!
29
+ Coupler::Database.rollback!
30
30
  end
31
31
 
32
32
  desc "Reset and bootstrap the database"
@@ -33,12 +33,16 @@ module CouplerFunctionalTests
33
33
  find('label[for="resource-type-csv"]').click
34
34
  attach_file('data', fixture_path('people.csv'))
35
35
 
36
+ job_count = Job.count
37
+ resource_count = Resource.count
36
38
  click_button('Begin Importing')
37
- assert_match %r{^/projects/#{@project[:id]}/resources/\d+$}, page.current_path
39
+ assert_match %r{^/projects/#{@project[:id]}/resources$}, page.current_path
40
+ assert_equal resource_count + 1, Resource.count
41
+ assert_equal job_count + 1, Job.count
38
42
  end
39
43
 
40
44
  attribute(:javascript, true)
41
- test "create with invalid import" do
45
+ test "create with invalid import, fix, and continue" do
42
46
  visit "/projects/#{@project.id}/resources/new"
43
47
  find('label[for="resource-type-csv"]').click
44
48
  attach_file('data', fixture_path('people.csv'))
@@ -47,30 +51,34 @@ module CouplerFunctionalTests
47
51
  click_button('Begin Importing')
48
52
 
49
53
  assert page.has_selector?("div.errors")
54
+
55
+ fill_in('name', :with => 'Foo Bar')
56
+ click_button('Begin Importing')
57
+ assert_match %r{^/projects/#{@project[:id]}/resources$}, page.current_path
50
58
  end
51
59
 
52
60
  attribute(:javascript, true)
53
- test "create with duplicate keys redirects to edit" do
54
- visit "/projects/#{@project.id}/resources/new"
55
- find('label[for="resource-type-csv"]').click
56
- attach_file('data', fixture_path('duplicate-keys.csv'))
57
- click_button('Begin Importing')
61
+ test "editing import with duplicate keys" do
62
+ import = Import.create(:data => fixture_file_upload("duplicate-keys.csv"), :project => @project)
63
+ import.import!
58
64
 
65
+ visit "/projects/#{@project.id}/imports/#{import.id}/edit"
59
66
  assert find("h2").has_content?("Duplicate Keys")
60
- assert_match %r{^/projects/#{@project.id}/imports/\d+/edit$}, page.current_path
61
67
  end
62
68
 
63
69
  attribute(:javascript, true)
64
70
  test "update import with duplicate keys" do
65
- visit "/projects/#{@project.id}/resources/new"
66
- find('label[for="resource-type-csv"]').click
67
- attach_file('data', fixture_path('duplicate-keys.csv'))
68
- click_button('Begin Importing')
71
+ import = Import.create(:data => fixture_file_upload("duplicate-keys.csv"), :project => @project)
72
+ resource = Resource.create(:name => import.name, :project => @project, :status => 'pending', :import => import)
73
+ import.import!
69
74
 
75
+ visit "/projects/#{@project.id}/imports/#{import.id}/edit"
70
76
  find('input[name="delete[2][]"][value="1"]').click
71
77
  click_button('Submit')
72
78
 
73
- assert_match %r{^/projects/#{@project[:id]}/resources/\d+$}, page.current_path
79
+ resource.refresh
80
+ assert_equal "ok", resource.status
81
+ assert_match %r{^/projects/#{@project[:id]}/resources/#{resource.id}$}, page.current_path
74
82
  end
75
83
  end
76
84
  end
@@ -0,0 +1,38 @@
1
+ require 'helper'
2
+
3
+ module CouplerFunctionalTests
4
+ class TestNotifications < Coupler::Test::FunctionalTest
5
+
6
+ test "empty index" do
7
+ visit "/notifications"
8
+ assert_equal 200, page.status_code
9
+ end
10
+
11
+ test "index" do
12
+ n1 = Notification.create(:message => "Test!")
13
+ n2 = Notification.create(:message => "Another Test!", :url => "/projects")
14
+ n3 = Notification.create(:message => "Foo", :seen => true)
15
+ n4 = Notification.create(:message => "Bar", :url => "/connections", :seen => true)
16
+ visit "/notifications"
17
+ assert_equal 200, page.status_code
18
+ end
19
+
20
+ test "flags notifications as seen when url is visited" do
21
+ n = Notification.create(:message => "Foo bar", :url => "/connections")
22
+ visit "/connections"
23
+ n.reload
24
+ assert n.seen
25
+ end
26
+
27
+ test "unseen json" do
28
+ now = DateTime.now
29
+ Timecop.freeze(now) do
30
+ n1 = Notification.create(:message => "Foo bar", :url => "/connections")
31
+ n2 = Notification.create(:message => "Seen foo bar", :url => "/projects", :seen => true)
32
+ end
33
+ page.driver.get "/notifications/unseen.json"
34
+ result = JSON.parse(page.driver.response.body)
35
+ assert_equal([{'id' => n1.id, 'message' => 'Foo bar', 'url' => '/connections', 'created_at' => now.to_s}], result)
36
+ end
37
+ end
38
+ end
@@ -5,7 +5,13 @@ class TestImport < Coupler::Test::IntegrationTest
5
5
  test "import!" do
6
6
  project = Project.create(:name => "foo")
7
7
  import = Import.create(:data => fixture_file_upload("people.csv"), :project => project)
8
- import.import!
8
+
9
+ total = import.data.file.size
10
+ completed = 0
11
+ import.import! do |pos|
12
+ assert pos > completed
13
+ completed = pos
14
+ end
9
15
  assert_not_nil import.occurred_at
10
16
 
11
17
  project.local_database do |db|
@@ -22,6 +28,24 @@ class TestImport < Coupler::Test::IntegrationTest
22
28
  end
23
29
  end
24
30
 
31
+ test "import job" do
32
+ project = Project.create(:name => "foo")
33
+
34
+ tempfile = Tempfile.new('coupler-import')
35
+ tempfile.write("id,foo,bar\n1,2,3\n4,5,6\n7,8,9\n2,3,4\n5,6,7\n8,9,0\n")
36
+ tempfile.close
37
+ import = Import.create(:data => file_upload(tempfile.path), :project => project)
38
+ resource = Resource.create(:name => 'foo', :status => 'pending', :project => project, :import => import)
39
+
40
+ job = Job.create(:name => 'import', :import => import, :status => "scheduled")
41
+ job.execute
42
+
43
+ project.local_database do |db|
44
+ name = :"import_#{import.id}"
45
+ assert db.tables.include?(name)
46
+ end
47
+ end
48
+
25
49
  test "flags duplicate primary keys" do
26
50
  tempfile = Tempfile.new('coupler-import')
27
51
  tempfile.write("id,foo,bar\n1,abc,def\n2,ghi,jkl\n2,mno,pqr")
@@ -46,17 +46,6 @@ module CouplerUnitTests
46
46
  assert field_2.is_selected
47
47
  end
48
48
 
49
- test "original_column_options" do
50
- field = new_field({
51
- :local_type => 'integer',
52
- :local_db_type => 'int(11)',
53
- })
54
- assert_equal({
55
- :name => 'foo', :type => 'varchar(255)',
56
- :primary_key => false
57
- }, field.original_column_options)
58
- end
59
-
60
49
  test "local_column_options" do
61
50
  field_1 = new_field({
62
51
  :type => 'integer', :db_type => 'int(11)',
@@ -69,11 +58,11 @@ module CouplerUnitTests
69
58
  })
70
59
 
71
60
  assert_equal({
72
- :name => 'foo', :type => 'varchar(255)',
61
+ :name => 'foo', :type => String, :size => 255,
73
62
  :primary_key => false
74
63
  }, field_1.local_column_options)
75
64
  assert_equal({
76
- :name => 'foo', :type => 'int(11)',
65
+ :name => 'foo', :type => Integer,
77
66
  :primary_key => false
78
67
  }, field_2.local_column_options)
79
68
  end
@@ -31,6 +31,10 @@ module CouplerUnitTests
31
31
  assert_respond_to Models::Import.new, :project
32
32
  end
33
33
 
34
+ test "one to one resource" do
35
+ assert_respond_to Models::Import.new, :resource
36
+ end
37
+
34
38
  test "gets name from original filename" do
35
39
  import = new_import
36
40
  assert_equal "People", import.name
@@ -11,13 +11,20 @@ module CouplerUnitTests
11
11
  if attribs[:scenario]
12
12
  j.stubs(:scenario_dataset).returns(stub({:all => [attribs[:scenario]]}))
13
13
  end
14
+ if attribs[:import]
15
+ j.stubs(:import_dataset).returns(stub({:all => [attribs[:import]]}))
16
+ end
14
17
  j
15
18
  end
16
19
 
17
20
  def setup
18
21
  super
22
+ @project = stub('project', :pk => 1, :id => 1, :associations => {})
19
23
  @resource = stub('resource', :pk => 456, :id => 456, :associations => {})
20
24
  @scenario = stub('scenario', :pk => 456, :id => 456, :associations => {})
25
+ @import = stub('import', :pk => 123, :id => 123, :associations => {}, :project_id => 1, :project => @project, :name => 'foo')
26
+ @notification = stub('notification', :pk => 222, :id => 222, :associations => {})
27
+ Coupler::Models::Notification.stubs(:create).returns(@notification)
21
28
  end
22
29
 
23
30
  test "sequel model" do
@@ -33,6 +40,14 @@ module CouplerUnitTests
33
40
  assert_respond_to Job.new, :scenario
34
41
  end
35
42
 
43
+ test "belongs to import" do
44
+ assert_respond_to Job.new, :import
45
+ end
46
+
47
+ test "belongs to notification" do
48
+ assert_respond_to Job.new, :notification
49
+ end
50
+
36
51
  test "percent completed" do
37
52
  job = new_job(:name => 'transform', :resource => @resource, :total => 200, :completed => 54)
38
53
  assert_equal 27, job.percent_completed
@@ -48,7 +63,9 @@ module CouplerUnitTests
48
63
  seq = sequence("update")
49
64
  job.expects(:update).with(:status => 'running', :total => 12345, :started_at => now).in_sequence(seq)
50
65
  @resource.expects(:transform!).in_sequence(seq)
51
- job.expects(:update).with(:status => 'done', :completed_at => now).in_sequence(seq)
66
+ job.expects(:status=).with('done').in_sequence(seq)
67
+ job.expects(:completed_at=).with(now).in_sequence(seq)
68
+ job.expects(:save).in_sequence(seq)
52
69
  Timecop.freeze(now) { job.execute }
53
70
  end
54
71
 
@@ -60,8 +77,9 @@ module CouplerUnitTests
60
77
  seq = sequence("update")
61
78
  job.expects(:update).with(:status => 'running', :total => 12345, :started_at => now).in_sequence(seq)
62
79
  fake_exception_klass = Class.new(Exception)
63
- @resource.expects(:transform!).raises(fake_exception_klass.new).in_sequence(seq)
64
- job.expects(:update).with(:status => 'failed', :completed_at => now).in_sequence(seq)
80
+ exception = fake_exception_klass.new("someone set us up the bomb")
81
+ @resource.expects(:transform!).raises(exception).in_sequence(seq)
82
+ job.expects(:update).with(has_entries(:status => 'failed', :completed_at => now, :error_msg => kind_of(String))).in_sequence(seq)
65
83
 
66
84
  Timecop.freeze(now) do
67
85
  begin
@@ -78,7 +96,9 @@ module CouplerUnitTests
78
96
  seq = sequence("update")
79
97
  job.expects(:update).with(:status => 'running', :started_at => now).in_sequence(seq)
80
98
  @scenario.expects(:run!).in_sequence(seq)
81
- job.expects(:update).with(:status => 'done', :completed_at => now).in_sequence(seq)
99
+ job.expects(:status=).with('done').in_sequence(seq)
100
+ job.expects(:completed_at=).with(now).in_sequence(seq)
101
+ job.expects(:save).in_sequence(seq)
82
102
 
83
103
  Timecop.freeze(now) { job.execute }
84
104
  end
@@ -90,8 +110,9 @@ module CouplerUnitTests
90
110
  seq = sequence("update")
91
111
  job.expects(:update).with(:status => 'running', :started_at => now).in_sequence(seq)
92
112
  fake_exception_klass = Class.new(Exception)
93
- @scenario.expects(:run!).raises(fake_exception_klass.new).in_sequence(seq)
94
- job.expects(:update).with(:status => 'failed', :completed_at => now).in_sequence(seq)
113
+ exception = fake_exception_klass.new("someone set us up the bomb")
114
+ @scenario.expects(:run!).raises(exception).in_sequence(seq)
115
+ job.expects(:update).with(has_entries(:status => 'failed', :completed_at => now, :error_msg => kind_of(String))).in_sequence(seq)
95
116
 
96
117
  Timecop.freeze(now) do
97
118
  begin
@@ -110,6 +131,38 @@ module CouplerUnitTests
110
131
  Timecop.freeze(now ) { job_4 = new_job(:name => "run_scenario", :scenario => @scenario).save! }
111
132
  assert_equal [job_4, job_3, job_2], Job.recently_accessed
112
133
  end
134
+
135
+ test "import job" do
136
+ job = new_job(:name => 'import', :import => @import).save!
137
+
138
+ now = Time.now
139
+ seq = sequence("update")
140
+ @import.expects(:data).returns(mock(:file => mock(:size => 12345)))
141
+ job.expects(:update).with(:status => 'running', :total => 12345, :started_at => now).in_sequence(seq)
142
+ @import.expects(:import!).returns(true).in_sequence(seq)
143
+ @import.expects(:resource).returns(mock({:id => 456, :activate! => nil})).in_sequence(seq)
144
+ Notification.expects(:create).with(:message => "Import finished successfully", :url => "/projects/1/resources/456").returns(@notification).in_sequence(seq)
145
+ job.expects(:notification=).with(@notification).in_sequence(seq)
146
+ job.expects(:status=).with('done').in_sequence(seq)
147
+ job.expects(:completed_at=).with(now).in_sequence(seq)
148
+ job.expects(:save).in_sequence(seq)
149
+ Timecop.freeze(now) { job.execute }
150
+ end
151
+
152
+ test "import job with more interaction needed" do
153
+ job = new_job(:name => 'import', :import => @import).save!
154
+
155
+ now = Time.now
156
+ seq = sequence("update")
157
+ @import.expects(:data).returns(mock(:file => mock(:size => 12345)))
158
+ job.expects(:update).with(:status => 'running', :total => 12345, :started_at => now).in_sequence(seq)
159
+ @import.expects(:import!).returns(false).in_sequence(seq)
160
+ Notification.expects(:create).with(:message => "Import finished, but with errors", :url => "/projects/1/imports/123/edit").returns(@notification)
161
+ job.expects(:status=).with('done').in_sequence(seq)
162
+ job.expects(:completed_at=).with(now).in_sequence(seq)
163
+ job.expects(:save).in_sequence(seq)
164
+ Timecop.freeze(now) { job.execute }
165
+ end
113
166
  end
114
167
  end
115
168
  end
@@ -0,0 +1,17 @@
1
+ require 'helper'
2
+
3
+ module TestModels
4
+ class TestNotification < Coupler::Test::UnitTest
5
+ include Coupler::Models
6
+ Coupler::Models::Notification # force load
7
+
8
+ test "sequel model" do
9
+ assert_equal ::Sequel::Model, Notification.superclass
10
+ assert_equal :notifications, Notification.table_name
11
+ end
12
+
13
+ test "common model" do
14
+ assert Notification.ancestors.include?(CommonModel)
15
+ end
16
+ end
17
+ end
@@ -29,8 +29,15 @@ module CouplerUnitTests
29
29
  :connection => @connection
30
30
  }.update(attribs)
31
31
  r = Resource.new(values)
32
- r.stubs(:project_dataset).returns(stub({:all => [values[:project]]}))
33
- r.stubs(:connection_dataset).returns(stub({:all => [values[:connection]]}))
32
+ if values[:project]
33
+ r.stubs(:project_dataset).returns(stub({:all => [values[:project]]}))
34
+ end
35
+ if values[:connection]
36
+ r.stubs(:connection_dataset).returns(stub({:all => [values[:connection]]}))
37
+ end
38
+ if values[:import]
39
+ r.stubs(:import_dataset).returns(stub({:all => [values[:import]]}))
40
+ end
34
41
  r
35
42
  end
36
43
 
@@ -311,23 +318,27 @@ module CouplerUnitTests
311
318
  assert_equal dataset, resource.local_dataset
312
319
  end
313
320
 
314
- test "refresh fields" do
321
+ test "transformations_updated!" do
315
322
  resource = new_resource.save!
316
323
  field_1 = stub("id field", :id => 1)
317
324
  field_2 = stub("first_name field", :id => 2)
318
325
  field_3 = stub("last_name field", :id => 3)
319
326
 
327
+ now = Time.now
320
328
  transformation_1 = stub("transformation 1", {
329
+ :id => 1, :updated_at => now,
321
330
  :source_field_id => 2, :result_field_id => 2,
322
331
  :field_changes => {2 => {:type => :integer, :db_type => 'int(11)'}},
323
332
  :source_field => field_2
324
333
  })
325
334
  transformation_2 = stub("transformation 2", {
335
+ :id => 2, :updated_at => now,
326
336
  :source_field_id => 3, :result_field_id => 3,
327
337
  :field_changes => {3 => {:type => :integer, :db_type => 'int(11)'}},
328
338
  :source_field => field_3
329
339
  })
330
340
  transformation_3 = stub("transformation 3", {
341
+ :id => 3, :updated_at => now,
331
342
  :source_field_id => 3, :result_field_id => 3,
332
343
  :field_changes => {3 => {:type => :datetime, :db_type => 'datetime'}},
333
344
  :source_field => field_3
@@ -349,10 +360,10 @@ module CouplerUnitTests
349
360
  :local_type => :datetime, :local_db_type => 'datetime'
350
361
  }).in_sequence(seq)
351
362
 
352
- resource.refresh_fields!
363
+ resource.transformations_updated!
353
364
  end
354
365
 
355
- test "refresh_fields does not change newly created result field" do
366
+ test "transformations_updated does not change newly created result field" do
356
367
  resource = new_resource.save!
357
368
  field_1 = stub("id field", :id => 1)
358
369
  field_2 = stub("first_name field", :id => 2)
@@ -360,6 +371,7 @@ module CouplerUnitTests
360
371
  new_field = stub("new field", :id => 4)
361
372
 
362
373
  transformation = stub("transformation 1", {
374
+ :id => 1, :updated_at => Time.now,
363
375
  :source_field_id => 2, :result_field_id => 4,
364
376
  :field_changes => {2 => {:type => :integer, :db_type => 'int(11)'}},
365
377
  :source_field => field_2
@@ -373,10 +385,10 @@ module CouplerUnitTests
373
385
  field_2.expects(:update).never
374
386
  new_field.expects(:update).never
375
387
 
376
- resource.refresh_fields!
388
+ resource.transformations_updated!
377
389
  end
378
390
 
379
- test "refresh_fields resets local_type and local_db_type" do
391
+ test "transformations_updated resets local_type and local_db_type" do
380
392
  resource = new_resource.save!
381
393
 
382
394
  resource.expects(:fields_dataset).returns(mock {
@@ -386,7 +398,7 @@ module CouplerUnitTests
386
398
  td.expects(:order).with(:position).returns(td)
387
399
  resource.expects(:transformations_dataset).returns(td)
388
400
 
389
- resource.refresh_fields!
401
+ resource.transformations_updated!
390
402
  end
391
403
 
392
404
  test "initial status" do
@@ -396,39 +408,108 @@ module CouplerUnitTests
396
408
 
397
409
  test "status after adding first transformation" do
398
410
  resource = new_resource.save!
399
- resource.stubs(:transformation_ids).returns([1])
411
+
412
+ field_1 = stub("id field", :id => 1, :update => nil)
413
+ transformation_1 = stub("transformation 1", {
414
+ :id => 1, :updated_at => Time.now,
415
+ :source_field_id => 1, :result_field_id => 1,
416
+ :field_changes => {1 => {:type => :integer, :db_type => 'int(11)'}},
417
+ :source_field => field_1
418
+ })
419
+ resource.stubs(:fields_dataset).returns(stub(:update => nil))
420
+ td = [transformation_1]
421
+ td.expects(:order).with(:position).returns(td)
422
+ resource.expects(:transformations_dataset).returns(td)
423
+
424
+ resource.transformations_updated!
400
425
  assert_equal "out_of_date", resource.status
401
426
  end
402
427
 
403
428
  test "status when new transformation is created since transforming" do
404
- resource = new_resource(:transformed_with => "1").save!
405
- resource.stubs(:transformation_ids).returns([1,2])
429
+ now = Time.now
430
+ resource = new_resource(:transformed_with => "1", :transformed_at => now - 5).save!
431
+
432
+ field_1 = stub("id field", :id => 1, :update => nil)
433
+ transformation_1 = stub("transformation 1", {
434
+ :id => 1, :updated_at => now - 10,
435
+ :source_field_id => 1, :result_field_id => 1,
436
+ :field_changes => {1 => {:type => :integer, :db_type => 'int(11)'}},
437
+ :source_field => field_1
438
+ })
439
+ transformation_2 = stub("transformation 2", {
440
+ :id => 2, :updated_at => now,
441
+ :source_field_id => 1, :result_field_id => 1,
442
+ :field_changes => {1 => {:type => :integer, :db_type => 'int(11)'}},
443
+ :source_field => field_1
444
+ })
445
+ resource.stubs(:fields_dataset).returns(stub(:update => nil))
446
+ td = [transformation_1, transformation_2]
447
+ td.expects(:order).with(:position).returns(td)
448
+ resource.expects(:transformations_dataset).returns(td)
449
+
450
+ resource.transformations_updated!
406
451
  assert_equal "out_of_date", resource.status
407
452
  end
408
453
 
409
454
  test "status when transformation is updated since transforming" do
410
455
  now = Time.now
411
- resource = new_resource(:transformed_with => "1", :transformed_at => now - 20).save!
412
- resource.stubs(:transformation_ids).returns([1])
413
- resource.stubs(:transformations_dataset).returns(stub {
414
- stubs(:filter).with('updated_at > ?', now - 20).returns(self)
415
- stubs(:count).returns(1)
456
+ resource = new_resource({
457
+ :transformed_with => "1",
458
+ :transformed_at => now - 20
459
+ }).save!
460
+ field_1 = stub("id field", :id => 1, :update => nil)
461
+
462
+ transformation_1 = stub("transformation 1", {
463
+ :id => 1, :updated_at => now,
464
+ :source_field_id => 1, :result_field_id => 1,
465
+ :field_changes => {1 => {:type => :integer, :db_type => 'int(11)'}},
466
+ :source_field => field_1
416
467
  })
468
+
469
+ resource.stubs(:fields_dataset).returns(stub(:update => nil))
470
+ td = [transformation_1]
471
+ td.expects(:order).with(:position).returns(td)
472
+ resource.expects(:transformations_dataset).returns(td)
473
+
474
+ resource.transformations_updated!
417
475
  assert_equal "out_of_date", resource.status
418
476
  end
419
477
 
420
478
  test "status when transformation is removed since transforming" do
421
479
  now = Time.now
422
- resource = new_resource(:transformed_at => now - 5, :transformed_with => "1").save!
423
- resource.stubs(:transformation_ids).returns([])
480
+ resource = new_resource({
481
+ :transformed_with => "1",
482
+ :transformed_at => now - 20
483
+ }).save!
484
+ td = []
485
+ td.stubs(:order).returns(td)
486
+ resource.stubs(:transformations_dataset).returns(td)
487
+
488
+ resource.transformations_updated!
424
489
  assert_equal "out_of_date", resource.status
425
490
  end
426
491
 
427
492
  test "status when new transformation is removed before transforming" do
428
493
  resource = new_resource.save!
429
- resource.stubs(:transformation_ids).returns([1])
494
+
495
+ field_1 = stub("id field", :id => 1, :update => nil)
496
+ transformation_1 = stub("transformation 1", {
497
+ :id => 1, :updated_at => Time.now,
498
+ :source_field_id => 1, :result_field_id => 1,
499
+ :field_changes => {1 => {:type => :integer, :db_type => 'int(11)'}},
500
+ :source_field => field_1
501
+ })
502
+ resource.stubs(:fields_dataset).returns(stub(:update => nil))
503
+ td = [transformation_1]
504
+ td.expects(:order).with(:position).returns(td)
505
+ resource.expects(:transformations_dataset).returns(td)
506
+ resource.transformations_updated!
430
507
  assert_equal "out_of_date", resource.status
431
- resource.stubs(:transformation_ids).returns([])
508
+
509
+ td = []
510
+ td.stubs(:order).returns(td)
511
+ resource.stubs(:transformations_dataset).returns(td)
512
+ resource.transformations_updated!
432
513
  assert_equal "ok", resource.status
433
514
  end
434
515
 
@@ -511,18 +592,21 @@ module CouplerUnitTests
511
592
  resource.destroy
512
593
  end
513
594
 
514
- test "creating resource via import" do
595
+ test "creating pending resource" do
596
+ resource = Resource.new(:name => "People", :project => @project, :status => 'pending')
597
+ assert resource.valid?
598
+ resource.save!
599
+ end
600
+
601
+ test "activate pending resource" do
515
602
  import = stub("import", {
516
603
  :id => 123, :pk => 123, :project => @project,
517
- :name => "People"
604
+ :name => "People", :project_id => @project.id,
605
+ :associations => {}
518
606
  })
519
- resource = Resource.new(:import => import)
520
- assert_equal "People", resource.name
521
- assert_equal @project, resource.project
522
- assert_equal "import_123", resource.table_name
523
- assert resource.valid?
607
+ resource = new_resource(:name => 'People', :status => 'pending', :import => import)
608
+ resource.save!
524
609
 
525
- # import.import! would happen here
526
610
  @local_database.stubs({
527
611
  :tables => [:import_123],
528
612
  :schema => [
@@ -531,9 +615,10 @@ module CouplerUnitTests
531
615
  [:bar, {:primary_key => false, :type => :string, :db_type => "VARCHAR"}]
532
616
  ]
533
617
  })
534
- resource.save!
618
+ resource.activate!
535
619
  assert_equal "id", resource.primary_key_name
536
620
  assert_equal "integer", resource.primary_key_type
621
+ assert_equal "ok", resource.status
537
622
  end
538
623
 
539
624
  test "source_dataset count" do