coupler 0.0.1-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 (258) hide show
  1. data/.document +5 -0
  2. data/.gitmodules +3 -0
  3. data/.rvmrc +1 -0
  4. data/.vimrc +40 -0
  5. data/Gemfile +27 -0
  6. data/Gemfile.lock +71 -0
  7. data/LICENSE +20 -0
  8. data/NOTES +6 -0
  9. data/README.rdoc +18 -0
  10. data/Rakefile +42 -0
  11. data/TODO +11 -0
  12. data/VERSION +1 -0
  13. data/bin/coupler +7 -0
  14. data/db/.gitignore +6 -0
  15. data/db/migrate/001_initial_schema.rb +166 -0
  16. data/db/migrate/002_stub.rb +4 -0
  17. data/db/migrate/003_stub.rb +4 -0
  18. data/db/migrate/004_create_comparisons.rb +28 -0
  19. data/db/migrate/005_move_database_name.rb +19 -0
  20. data/db/migrate/006_upgrade_comparisons.rb +34 -0
  21. data/db/migrate/007_add_which_to_comparisons.rb +23 -0
  22. data/db/migrate/008_add_result_field_to_transformations.rb +33 -0
  23. data/db/migrate/009_add_generated_flag_to_fields.rb +13 -0
  24. data/db/migrate/010_create_imports.rb +24 -0
  25. data/db/migrate/011_add_primary_key_type.rb +13 -0
  26. data/db/migrate/012_add_transformed_with_to_resources.rb +13 -0
  27. data/db/migrate/013_add_run_count_to_scenarios.rb +13 -0
  28. data/db/migrate/014_add_last_accessed_at_to_some_tables.rb +13 -0
  29. data/db/migrate/015_add_run_number_to_results.rb +15 -0
  30. data/db/migrate/016_fix_scenario_run_count.rb +27 -0
  31. data/db/migrate/017_rename_comparison_columns.rb +14 -0
  32. data/db/migrate/018_fix_scenario_linkage_type.rb +8 -0
  33. data/db/migrate/019_add_columns_to_imports.rb +24 -0
  34. data/db/migrate/020_rename_import_columns.rb +12 -0
  35. data/db/migrate/021_add_fields_to_connections.rb +15 -0
  36. data/db/migrate/022_remove_database_name_from_resources.rb +11 -0
  37. data/features/connections.feature +28 -0
  38. data/features/matchers.feature +35 -0
  39. data/features/projects.feature +11 -0
  40. data/features/resources.feature +62 -0
  41. data/features/scenarios.feature +45 -0
  42. data/features/step_definitions/coupler_steps.rb +145 -0
  43. data/features/step_definitions/matchers_steps.rb +26 -0
  44. data/features/step_definitions/resources_steps.rb +12 -0
  45. data/features/step_definitions/scenarios_steps.rb +7 -0
  46. data/features/step_definitions/transformations_steps.rb +3 -0
  47. data/features/support/env.rb +128 -0
  48. data/features/transformations.feature +22 -0
  49. data/features/wizard.feature +10 -0
  50. data/gfx/coupler-header.svg +213 -0
  51. data/gfx/coupler-sidebar.svg +656 -0
  52. data/gfx/coupler.svg +184 -0
  53. data/gfx/icon.svg +75 -0
  54. data/lib/coupler/base.rb +63 -0
  55. data/lib/coupler/config.rb +128 -0
  56. data/lib/coupler/data_uploader.rb +20 -0
  57. data/lib/coupler/database.rb +31 -0
  58. data/lib/coupler/extensions/connections.rb +57 -0
  59. data/lib/coupler/extensions/exceptions.rb +58 -0
  60. data/lib/coupler/extensions/imports.rb +43 -0
  61. data/lib/coupler/extensions/jobs.rb +21 -0
  62. data/lib/coupler/extensions/matchers.rb +64 -0
  63. data/lib/coupler/extensions/projects.rb +62 -0
  64. data/lib/coupler/extensions/resources.rb +89 -0
  65. data/lib/coupler/extensions/results.rb +100 -0
  66. data/lib/coupler/extensions/scenarios.rb +50 -0
  67. data/lib/coupler/extensions/transformations.rb +70 -0
  68. data/lib/coupler/extensions/transformers.rb +58 -0
  69. data/lib/coupler/extensions.rb +16 -0
  70. data/lib/coupler/helpers.rb +121 -0
  71. data/lib/coupler/import_buffer.rb +48 -0
  72. data/lib/coupler/logger.rb +16 -0
  73. data/lib/coupler/models/common_model.rb +104 -0
  74. data/lib/coupler/models/comparison.rb +166 -0
  75. data/lib/coupler/models/connection.rb +59 -0
  76. data/lib/coupler/models/field.rb +55 -0
  77. data/lib/coupler/models/import.rb +238 -0
  78. data/lib/coupler/models/job.rb +42 -0
  79. data/lib/coupler/models/jobify.rb +17 -0
  80. data/lib/coupler/models/matcher.rb +36 -0
  81. data/lib/coupler/models/project.rb +40 -0
  82. data/lib/coupler/models/resource.rb +287 -0
  83. data/lib/coupler/models/result.rb +92 -0
  84. data/lib/coupler/models/scenario/runner.rb +357 -0
  85. data/lib/coupler/models/scenario.rb +115 -0
  86. data/lib/coupler/models/transformation.rb +117 -0
  87. data/lib/coupler/models/transformer/runner.rb +28 -0
  88. data/lib/coupler/models/transformer.rb +110 -0
  89. data/lib/coupler/models.rb +30 -0
  90. data/lib/coupler/runner.rb +76 -0
  91. data/lib/coupler/scheduler.rb +56 -0
  92. data/lib/coupler.rb +34 -0
  93. data/log/.gitignore +1 -0
  94. data/misc/README +5 -0
  95. data/misc/jruby-json.license +57 -0
  96. data/misc/rack-flash.license +22 -0
  97. data/script/dbconsole.rb +5 -0
  98. data/src/edu/vanderbilt/coupler/Main.java +116 -0
  99. data/src/edu/vanderbilt/coupler/jruby.properties +1 -0
  100. data/tasks/annotations.rake +84 -0
  101. data/tasks/db.rake +120 -0
  102. data/tasks/environment.rake +12 -0
  103. data/tasks/jeweler.rake +43 -0
  104. data/tasks/package.rake +58 -0
  105. data/tasks/rdoc.rake +13 -0
  106. data/tasks/test.rake +63 -0
  107. data/tasks/vendor.rake +43 -0
  108. data/test/README.txt +6 -0
  109. data/test/config.yml +9 -0
  110. data/test/coupler/models/test_import.rb +221 -0
  111. data/test/factories.rb +91 -0
  112. data/test/fixtures/duplicate-keys.csv +5 -0
  113. data/test/fixtures/no-headers.csv +50 -0
  114. data/test/fixtures/people.csv +51 -0
  115. data/test/fixtures/varying-row-size.csv +4 -0
  116. data/test/helper.rb +156 -0
  117. data/test/integration/extensions/test_connections.rb +80 -0
  118. data/test/integration/extensions/test_imports.rb +94 -0
  119. data/test/integration/extensions/test_jobs.rb +52 -0
  120. data/test/integration/extensions/test_matchers.rb +134 -0
  121. data/test/integration/extensions/test_projects.rb +82 -0
  122. data/test/integration/extensions/test_resources.rb +150 -0
  123. data/test/integration/extensions/test_results.rb +89 -0
  124. data/test/integration/extensions/test_scenarios.rb +88 -0
  125. data/test/integration/extensions/test_transformations.rb +113 -0
  126. data/test/integration/extensions/test_transformers.rb +80 -0
  127. data/test/integration/test_field.rb +45 -0
  128. data/test/integration/test_import.rb +78 -0
  129. data/test/integration/test_running_scenarios.rb +379 -0
  130. data/test/integration/test_transformation.rb +56 -0
  131. data/test/integration/test_transforming.rb +154 -0
  132. data/test/table_sets.rb +76 -0
  133. data/test/unit/models/test_common_model.rb +130 -0
  134. data/test/unit/models/test_comparison.rb +619 -0
  135. data/test/unit/models/test_connection.rb +115 -0
  136. data/test/unit/models/test_field.rb +99 -0
  137. data/test/unit/models/test_import.rb +130 -0
  138. data/test/unit/models/test_job.rb +115 -0
  139. data/test/unit/models/test_matcher.rb +82 -0
  140. data/test/unit/models/test_project.rb +102 -0
  141. data/test/unit/models/test_resource.rb +564 -0
  142. data/test/unit/models/test_result.rb +90 -0
  143. data/test/unit/models/test_scenario.rb +199 -0
  144. data/test/unit/models/test_transformation.rb +193 -0
  145. data/test/unit/models/test_transformer.rb +188 -0
  146. data/test/unit/test_base.rb +60 -0
  147. data/test/unit/test_data_uploader.rb +27 -0
  148. data/test/unit/test_database.rb +23 -0
  149. data/test/unit/test_helpers.rb +58 -0
  150. data/test/unit/test_logger.rb +10 -0
  151. data/test/unit/test_models.rb +12 -0
  152. data/test/unit/test_runner.rb +76 -0
  153. data/test/unit/test_scheduler.rb +66 -0
  154. data/uploads/.gitignore +2 -0
  155. data/vendor/java/.gitignore +5 -0
  156. data/webroot/public/css/960.css +1 -0
  157. data/webroot/public/css/dataTables.css +1057 -0
  158. data/webroot/public/css/jquery-ui.css +572 -0
  159. data/webroot/public/css/jquery.treeview.css +68 -0
  160. data/webroot/public/css/reset.css +1 -0
  161. data/webroot/public/css/style.css +504 -0
  162. data/webroot/public/css/text.css +1 -0
  163. data/webroot/public/favicon.ico +0 -0
  164. data/webroot/public/images/12_col.gif +0 -0
  165. data/webroot/public/images/16_col.gif +0 -0
  166. data/webroot/public/images/add.png +0 -0
  167. data/webroot/public/images/ajax-loader.gif +0 -0
  168. data/webroot/public/images/cog.png +0 -0
  169. data/webroot/public/images/coupler.png +0 -0
  170. data/webroot/public/images/foo.png +0 -0
  171. data/webroot/public/images/hammer.png +0 -0
  172. data/webroot/public/images/header.png +0 -0
  173. data/webroot/public/images/home.gif +0 -0
  174. data/webroot/public/images/jobs.gif +0 -0
  175. data/webroot/public/images/sidebar-bottom.png +0 -0
  176. data/webroot/public/images/sidebar.png +0 -0
  177. data/webroot/public/images/treeview-default-line.gif +0 -0
  178. data/webroot/public/images/treeview-default.gif +0 -0
  179. data/webroot/public/images/ui-anim_basic_16x16.gif +0 -0
  180. data/webroot/public/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  181. data/webroot/public/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  182. data/webroot/public/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  183. data/webroot/public/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  184. data/webroot/public/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  185. data/webroot/public/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  186. data/webroot/public/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  187. data/webroot/public/images/ui-bg_highlight-hard_30_565356_1x100.png +0 -0
  188. data/webroot/public/images/ui-bg_highlight-hard_75_888588_1x100.png +0 -0
  189. data/webroot/public/images/ui-bg_highlight-soft_30_6e3b3a_1x100.png +0 -0
  190. data/webroot/public/images/ui-bg_highlight-soft_35_8e8b8e_1x100.png +0 -0
  191. data/webroot/public/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  192. data/webroot/public/images/ui-icons_222222_256x240.png +0 -0
  193. data/webroot/public/images/ui-icons_2e83ff_256x240.png +0 -0
  194. data/webroot/public/images/ui-icons_454545_256x240.png +0 -0
  195. data/webroot/public/images/ui-icons_888888_256x240.png +0 -0
  196. data/webroot/public/images/ui-icons_cd0a0a_256x240.png +0 -0
  197. data/webroot/public/images/ui-icons_ffffff_256x240.png +0 -0
  198. data/webroot/public/js/ajaxupload.js +673 -0
  199. data/webroot/public/js/application.js +40 -0
  200. data/webroot/public/js/jquery-ui.combobox.js +98 -0
  201. data/webroot/public/js/jquery-ui.js +9867 -0
  202. data/webroot/public/js/jquery-ui.min.js +559 -0
  203. data/webroot/public/js/jquery.dataTables.min.js +587 -0
  204. data/webroot/public/js/jquery.min.js +154 -0
  205. data/webroot/public/js/jquery.timeago.js +140 -0
  206. data/webroot/public/js/jquery.tooltip.min.js +19 -0
  207. data/webroot/public/js/jquery.treeview.min.js +15 -0
  208. data/webroot/public/js/resource.js +11 -0
  209. data/webroot/public/js/results.js +56 -0
  210. data/webroot/public/js/transformations.js +95 -0
  211. data/webroot/views/connections/index.erb +5 -0
  212. data/webroot/views/connections/list.erb +34 -0
  213. data/webroot/views/connections/new.erb +55 -0
  214. data/webroot/views/connections/show.erb +36 -0
  215. data/webroot/views/imports/edit.erb +60 -0
  216. data/webroot/views/imports/form.erb +81 -0
  217. data/webroot/views/imports/new.erb +89 -0
  218. data/webroot/views/index.erb +12 -0
  219. data/webroot/views/jobs/index.erb +7 -0
  220. data/webroot/views/jobs/list.erb +24 -0
  221. data/webroot/views/layout.erb +38 -0
  222. data/webroot/views/matchers/form.erb +250 -0
  223. data/webroot/views/matchers/list.erb +32 -0
  224. data/webroot/views/projects/form.erb +14 -0
  225. data/webroot/views/projects/index.erb +96 -0
  226. data/webroot/views/projects/show.erb +24 -0
  227. data/webroot/views/resources/edit.erb +88 -0
  228. data/webroot/views/resources/index.erb +5 -0
  229. data/webroot/views/resources/list.erb +27 -0
  230. data/webroot/views/resources/new.erb +121 -0
  231. data/webroot/views/resources/show.erb +86 -0
  232. data/webroot/views/resources/transform.erb +2 -0
  233. data/webroot/views/results/csv.erb +12 -0
  234. data/webroot/views/results/details.erb +15 -0
  235. data/webroot/views/results/index.erb +2 -0
  236. data/webroot/views/results/list.erb +22 -0
  237. data/webroot/views/results/record.erb +24 -0
  238. data/webroot/views/results/show.erb +68 -0
  239. data/webroot/views/scenarios/index.erb +5 -0
  240. data/webroot/views/scenarios/list.erb +20 -0
  241. data/webroot/views/scenarios/new.erb +99 -0
  242. data/webroot/views/scenarios/run.erb +2 -0
  243. data/webroot/views/scenarios/show.erb +50 -0
  244. data/webroot/views/sidebar.erb +106 -0
  245. data/webroot/views/transformations/create.erb +115 -0
  246. data/webroot/views/transformations/for.erb +16 -0
  247. data/webroot/views/transformations/index.erb +2 -0
  248. data/webroot/views/transformations/list.erb +29 -0
  249. data/webroot/views/transformations/new.erb +126 -0
  250. data/webroot/views/transformations/preview.erb +46 -0
  251. data/webroot/views/transformers/edit.erb +6 -0
  252. data/webroot/views/transformers/form.erb +58 -0
  253. data/webroot/views/transformers/index.erb +2 -0
  254. data/webroot/views/transformers/list.erb +25 -0
  255. data/webroot/views/transformers/new.erb +5 -0
  256. data/webroot/views/transformers/preview.erb +23 -0
  257. data/webroot/views/transformers/show.erb +0 -0
  258. metadata +558 -0
@@ -0,0 +1,199 @@
1
+ require 'helper'
2
+
3
+ module Coupler
4
+ module Models
5
+ class TestScenario < Coupler::Test::UnitTest
6
+ def setup
7
+ super
8
+ @project = stub('project', :pk => 1, :id => 1, :associations => {})
9
+ @resource_1 = stub('resource 1', :pk => 123, :id => 123, :associations => {}, :status => "ok")
10
+ @resource_2 = stub('resource 2', :pk => 456, :id => 456, :associations => {}, :status => "ok")
11
+ @matcher = stub('matcher', :cross_match? => false, :associations => {})
12
+ end
13
+
14
+ def new_scenario(attribs = {})
15
+ values = {
16
+ :name => 'Foo bar',
17
+ :project => @project,
18
+ :resource_1 => @resource_1,
19
+ :matcher => @matcher
20
+ }.update(attribs)
21
+ matcher = values.delete(:matcher)
22
+ s = Scenario.new(values)
23
+ if values[:project]
24
+ s.stubs(:project_dataset).returns(stub({:all => [values[:project]]}))
25
+ end
26
+ if values[:resource_1]
27
+ s.stubs(:resource_1_dataset).returns(stub({:all => [values[:resource_1]]}))
28
+ end
29
+ if values[:resource_2]
30
+ s.stubs(:resource_2_dataset).returns(stub({:all => [values[:resource_2]]}))
31
+ end
32
+ if matcher
33
+ s.stubs(:matcher_dataset).returns(stub({:all => [matcher]}))
34
+ end
35
+ s
36
+ end
37
+
38
+ test "sequel model" do
39
+ assert_equal ::Sequel::Model, Scenario.superclass
40
+ assert_equal :scenarios, Scenario.table_name
41
+ end
42
+
43
+ test "many to one project" do
44
+ assert_respond_to Scenario.new, :project
45
+ end
46
+
47
+ test "many to one resource 1" do
48
+ assert_respond_to Scenario.new, :resource_1
49
+ end
50
+
51
+ test "many to one resource 2" do
52
+ assert_respond_to Scenario.new, :resource_2
53
+ end
54
+
55
+ test "resources" do
56
+ scenario = Scenario.new(:resource_1 => @resource_1)
57
+ assert_equal [@resource_1], scenario.resources
58
+ scenario.resource_2 = @resource_2
59
+ assert_equal [@resource_1, @resource_2], scenario.resources
60
+ end
61
+
62
+ test "one to one matcher" do
63
+ assert_respond_to Scenario.new, :matcher
64
+ end
65
+
66
+ test "one to many jobs" do
67
+ assert_respond_to Scenario.new, :jobs
68
+ end
69
+
70
+ test "one to many results" do
71
+ assert_respond_to Scenario.new, :results
72
+ end
73
+
74
+ test "requires name" do
75
+ scenario = new_scenario(:name => nil)
76
+ scenario.expects(:validates_presence).with(:name).returns(false)
77
+ scenario.valid?
78
+ end
79
+
80
+ test "requires unique name across projects" do
81
+ scenario = new_scenario
82
+ scenario.expects(:validates_unique).with([:name, :project_id]).returns(false)
83
+ scenario.valid?
84
+ end
85
+
86
+ test "requires at least one resource" do
87
+ scenario = new_scenario(:resource_1 => nil)
88
+ assert !scenario.valid?
89
+ end
90
+
91
+ test "sets slug from name" do
92
+ scenario = new_scenario.save!
93
+ assert_equal "foo_bar", scenario.slug
94
+ end
95
+
96
+ test "setting one resource with resource_ids=" do
97
+ scenario = new_scenario(:resource_1 => nil, :resource_ids => [123])
98
+ resource_1 = @resource_1 # so mocha can resolve it
99
+ @project.expects(:resources_dataset).returns(mock {
100
+ expects(:filter).with(:id => [123]).returns(self)
101
+ expects(:all).returns([resource_1])
102
+ })
103
+ scenario.save!
104
+ assert_equal 123, scenario.resource_1_id
105
+ end
106
+
107
+ test "setting two resources with resource ids=" do
108
+ scenario = new_scenario(:resource_1 => nil, :resource_ids => [123, 456])
109
+ resource_1 = @resource_1 # so mocha can resolve it
110
+ resource_2 = @resource_2
111
+ @project.expects(:resources_dataset).returns(mock {
112
+ expects(:filter).with(:id => [123, 456]).returns(self)
113
+ expects(:all).returns([resource_1, resource_2])
114
+ })
115
+ scenario.save!
116
+ assert_equal 123, scenario.resource_1_id
117
+ assert_equal 456, scenario.resource_2_id
118
+ end
119
+
120
+ test "doesn't run when there is no matcher" do
121
+ scenario = new_scenario(:matcher => nil).save!
122
+ assert_raises(Scenario::NoMatcherError) { scenario.run! }
123
+ end
124
+
125
+ test "doesn't run when resources are out of date" do
126
+ scenario = new_scenario.save!
127
+ @resource_1.expects(:status).returns("out_of_date")
128
+ assert_raises(Scenario::ResourcesOutOfDateError) { scenario.run! }
129
+ end
130
+
131
+ test "status with no matcher" do
132
+ scenario = new_scenario(:matcher => nil).save!
133
+ assert_equal "no_matcher", scenario.status
134
+ end
135
+
136
+ test "status with matcher" do
137
+ scenario = new_scenario.save!
138
+ assert_equal "ok", scenario.status
139
+ end
140
+
141
+ test "status with outdated resources" do
142
+ scenario = new_scenario.save!
143
+ @resource_1.expects(:status).returns("out_of_date")
144
+ assert_equal "resources_out_of_date", scenario.status
145
+ end
146
+
147
+ test "linkage type with one resource" do
148
+ scenario = new_scenario.save!
149
+ assert_equal "self-linkage", scenario.linkage_type
150
+ end
151
+
152
+ test "linkage type with two resources" do
153
+ scenario = new_scenario(:resource_2 => @resource_2).save!
154
+ assert_equal "dual-linkage", scenario.linkage_type
155
+ end
156
+
157
+ test "matcher with cross match makes cross-linkage" do
158
+ scenario = new_scenario.save!
159
+ @matcher.stubs(:cross_match?).returns(true)
160
+ scenario.set_linkage_type
161
+ assert_equal "cross-linkage", scenario.linkage_type
162
+ end
163
+
164
+ test "jobified" do
165
+ assert Scenario.ancestors.include?(Jobify)
166
+ end
167
+
168
+ #def test_destroying
169
+ #pend
170
+ #end
171
+
172
+ test "local database" do
173
+ scenario = new_scenario.save!
174
+ Base.expects(:connection_string).with("scenario_#{scenario.id}").returns("foo")
175
+ db = mock('scenario db')
176
+ Sequel.expects(:connect).with('foo', instance_of(Hash)).returns(db)
177
+ assert_equal db, scenario.local_database
178
+ end
179
+
180
+ #def test_deletes_local_database_after_destroy
181
+ #pend
182
+ #end
183
+
184
+ #def test_freezes_models_on_run
185
+ #flunk
186
+ #end
187
+
188
+ test "count by project" do
189
+ ds = mock('dataset') do
190
+ expects(:naked).returns(self)
191
+ expects(:group_and_count).with(:project_id).returns(self)
192
+ expects(:to_hash).with(:project_id, :count).returns({ 1 => 1 })
193
+ end
194
+ Scenario.expects(:dataset).returns(ds)
195
+ assert_equal({1 => 1}, Scenario.count_by_project)
196
+ end
197
+ end
198
+ end
199
+ end
@@ -0,0 +1,193 @@
1
+ require 'helper'
2
+
3
+ module Coupler
4
+ module Models
5
+ class TestTransformation < Coupler::Test::UnitTest
6
+ def new_transformation(attribs = {})
7
+ values = {
8
+ :transformer => @transformer,
9
+ :resource => @resource,
10
+ :source_field => @source_field
11
+ }.update(attribs)
12
+ t = Transformation.new(values)
13
+ if values[:transformer]
14
+ t.stubs(:transformer_dataset).returns(stub({:all => [values[:transformer]]}))
15
+ end
16
+ if values[:source_field]
17
+ t.stubs(:source_field_dataset).returns(stub({:all => [values[:source_field]]}))
18
+ if values[:resource]
19
+ values[:resource].stubs(:fields_dataset).returns(stub('fields dataset') {
20
+ stubs(:[]).with(:id => values[:source_field].id).returns(values[:source_field])
21
+ })
22
+ end
23
+ end
24
+ if values[:result_field]
25
+ t.stubs(:result_field_dataset).returns(stub({:all => [values[:result_field]]}))
26
+ end
27
+ if values[:resource]
28
+ t.stubs(:resource_dataset).returns(stub({:all => [values[:resource]]}))
29
+ values[:resource].stubs(:fields_dataset).returns(stub('fields dataset') {
30
+ stubs(:[]).returns(nil)
31
+ if values[:source_field]
32
+ stubs(:[]).with(:id => values[:source_field].id).returns(values[:source_field])
33
+ end
34
+ if values[:result_field]
35
+ stubs(:[]).with(:id => values[:result_field].id).returns(values[:result_field])
36
+ end
37
+ })
38
+ end
39
+ t
40
+ end
41
+
42
+ def setup
43
+ super
44
+ @resource = stub('resource', :pk => 3, :id => 3, :associations => {}, :refresh_fields! => nil)
45
+ @transformer = stub('transformer', {
46
+ :pk => 1, :id => 1, :associations => {},
47
+ :allowed_types => %w{string}, :name => "foobar"
48
+ })
49
+ @source_field = stub('source_field', {
50
+ :pk => 7, :id => 7, :associations => {},
51
+ :final_type => 'string', :name => 'first_name'
52
+ })
53
+ @result_field = stub('result_field', {
54
+ :pk => 8, :id => 8, :associations => {},
55
+ :final_type => 'string', :name => 'new_first_name'
56
+ })
57
+ end
58
+
59
+ test "sequel model" do
60
+ assert_equal ::Sequel::Model, Transformation.superclass
61
+ assert_equal :transformations, Transformation.table_name
62
+ end
63
+
64
+ test "many to one resource" do
65
+ assert_respond_to Transformation.new, :resource
66
+ end
67
+
68
+ test "many to one source field" do
69
+ assert_respond_to Transformation.new, :source_field
70
+ end
71
+
72
+ test "many to one result field" do
73
+ assert_respond_to Transformation.new, :result_field
74
+ end
75
+
76
+ test "requires resource id" do
77
+ transformation = new_transformation(:resource => nil)
78
+ assert !transformation.valid?
79
+ end
80
+
81
+ test "requires existing transformer or nested attributes" do
82
+ transformation = new_transformation(:transformer => nil)
83
+ assert !transformation.valid?
84
+ end
85
+
86
+ test "requires correct field type" do
87
+ @source_field.stubs(:final_type).returns('integer')
88
+ transformation = new_transformation
89
+ assert !transformation.valid?
90
+ end
91
+
92
+ test "requires existing source field" do
93
+ transformation = new_transformation(:source_field => nil, :source_field_id => 1337)
94
+ assert !transformation.valid?
95
+ end
96
+
97
+ test "result field same as source field by default" do
98
+ transformation = new_transformation.save!
99
+ assert_equal transformation.result_field_id, @source_field.id
100
+ end
101
+
102
+ test "requires existing result field or nested attributes" do
103
+ transformation = new_transformation(:result_field_id => 1337)
104
+ assert !transformation.valid?
105
+ end
106
+
107
+ test "accepts nested attributes for transformer" do
108
+ assert_respond_to Transformation.new, :transformer_attributes=
109
+ end
110
+
111
+ test "transform with same source and result field" do
112
+ transformation = new_transformation(:result_field => @source_field).save!
113
+
114
+ data = {:id => 1, :first_name => "Peter"}
115
+ expected = stub("result")
116
+ @transformer.expects(:transform).with(data, { :in => :first_name, :out => :first_name }).returns(expected)
117
+
118
+ assert_equal expected, transformation.transform(data)
119
+ end
120
+
121
+ test "transform with differing source and result field" do
122
+ transformation = new_transformation(:result_field => @result_field)
123
+
124
+ data = {:id => 1, :first_name => "Peter"}
125
+ expected = stub("result")
126
+ transformation.transformer.expects(:transform).with(data, { :in => :first_name, :out => :new_first_name }).returns(expected)
127
+
128
+ assert_equal expected, transformation.transform(data)
129
+ end
130
+
131
+ test "field changes" do
132
+ transformation = new_transformation.save!
133
+ result = stub('result')
134
+ @transformer.expects(:field_changes).with(@source_field).returns(result)
135
+ assert_equal result, transformation.field_changes
136
+ end
137
+
138
+ test "updates resource fields on save" do
139
+ transformation = new_transformation
140
+ @resource.expects(:refresh_fields!)
141
+ transformation.save!
142
+ end
143
+
144
+ #def test_updates_resource_fields_on_destroy
145
+ #pend
146
+ #end
147
+
148
+ test "deletes orphaned result field on destroy" do
149
+ @result_field.stubs(:is_generated).returns(true)
150
+ @result_field.stubs(:scenarios_dataset).returns(stub(:count => 0))
151
+ transformation = new_transformation(:result_field => @result_field).save!
152
+ Transformation.expects(:filter).with(:result_field_id => 8).returns(mock(:count => 0))
153
+ @result_field.expects(:destroy)
154
+ transformation.destroy
155
+ end
156
+
157
+ test "does not delete result field in use by other transformation" do
158
+ @result_field.stubs(:is_generated).returns(true)
159
+ @result_field.stubs(:scenarios_dataset).returns(stub(:count => 0))
160
+ transformation = new_transformation(:result_field => @result_field).save!
161
+ Transformation.expects(:filter).with(:result_field_id => 8).returns(mock(:count => 1))
162
+ @result_field.expects(:destroy).never
163
+ transformation.destroy
164
+ end
165
+
166
+ test "prevents deletion if result field is in use by scenario" do
167
+ @result_field.stubs(:is_generated).returns(true)
168
+ @result_field.stubs(:scenarios_dataset).returns(stub(:count => 1))
169
+ transformation = new_transformation(:result_field => @result_field).save!
170
+ assert !transformation.destroy
171
+ end
172
+
173
+ test "prevents deletion unless in last position" do
174
+ transformation_1 = new_transformation(:position => 1).save!
175
+ transformation_2 = new_transformation(:position => 2).save!
176
+ assert !transformation_1.destroy
177
+ assert_not_nil Transformation[:id => transformation_1.id]
178
+ end
179
+
180
+ test "sets position by resource" do
181
+ resource_1 = stub('resource', :pk => 1, :id => 1, :associations => {}, :refresh_fields! => nil)
182
+ resource_2 = stub('resource', :pk => 2, :id => 2, :associations => {}, :refresh_fields! => nil)
183
+
184
+ xformation_1 = new_transformation(:resource => resource_1).save!
185
+ xformation_2 = new_transformation(:resource => resource_1).save!
186
+ xformation_3 = new_transformation(:resource => resource_2).save!
187
+ assert_equal 1, xformation_1.position
188
+ assert_equal 2, xformation_2.position
189
+ assert_equal 1, xformation_3.position
190
+ end
191
+ end
192
+ end
193
+ end
@@ -0,0 +1,188 @@
1
+ require 'helper'
2
+
3
+ module Coupler
4
+ module Models
5
+ class TestTransformer < Coupler::Test::UnitTest
6
+ def new_transformer(attribs = {})
7
+ values = {
8
+ :name => "foo",
9
+ :code => "value",
10
+ :allowed_types => %w{string integer datetime},
11
+ :result_type => 'same'
12
+ }.update(attribs)
13
+ Transformer.new(values)
14
+ end
15
+
16
+ test "sequel model" do
17
+ assert_equal ::Sequel::Model, Transformer.superclass
18
+ assert_equal :transformers, Transformer.table_name
19
+ end
20
+
21
+ test "requires name" do
22
+ xformer = new_transformer(:name => nil)
23
+ assert !xformer.valid?
24
+ end
25
+
26
+ test "requires unique name" do
27
+ new_transformer(:name => "foobar").save!
28
+ xformer = new_transformer(:name => "foobar")
29
+ assert !xformer.valid?
30
+ end
31
+
32
+ test "serializes allowed types" do
33
+ new_transformer.save!
34
+ xformer = Transformer[:name => "foo"]
35
+ assert_equal %w{string integer datetime}, xformer.allowed_types
36
+ end
37
+
38
+ test "requires allowed types" do
39
+ xformer = new_transformer(:allowed_types => nil)
40
+ assert !xformer.valid?
41
+ end
42
+
43
+ test "requires valid allowed types" do
44
+ xformer = new_transformer(:allowed_types => %w{blah})
45
+ assert !xformer.valid?
46
+ end
47
+
48
+ test "requires result type" do
49
+ xformer = new_transformer(:result_type => nil)
50
+ assert !xformer.valid?
51
+ end
52
+
53
+ test "requires valid result type" do
54
+ xformer = new_transformer(:result_type => "blah")
55
+ assert !xformer.valid?
56
+ end
57
+
58
+ test "special result type" do
59
+ xformer = new_transformer(:result_type => "same")
60
+ assert xformer.valid?
61
+ end
62
+
63
+ test "requires code" do
64
+ xformer = new_transformer(:code => nil)
65
+ assert !xformer.valid?
66
+ end
67
+
68
+ test "requires parseable code" do
69
+ xformer = new_transformer(:code => "foo(")
70
+ assert !xformer.valid?
71
+ end
72
+
73
+ test "no-op transform" do
74
+ xformer = new_transformer.save!
75
+ original = {:id => 1, :first_name => "Golan", :last_name => "Trevize"}
76
+ expected = original.dup
77
+ result = xformer.transform(original, { :in => :first_name, :out => :first_name })
78
+ assert_equal expected, result
79
+ end
80
+
81
+ test "transform new field" do
82
+ xformer = new_transformer(:code => "value.downcase", :allowed_types => %w{string}).save!
83
+ original = {:id => 1, :first_name => "Golan", :last_name => "Trevize"}
84
+ expected = original.merge(:first_name_small => "golan")
85
+ result = xformer.transform(original.dup, { :in => :first_name, :out => :first_name_small })
86
+ assert_equal expected, result
87
+ end
88
+
89
+ test "preview downcaser" do
90
+ xformer = new_transformer({
91
+ :name => "downcaser", :code => "value.to_s.downcase",
92
+ :allowed_types => %w{integer string datetime},
93
+ :result_type => "string"
94
+ })
95
+ now = Time.now
96
+ Timecop.freeze(now) do
97
+ expected = {
98
+ 'integer' => {:in => 123, :out => "123"},
99
+ 'string' => {:in => "Test", :out => "test"},
100
+ 'datetime' => {:in => now, :out => now.to_s.downcase},
101
+ 'success' => true
102
+ }
103
+ assert_equal expected, xformer.preview
104
+ end
105
+ end
106
+
107
+ test "preview fails if invalid" do
108
+ assert_nil Transformer.new.preview
109
+ end
110
+
111
+ test "preview code error returns exception" do
112
+ xformer = new_transformer({
113
+ :name => "downcaser", :code => "value.downcase",
114
+ :allowed_types => %w{integer string datetime},
115
+ :result_type => "string"
116
+ })
117
+ now = Time.now
118
+ Timecop.freeze(now) do
119
+ expected = {
120
+ 'integer' => {:in => 123, :out => Exception},
121
+ 'string' => {:in => "Test", :out => "test"},
122
+ 'datetime' => {:in => now, :out => Exception},
123
+ 'success' => false
124
+ }
125
+ assert expected === xformer.preview
126
+ end
127
+ end
128
+
129
+ test "requires successful preview" do
130
+ xformer = new_transformer({
131
+ :name => "downcaser", :code => "value.downcase",
132
+ :allowed_types => %w{integer string datetime},
133
+ :result_type => "string"
134
+ })
135
+ assert !xformer.valid?
136
+ end
137
+
138
+ test "requires correct result type" do
139
+ xformer = new_transformer({
140
+ :name => "stringify", :code => "value.to_i",
141
+ :allowed_types => %w{integer string datetime},
142
+ :result_type => "string"
143
+ })
144
+ assert !xformer.valid?
145
+ end
146
+
147
+ test "requires same result type" do
148
+ xformer = new_transformer({
149
+ :name => "stringify", :code => "value.to_i",
150
+ :allowed_types => %w{integer string datetime},
151
+ :result_type => "same"
152
+ })
153
+ assert !xformer.valid?
154
+ end
155
+
156
+ test "allows nil return value" do
157
+ xformer = new_transformer({
158
+ :name => "nullify", :code => "nil",
159
+ :allowed_types => %w{integer string datetime},
160
+ :result_type => "same"
161
+ })
162
+ assert xformer.valid?
163
+ end
164
+
165
+ test "field changes with no type changes" do
166
+ field = stub('field', :id => 1)
167
+ transformer = new_transformer({
168
+ :allowed_types => %w{integer datetime string},
169
+ :result_type => 'same', :code => 'value'
170
+ }).save!
171
+ assert_equal({ field.id => { } }, transformer.field_changes(field))
172
+ end
173
+
174
+ test "field changes to integer" do
175
+ field = stub('field', :id => 1)
176
+ transformer = new_transformer({
177
+ :allowed_types => %w{integer datetime string},
178
+ :result_type => 'integer', :code => 'value.to_i'
179
+ }).save!
180
+ assert_equal({ field.id => { :db_type => "int(11)", :type => :integer } }, transformer.field_changes(field))
181
+ end
182
+
183
+ #def test_should_handle_empty_values
184
+ #pend
185
+ #end
186
+ end
187
+ end
188
+ end
@@ -0,0 +1,60 @@
1
+ require 'helper'
2
+
3
+ module Coupler
4
+ class TestBase < Coupler::Test::UnitTest
5
+ def test_subclasses_sinatra_base
6
+ assert_equal Sinatra::Base, Coupler::Base.superclass
7
+ end
8
+
9
+ def test_index_when_no_projects
10
+ get "/"
11
+ assert last_response.ok?
12
+ assert_match /Getting Started/, last_response.body
13
+ end
14
+
15
+ def test_redirect_when_projects_exist
16
+ project = Factory(:project)
17
+ get "/"
18
+ assert last_response.redirect?
19
+ assert_equal "http://example.org/projects", last_response['location']
20
+ end
21
+
22
+ def test_db_path
23
+ env = Base.settings.environment
24
+ begin
25
+ Base.set :environment, :production
26
+ expected = File.join(Base.settings.data_path, 'db', 'production', 'ponies')
27
+ assert_equal expected, Base.db_path("ponies")
28
+ ensure
29
+ Base.set :environment, env
30
+ end
31
+ end
32
+
33
+ def test_connection_string
34
+ env = Base.settings.environment
35
+ begin
36
+ Base.set :environment, :production
37
+ expected = "jdbc:h2:#{File.join(Base.settings.data_path, 'db', 'production', 'ponies')};IGNORECASE=TRUE"
38
+ assert_equal expected, Base.connection_string("ponies")
39
+ ensure
40
+ Base.set :environment, env
41
+ end
42
+ end
43
+
44
+ def test_upload_path
45
+ env = Base.settings.environment
46
+ begin
47
+ Base.set :environment, :production
48
+ expected = File.join(Base.settings.data_path, 'uploads', 'production')
49
+ assert_equal expected, Base.upload_path
50
+ ensure
51
+ Base.set :environment, env
52
+ end
53
+ end
54
+
55
+ def test_log_path
56
+ expected = File.join(Base.settings.data_path, 'log')
57
+ assert_equal expected, Base.log_path
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,27 @@
1
+ require 'helper'
2
+
3
+ module Coupler
4
+ class TestDataUploader < Coupler::Test::UnitTest
5
+ def test_carrierwave_subclass
6
+ assert_equal CarrierWave::Uploader::Base, DataUploader.superclass
7
+ end
8
+
9
+ def test_store_dir_same_as_upload_path
10
+ Base.expects(:upload_path).returns("/path/to/uploads")
11
+ uploader = DataUploader.new
12
+ assert_equal "/path/to/uploads", uploader.store_dir
13
+ end
14
+
15
+ def test_cache_dir_uses_upload_path
16
+ Base.expects(:upload_path).returns("/path/to/uploads")
17
+ uploader = DataUploader.new
18
+ assert_equal "/path/to/uploads/tmp", uploader.cache_dir
19
+ end
20
+
21
+ def test_filename_uniqueness
22
+ uploader = DataUploader.new
23
+ uploader.store!(fixture_file_upload('people.csv'))
24
+ assert_match /^people-[a-f0-9]+.csv$/, uploader.filename
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,23 @@
1
+ require 'helper'
2
+
3
+ module Coupler
4
+ class TestDatabase < Coupler::Test::UnitTest
5
+ def setup
6
+ super
7
+ @database = Coupler::Database.instance
8
+ end
9
+
10
+ def test_connection
11
+ assert_kind_of Sequel::JDBC::Database, @database.__getobj__
12
+
13
+ expected = Base.connection_string('coupler')
14
+ assert_equal expected, @database.uri
15
+ end
16
+
17
+ def test_migrate
18
+ dir = File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "db", "migrate"))
19
+ Sequel::Migrator.expects(:apply).with(@database.__getobj__, dir)
20
+ @database.migrate!
21
+ end
22
+ end
23
+ end