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.
- data/LICENSE +674 -0
- data/README.rdoc +29 -0
- data/Rakefile +75 -0
- data/TODO +42 -0
- data/lib/app/models/offroad/group_state.rb +85 -0
- data/lib/app/models/offroad/mirror_info.rb +53 -0
- data/lib/app/models/offroad/model_state.rb +36 -0
- data/lib/app/models/offroad/received_record_state.rb +109 -0
- data/lib/app/models/offroad/sendable_record_state.rb +91 -0
- data/lib/app/models/offroad/system_state.rb +33 -0
- data/lib/cargo_streamer.rb +222 -0
- data/lib/controller_extensions.rb +74 -0
- data/lib/exceptions.rb +16 -0
- data/lib/migrate/20100512164608_create_offroad_tables.rb +72 -0
- data/lib/mirror_data.rb +354 -0
- data/lib/model_extensions.rb +377 -0
- data/lib/module_funcs.rb +94 -0
- data/lib/offroad.rb +30 -0
- data/lib/version.rb +3 -0
- data/lib/view_helper.rb +7 -0
- data/templates/offline.rb +36 -0
- data/templates/offline_database.yml +7 -0
- data/templates/offroad.yml +6 -0
- data/test/app_root/app/controllers/application_controller.rb +2 -0
- data/test/app_root/app/controllers/group_controller.rb +28 -0
- data/test/app_root/app/models/global_record.rb +10 -0
- data/test/app_root/app/models/group.rb +12 -0
- data/test/app_root/app/models/group_owned_record.rb +68 -0
- data/test/app_root/app/models/guest.rb +7 -0
- data/test/app_root/app/models/subrecord.rb +12 -0
- data/test/app_root/app/models/unmirrored_record.rb +4 -0
- data/test/app_root/app/views/group/download_down_mirror.html.erb +4 -0
- data/test/app_root/app/views/group/download_initial_down_mirror.html.erb +4 -0
- data/test/app_root/app/views/group/download_up_mirror.html.erb +6 -0
- data/test/app_root/app/views/group/upload_down_mirror.html.erb +1 -0
- data/test/app_root/app/views/group/upload_up_mirror.html.erb +1 -0
- data/test/app_root/app/views/layouts/mirror.html.erb +9 -0
- data/test/app_root/config/boot.rb +115 -0
- data/test/app_root/config/database.yml +6 -0
- data/test/app_root/config/environment.rb +15 -0
- data/test/app_root/config/environments/test.rb +17 -0
- data/test/app_root/config/offroad.yml +6 -0
- data/test/app_root/config/routes.rb +4 -0
- data/test/app_root/db/migrate/20100529235049_create_tables.rb +64 -0
- data/test/app_root/lib/common_hobo.rb +15 -0
- data/test/app_root/vendor/plugins/offroad/init.rb +2 -0
- data/test/functional/mirror_operations_test.rb +148 -0
- data/test/test_helper.rb +405 -0
- data/test/unit/app_state_tracking_test.rb +275 -0
- data/test/unit/cargo_streamer_test.rb +332 -0
- data/test/unit/global_data_test.rb +102 -0
- data/test/unit/group_controller_test.rb +152 -0
- data/test/unit/group_data_test.rb +435 -0
- data/test/unit/group_single_test.rb +136 -0
- data/test/unit/hobo_permissions_test.rb +57 -0
- data/test/unit/mirror_data_test.rb +1271 -0
- data/test/unit/mirror_info_test.rb +31 -0
- data/test/unit/module_funcs_test.rb +37 -0
- data/test/unit/pathological_model_test.rb +62 -0
- data/test/unit/test_framework_test.rb +86 -0
- data/test/unit/unmirrored_data_test.rb +14 -0
- 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
|