coupler 0.0.7-java → 0.0.8-java

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