offroad 0.0.1

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 (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