offroad 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. data/LICENSE +674 -0
  2. data/README.rdoc +29 -0
  3. data/Rakefile +75 -0
  4. data/TODO +42 -0
  5. data/lib/app/models/offroad/group_state.rb +85 -0
  6. data/lib/app/models/offroad/mirror_info.rb +53 -0
  7. data/lib/app/models/offroad/model_state.rb +36 -0
  8. data/lib/app/models/offroad/received_record_state.rb +109 -0
  9. data/lib/app/models/offroad/sendable_record_state.rb +91 -0
  10. data/lib/app/models/offroad/system_state.rb +33 -0
  11. data/lib/cargo_streamer.rb +222 -0
  12. data/lib/controller_extensions.rb +74 -0
  13. data/lib/exceptions.rb +16 -0
  14. data/lib/migrate/20100512164608_create_offroad_tables.rb +72 -0
  15. data/lib/mirror_data.rb +354 -0
  16. data/lib/model_extensions.rb +377 -0
  17. data/lib/module_funcs.rb +94 -0
  18. data/lib/offroad.rb +30 -0
  19. data/lib/version.rb +3 -0
  20. data/lib/view_helper.rb +7 -0
  21. data/templates/offline.rb +36 -0
  22. data/templates/offline_database.yml +7 -0
  23. data/templates/offroad.yml +6 -0
  24. data/test/app_root/app/controllers/application_controller.rb +2 -0
  25. data/test/app_root/app/controllers/group_controller.rb +28 -0
  26. data/test/app_root/app/models/global_record.rb +10 -0
  27. data/test/app_root/app/models/group.rb +12 -0
  28. data/test/app_root/app/models/group_owned_record.rb +68 -0
  29. data/test/app_root/app/models/guest.rb +7 -0
  30. data/test/app_root/app/models/subrecord.rb +12 -0
  31. data/test/app_root/app/models/unmirrored_record.rb +4 -0
  32. data/test/app_root/app/views/group/download_down_mirror.html.erb +4 -0
  33. data/test/app_root/app/views/group/download_initial_down_mirror.html.erb +4 -0
  34. data/test/app_root/app/views/group/download_up_mirror.html.erb +6 -0
  35. data/test/app_root/app/views/group/upload_down_mirror.html.erb +1 -0
  36. data/test/app_root/app/views/group/upload_up_mirror.html.erb +1 -0
  37. data/test/app_root/app/views/layouts/mirror.html.erb +9 -0
  38. data/test/app_root/config/boot.rb +115 -0
  39. data/test/app_root/config/database.yml +6 -0
  40. data/test/app_root/config/environment.rb +15 -0
  41. data/test/app_root/config/environments/test.rb +17 -0
  42. data/test/app_root/config/offroad.yml +6 -0
  43. data/test/app_root/config/routes.rb +4 -0
  44. data/test/app_root/db/migrate/20100529235049_create_tables.rb +64 -0
  45. data/test/app_root/lib/common_hobo.rb +15 -0
  46. data/test/app_root/vendor/plugins/offroad/init.rb +2 -0
  47. data/test/functional/mirror_operations_test.rb +148 -0
  48. data/test/test_helper.rb +405 -0
  49. data/test/unit/app_state_tracking_test.rb +275 -0
  50. data/test/unit/cargo_streamer_test.rb +332 -0
  51. data/test/unit/global_data_test.rb +102 -0
  52. data/test/unit/group_controller_test.rb +152 -0
  53. data/test/unit/group_data_test.rb +435 -0
  54. data/test/unit/group_single_test.rb +136 -0
  55. data/test/unit/hobo_permissions_test.rb +57 -0
  56. data/test/unit/mirror_data_test.rb +1271 -0
  57. data/test/unit/mirror_info_test.rb +31 -0
  58. data/test/unit/module_funcs_test.rb +37 -0
  59. data/test/unit/pathological_model_test.rb +62 -0
  60. data/test/unit/test_framework_test.rb +86 -0
  61. data/test/unit/unmirrored_data_test.rb +14 -0
  62. metadata +140 -0
@@ -0,0 +1,332 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ class CargoStreamerTest < Test::Unit::TestCase
4
+ # Based on the pattern found here: http://stackoverflow.com/questions/315850/rails-model-without-database
5
+ class TestModel < ActiveRecord::Base
6
+ self.abstract_class = true
7
+
8
+ def self.columns
9
+ @columns ||= []
10
+ end
11
+
12
+ columns << ActiveRecord::ConnectionAdapters::Column.new("id", nil, "integer", true)
13
+ columns << ActiveRecord::ConnectionAdapters::Column.new("data", "", "string", false)
14
+
15
+ has_one(:fake_association)
16
+ attr_accessor :fake_association
17
+
18
+ validates_presence_of :data
19
+
20
+ @@safety_switch = true
21
+
22
+ def self.safe_to_load_from_cargo_stream?
23
+ @@safety_switch
24
+ end
25
+
26
+ def self.set_safe
27
+ @@safety_switch = true
28
+ end
29
+
30
+ def self.set_unsafe
31
+ @@safety_switch = false
32
+ end
33
+ end
34
+
35
+ def generate_cargo_string(hash, skip_validation = false)
36
+ return StringIO.open do |sio|
37
+ writer = Offroad::CargoStreamer.new(sio, "w")
38
+ hash.each do |key, arr|
39
+ arr.each do |elem|
40
+ writer.write_cargo_section(key, elem, :skip_validation => skip_validation)
41
+ end
42
+ end
43
+
44
+ sio.string
45
+ end
46
+ end
47
+
48
+ def retrieve_cargo_from_string(str)
49
+ hash = {}
50
+
51
+ reader = Offroad::CargoStreamer.new(str, "r")
52
+ reader.cargo_section_names.each do |key|
53
+ hash[key] = []
54
+ reader.each_cargo_section(key) do |elem|
55
+ hash[key] << elem
56
+ end
57
+ end
58
+
59
+ return hash
60
+ end
61
+
62
+ def round_trip(hash = {})
63
+ retrieve_cargo_from_string(generate_cargo_string(hash))
64
+ end
65
+
66
+ # Asserts content equality between two hashes of arrays of arrays of records ("haar"s)
67
+ # Cannot just do new_hash == hash, because ActiveRecord#== always false when comparing two unsaved records.
68
+ def assert_haar_equality(first_hash, second_hash)
69
+ assert_nothing_raised do
70
+ # Assert that they are subsets of each other
71
+ [[first_hash, second_hash], [second_hash, first_hash]].each do |hash_a, hash_b|
72
+ hash_a.each do |key, arr|
73
+ arr.each_with_index do |subarr, i|
74
+ subarr.each_with_index do |rec, j|
75
+ rec.attributes.each_pair do |attr_key, attr_value|
76
+ raise "Mismatch" unless attr_value == hash_b[key][i][j].attributes[attr_key]
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
84
+
85
+ def assert_round_trip_equality(hash = {})
86
+ assert_haar_equality(hash, round_trip(hash))
87
+ end
88
+
89
+ def test_rec(str)
90
+ TestModel.new(:data => str)
91
+ end
92
+
93
+ agnostic_test "can encode and retrieve a model instances in an array" do
94
+ assert_round_trip_equality "test" => [[test_rec("A"), test_rec("B")]]
95
+ end
96
+
97
+ agnostic_test "can encode and retrieve model instances with first-level association data" do
98
+ r1 = test_rec("A")
99
+ r1.fake_association = test_rec("B")
100
+ r2 = test_rec("XYZ") # Making sure we can also encode a model instance that doesn't have the assoc data
101
+
102
+ str = StringIO.open do |sio|
103
+ writer = Offroad::CargoStreamer.new(sio, "w")
104
+ writer.write_cargo_section("abc", [r1, r2], :include => [:fake_association])
105
+ sio.string
106
+ end
107
+
108
+ decoded_rec = StringIO.open(str) do |sio|
109
+ cs = Offroad::CargoStreamer.new(sio, "r")
110
+ cs.first_cargo_section("abc")[0]
111
+ end
112
+
113
+ assert_equal "B", decoded_rec.fake_association.data
114
+ end
115
+
116
+ agnostic_test "encoded models do not lose their id" do
117
+ rec = test_rec("ABC")
118
+ rec.id = 45
119
+ decoded = round_trip "test" => [[rec]]
120
+ assert_equal 45, decoded["test"][0][0].id
121
+ end
122
+
123
+ agnostic_test "cannot encode and retrieve non-model data" do
124
+ assert_raise Offroad::CargoStreamerError do
125
+ generate_cargo_string "a" => [[1]]
126
+ end
127
+ end
128
+
129
+ agnostic_test "cannot encode a model that is not in an array" do
130
+ assert_raise Offroad::CargoStreamerError do
131
+ # This is not "in an array" for CargoStreamer; look at how generate_cargo_string is implemented
132
+ generate_cargo_string "a" => [test_rec("Test")]
133
+ end
134
+ end
135
+
136
+ agnostic_test "can decode cargo data even if there is other stuff around it" do
137
+ test_hash = {"foo bar narf bork" => [[test_rec("Test")]]}
138
+ str = "BLAH BLAH BLAH" + generate_cargo_string(test_hash) + "BAR BAR BAR"
139
+ assert_haar_equality test_hash, retrieve_cargo_from_string(str)
140
+ end
141
+
142
+ agnostic_test "can correctly identify the names of the cargo sections" do
143
+ test_hash = {"abc" => [[test_rec("A")]], "xyz" => [[test_rec("X")]]}
144
+ cs = Offroad::CargoStreamer.new(generate_cargo_string(test_hash), "r")
145
+ assert_equal test_hash.keys, cs.cargo_section_names
146
+ assert cs.has_cargo_named?("abc")
147
+ assert_equal false, cs.has_cargo_named?("foobar")
148
+ end
149
+
150
+ agnostic_test "can create and retrieve multiple ordered cargo sections with the same name" do
151
+ test_data = [[test_rec("a"), test_rec("b")], [test_rec("c"), test_rec("d")], [test_rec("e"), test_rec("f")]]
152
+
153
+ str = StringIO.open do |sio|
154
+ cs = Offroad::CargoStreamer.new(sio, "w")
155
+ test_data.each do |dat|
156
+ cs.write_cargo_section("xyz", dat)
157
+ end
158
+ sio.string
159
+ end
160
+
161
+ result_data = []
162
+ cs = Offroad::CargoStreamer.new(str, "r")
163
+ cs.each_cargo_section "xyz" do |dat|
164
+ result_data << dat
165
+ end
166
+
167
+ assert_haar_equality({"test" => test_data}, {"test" => result_data})
168
+ end
169
+
170
+ agnostic_test "can use first_cargo_section to get only the first section with a given name" do
171
+ result = StringIO.open do |sio|
172
+ cs = Offroad::CargoStreamer.new(sio, "w")
173
+ for i in 1..3 do
174
+ cs.write_cargo_section("testing", [test_rec("item number #{i}")])
175
+ end
176
+ sio.string
177
+ end
178
+
179
+ cs = Offroad::CargoStreamer.new(result, "r")
180
+ assert_equal test_rec("item number 1").attributes, cs.first_cargo_section("testing")[0].attributes
181
+ assert_equal nil, cs.first_cargo_section("no-such-section")
182
+ end
183
+
184
+ agnostic_test "can use first_cargo_element to get the first element of the first section with a given name" do
185
+ result = StringIO.open do |sio|
186
+ cs = Offroad::CargoStreamer.new(sio, "w")
187
+ [10, 20, 30].each do |i|
188
+ cs.write_cargo_section("testing", [test_rec("item number #{i}"), test_rec("item number #{i+1}")])
189
+ end
190
+ sio.string
191
+ end
192
+
193
+ cs = Offroad::CargoStreamer.new(result, "r")
194
+ assert_equal test_rec("item number 10").attributes, cs.first_cargo_element("testing").attributes
195
+ assert_equal nil, cs.first_cargo_element("no-such-section")
196
+ end
197
+
198
+ agnostic_test "can use :human_readable to include a string version of a record" do
199
+ test_str = "ABCD\n123"
200
+ rec = test_rec(test_str)
201
+
202
+ result = StringIO.open do |sio|
203
+ cs = Offroad::CargoStreamer.new(sio, "w")
204
+ cs.write_cargo_section("test", [rec], :human_readable => false)
205
+ sio.string
206
+ end
207
+ assert_equal false, result.include?(test_str)
208
+
209
+ result = StringIO.open do |sio|
210
+ cs = Offroad::CargoStreamer.new(sio, "w")
211
+ cs.write_cargo_section("test", [rec], :human_readable => true)
212
+ sio.string
213
+ end
214
+ assert result.include?(test_str)
215
+ end
216
+
217
+ agnostic_test "uses an md5 fingerprint to detect corruption" do
218
+ str = generate_cargo_string "test" => [[test_rec("abc")]]
219
+
220
+ md5sum = nil
221
+ if str =~ /\b([0-9a-f]{32})\b/
222
+ md5sum = $1
223
+ else
224
+ flunk "Unable to find an md5sum in the generated string"
225
+ end
226
+ assert_raise Offroad::CargoStreamerError, "Changing fingerprint causes exception to be raised" do
227
+ retrieve_cargo_from_string(str.gsub md5sum, "a"*md5sum.size)
228
+ end
229
+
230
+ assert_raise Offroad::CargoStreamerError, "Changing base64 content causes exception to be raised" do
231
+ # This is somewhat of an implementation-dependent test; I checked manually that the data has these strings.
232
+ # It's safe, though, as changing the implementation should cause false neg, not false pos.
233
+ retrieve_cargo_from_string(str.sub("X", "x"))
234
+ end
235
+ end
236
+
237
+ agnostic_test "modes r and w work, other modes do not" do
238
+ assert_nothing_raised "Mode r works" do
239
+ Offroad::CargoStreamer.new(StringIO.new(), "r")
240
+ end
241
+
242
+ assert_nothing_raised "Mode w works" do
243
+ Offroad::CargoStreamer.new(StringIO.new(), "w")
244
+ end
245
+
246
+ assert_raise Offroad::CargoStreamerError, "Mode a doesn't work" do
247
+ Offroad::CargoStreamer.new(StringIO.new(), "a")
248
+ end
249
+ end
250
+
251
+ agnostic_test "cannot write cargo in read mode" do
252
+ assert_raise Offroad::CargoStreamerError do
253
+ cs = Offroad::CargoStreamer.new(StringIO.new, "r")
254
+ cs.write_cargo_section("test", [test_rec("test")])
255
+ end
256
+ end
257
+
258
+ agnostic_test "cannot use invalid cargo section names" do
259
+ cs = Offroad::CargoStreamer.new(StringIO.new, "w")
260
+
261
+ assert_raise Offroad::CargoStreamerError, "Expect exception for symbol cargo name" do
262
+ cs.write_cargo_section(:test, [test_rec("test")])
263
+ end
264
+
265
+ assert_raise Offroad::CargoStreamerError, "Expect exception for cargo name that's bad in HTML comments" do
266
+ cs.write_cargo_section("whatever--foobar", [test_rec("test")])
267
+ end
268
+
269
+ assert_raise Offroad::CargoStreamerError, "Expect exception for cargo name that's multiline" do
270
+ cs.write_cargo_section("whatever\nfoobar", [test_rec("test")])
271
+ end
272
+ end
273
+
274
+ agnostic_test "cannot encode invalid records except with :skip_validation option" do
275
+ rec = TestModel.new() # Nothing set to the required "data" field
276
+ assert_equal false, rec.valid?
277
+ assert_raise Offroad::CargoStreamerError do
278
+ generate_cargo_string "foo" => [[rec]]
279
+ end
280
+ assert_nothing_raised Offroad::CargoStreamerError do
281
+ generate_cargo_string({"foo" => [[rec]]}, true)
282
+ end
283
+ rec.data = "Something"
284
+ assert_nothing_raised do
285
+ generate_cargo_string "foo" => [[rec]]
286
+ end
287
+ end
288
+
289
+ agnostic_test "cannot encode a non-safe model class" do
290
+ begin
291
+ TestModel.set_safe
292
+ assert_nothing_raised do
293
+ str = generate_cargo_string "test" => [[test_rec("ABC")]]
294
+ end
295
+ TestModel.set_unsafe
296
+ assert_raise Offroad::CargoStreamerError do
297
+ str = generate_cargo_string "test" => [[test_rec("ABC")]]
298
+ end
299
+ ensure
300
+ TestModel.set_safe
301
+ end
302
+ end
303
+
304
+ agnostic_test "cannot trick cargo streamer into decoding a non-safe model class" do
305
+ begin
306
+ TestModel.set_safe
307
+ str = generate_cargo_string "test" => [[test_rec("Stuff")]]
308
+
309
+ assert_nothing_raised do
310
+ retrieve_cargo_from_string(str)
311
+ end
312
+ TestModel.set_unsafe
313
+ assert_raise Offroad::CargoStreamerError do
314
+ retrieve_cargo_from_string(str)
315
+ end
316
+ ensure
317
+ TestModel.set_safe
318
+ end
319
+ end
320
+
321
+ agnostic_test "cargo streamer can read directly from a passed in string" do
322
+ str = generate_cargo_string("test" => [[test_rec("abc")]])
323
+ cs = Offroad::CargoStreamer.new(str, "r")
324
+ assert cs.has_cargo_named?("test")
325
+ end
326
+
327
+ agnostic_test "cannot have cargo streamer write to a passed in string" do
328
+ assert_raise Offroad::CargoStreamerError do
329
+ Offroad::CargoStreamer.new("", "w")
330
+ end
331
+ end
332
+ end
@@ -0,0 +1,102 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ # This is a unit test on the ability of model_extensions to handle global models
4
+
5
+ class GlobalDataTest < Test::Unit::TestCase
6
+ online_test "can create new global records" do
7
+ assert_nothing_raised do
8
+ GlobalRecord.create(:title => "Something or other")
9
+ end
10
+ end
11
+
12
+ offline_test "cannot create new global records" do
13
+ assert_raise ActiveRecord::ReadOnlyRecord do
14
+ GlobalRecord.create(:title => "Foo bar baz bork")
15
+ end
16
+ end
17
+
18
+ double_test "global data models report being global data" do
19
+ assert GlobalRecord.offroad_global_data?, "Global model should return true to offroad_global_data?"
20
+ assert_equal false, GlobalRecord.offroad_group_data?, "Global model should return false to offroad_group_data?"
21
+ end
22
+
23
+ online_test "global data is writable and destroyable" do
24
+ global_record = GlobalRecord.create(:title => "Something or other")
25
+ assert !global_record.locked_by_offroad?
26
+ assert_nothing_raised do
27
+ global_record.title = "Something else"
28
+ global_record.save!
29
+ global_record.destroy
30
+ end
31
+
32
+ if HOBO_TEST_MODE
33
+ guest = Guest.new
34
+ global_record.permissive = true
35
+ assert global_record.creatable_by?(guest)
36
+ assert global_record.updatable_by?(guest)
37
+ assert global_record.destroyable_by?(guest)
38
+ end
39
+ end
40
+
41
+ offline_test "global data is not writable or destroyable" do
42
+ global_record = GlobalRecord.new(:title => "Something or other")
43
+ force_save_and_reload(global_record)
44
+ assert global_record.locked_by_offroad?
45
+
46
+ assert_raise ActiveRecord::ReadOnlyRecord, "expect exception on title change" do
47
+ global_record.title = "Something else"
48
+ global_record.save!
49
+ end
50
+
51
+ assert_raise ActiveRecord::ReadOnlyRecord, "expect exception on destroy" do
52
+ global_record.destroy
53
+ end
54
+
55
+ if HOBO_TEST_MODE
56
+ guest = Guest.new
57
+ global_record.permissive = true
58
+ assert !global_record.creatable_by?(guest)
59
+ assert !global_record.updatable_by?(guest)
60
+ assert !global_record.destroyable_by?(guest)
61
+ end
62
+ end
63
+
64
+ online_test "cannot change id of global data" do
65
+ global_record = GlobalRecord.create(:title => "Something or other")
66
+ assert_raise Offroad::DataError do
67
+ global_record.id += 1
68
+ global_record.save!
69
+ end
70
+ end
71
+
72
+ online_test "global data can hold a foreign key to other global data" do
73
+ global_record = GlobalRecord.create(:title => "Something or other")
74
+ another_global_record = GlobalRecord.create(:title => "Yet Another")
75
+
76
+ assert_nothing_raised do
77
+ global_record.friend = another_global_record
78
+ global_record.save!
79
+ end
80
+ end
81
+
82
+ online_test "global data cannot hold a foreign key to group data" do
83
+ global_record = GlobalRecord.create(:title => "Something or other")
84
+ assert_raise Offroad::DataError do
85
+ global_record.some_group = @offline_group
86
+ global_record.save!
87
+ end
88
+ end
89
+
90
+ online_test "global data cannot hold a foreign key to unmirrored data" do
91
+ global_record = GlobalRecord.create(:title => "Something or other")
92
+ unmirrored_data = UnmirroredRecord.create(:content => "Some Unmirrored Data")
93
+ assert_raise Offroad::DataError do
94
+ global_record.unmirrored_record = unmirrored_data
95
+ global_record.save!
96
+ end
97
+ end
98
+
99
+ double_test "global data models return true to acts_as_offroadable?" do
100
+ assert GlobalRecord.acts_as_offroadable?
101
+ end
102
+ end
@@ -0,0 +1,152 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ # This just tests the controller's ability to properly access the functionality of the MirrorData class
4
+ # Tests for the actual generation and processing of mirror files are in mirror_data_test.rb
5
+
6
+ class GroupControllerTest < ActionController::TestCase
7
+ online_test "can retrieve a down mirror file for the offline group" do
8
+ get :download_down_mirror, "id" => @offline_group.id
9
+ assert_response :success
10
+ assert @response.headers["Content-Disposition"].include?("attachment")
11
+ content = @response.binary_content
12
+ assert content.include?("downloaded from the Test App online system"), "testapp's down mirror view file used"
13
+
14
+ StringIO.open(content) do |sio|
15
+ cs = Offroad::CargoStreamer.new(sio, "r")
16
+ mirror_info = cs.first_cargo_element("mirror_info")
17
+ assert mirror_info.app_mode.downcase.include?("online")
18
+ assert_equal false, mirror_info.initial_file
19
+ end
20
+ end
21
+
22
+ online_test "can retrieve an initial down mirror file for the offline group" do
23
+ get :download_initial_down_mirror, "id" => @offline_group.id
24
+ assert_response :success
25
+ assert @response.headers["Content-Disposition"].include?("attachment")
26
+ content = @response.binary_content
27
+ assert content.include?("downloaded from the Test App online system"), "testapp's down mirror view file used"
28
+
29
+ StringIO.open(content) do |sio|
30
+ cs = Offroad::CargoStreamer.new(sio, "r")
31
+ mirror_info = cs.first_cargo_element("mirror_info")
32
+ assert mirror_info.app_mode.downcase.include?("online")
33
+ assert mirror_info.initial_file
34
+ end
35
+ end
36
+
37
+ offline_test "can retrieve an up mirror file for the offline group" do
38
+ get :download_up_mirror, "id" => @offline_group.id
39
+ assert_response :success
40
+ assert @response.headers["Content-Disposition"].include?("attachment")
41
+ content = @response.binary_content
42
+ assert content.include?("to the Test App online system"), "testapp's up mirror view file was used"
43
+
44
+ # This tests ViewHelper::link_to_online_app, used from the testapp's up mirror view
45
+ assert content.include?(">" + Offroad::online_url + "</a>")
46
+ assert content.include?("href=\"" + Offroad::online_url + "\"")
47
+
48
+ StringIO.open(content) do |sio|
49
+ cs = Offroad::CargoStreamer.new(sio, "r")
50
+ assert cs.first_cargo_element("mirror_info").app_mode.downcase.include?("offline")
51
+ end
52
+ end
53
+
54
+ online_test "cannot retrieve up mirror files" do
55
+ assert_raise Offroad::PluginError do
56
+ get :download_up_mirror, "id" => @offline_group.id
57
+ end
58
+ end
59
+
60
+ online_test "cannot retrieve down mirror files for online groups" do
61
+ assert_raise Offroad::PluginError do
62
+ get :download_down_mirror, "id" => @online_group.id
63
+ end
64
+ end
65
+
66
+ cross_test "can upload up mirror files" do
67
+ mirror_data = ""
68
+ in_offline_app do
69
+ @offline_group.name = "ABC"
70
+ @offline_group.save!
71
+ get :download_up_mirror, "id" => @offline_group.id
72
+ mirror_data = @response.binary_content
73
+ end
74
+
75
+ in_online_app do
76
+ post :upload_up_mirror, "id" => @offline_group.id, "mirror_data" => mirror_data
77
+ assert_response :success
78
+ @offline_group.reload
79
+ assert_equal "ABC", @offline_group.name
80
+ end
81
+ end
82
+
83
+ offline_test "can upload down mirror files" do
84
+ mirror_data = ""
85
+ in_online_app do
86
+ GlobalRecord.create!(:title => "123")
87
+ get :download_down_mirror, "id" => @offline_group.id
88
+ mirror_data = @response.binary_content
89
+ end
90
+
91
+ in_offline_app do
92
+ assert_equal 0, GlobalRecord.count
93
+ post :upload_down_mirror, "id" => @offline_group.id, "mirror_data" => mirror_data
94
+ assert_response :success
95
+ assert_equal 1, GlobalRecord.count
96
+ assert_equal "123", GlobalRecord.first.title
97
+ end
98
+ end
99
+
100
+ cross_test "can upload initial down mirror files" do
101
+ mirror_data = ""
102
+ in_online_app do
103
+ get :download_initial_down_mirror, "id" => @offline_group.id
104
+ mirror_data = @response.binary_content
105
+ end
106
+
107
+ in_offline_app(false, true) do
108
+ assert_equal 0, Group.count
109
+ post :upload_initial_down_mirror, "mirror_data" => mirror_data
110
+ assert_equal 1, Group.count
111
+ end
112
+ end
113
+
114
+ offline_test "cannot retrieve down mirror files" do
115
+ assert_raise Offroad::PluginError do
116
+ get :download_down_mirror, {"id" => @offline_group.id}
117
+ end
118
+ end
119
+
120
+ offline_test "cannot upload up mirror files" do
121
+ get :download_up_mirror, "id" => @offline_group.id
122
+ mirror_data = @response.binary_content
123
+
124
+ assert_raise Offroad::PluginError do
125
+ post :upload_up_mirror, "id" => @offline_group.id, "mirror_data" => mirror_data
126
+ end
127
+ end
128
+
129
+ online_test "cannot upload down mirror files" do
130
+ get :download_down_mirror, "id" => @offline_group.id
131
+ mirror_data = @response.binary_content
132
+
133
+ assert_raise Offroad::PluginError do
134
+ post :upload_down_mirror, "id" => @offline_group.id, "mirror_data" => mirror_data
135
+ end
136
+ end
137
+
138
+ cross_test "cannot upload a mirror file for an online group" do
139
+ mirror_data = ""
140
+ in_offline_app do
141
+ get :download_up_mirror, "id" => @offline_group.id
142
+ mirror_data = @response.binary_content
143
+ end
144
+
145
+ in_online_app do
146
+ @offline_group.group_offline = false
147
+ assert_raise Offroad::PluginError do
148
+ post :upload_up_mirror, "id" => @online_group.id, "mirror_data" => mirror_data
149
+ end
150
+ end
151
+ end
152
+ end