offroad 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. data/LICENSE +674 -674
  2. data/README.rdoc +29 -29
  3. data/Rakefile +75 -75
  4. data/TODO +42 -42
  5. data/lib/app/models/offroad/group_state.rb +85 -85
  6. data/lib/app/models/offroad/mirror_info.rb +53 -53
  7. data/lib/app/models/offroad/model_state.rb +36 -36
  8. data/lib/app/models/offroad/received_record_state.rb +115 -115
  9. data/lib/app/models/offroad/sendable_record_state.rb +91 -91
  10. data/lib/app/models/offroad/system_state.rb +33 -33
  11. data/lib/cargo_streamer.rb +222 -222
  12. data/lib/controller_extensions.rb +74 -74
  13. data/lib/exceptions.rb +16 -16
  14. data/lib/migrate/20100512164608_create_offroad_tables.rb +72 -72
  15. data/lib/mirror_data.rb +376 -376
  16. data/lib/model_extensions.rb +378 -377
  17. data/lib/module_funcs.rb +94 -94
  18. data/lib/offroad.rb +41 -41
  19. data/lib/version.rb +3 -3
  20. data/lib/view_helper.rb +7 -7
  21. data/templates/offline.rb +36 -36
  22. data/templates/offline_database.yml +7 -7
  23. data/templates/offroad.yml +6 -6
  24. data/test/app_root/app/controllers/application_controller.rb +2 -2
  25. data/test/app_root/app/controllers/group_controller.rb +28 -28
  26. data/test/app_root/app/models/global_record.rb +10 -10
  27. data/test/app_root/app/models/group.rb +12 -12
  28. data/test/app_root/app/models/group_owned_record.rb +68 -68
  29. data/test/app_root/app/models/guest.rb +7 -7
  30. data/test/app_root/app/models/subrecord.rb +12 -12
  31. data/test/app_root/app/models/unmirrored_record.rb +4 -4
  32. data/test/app_root/app/views/group/download_down_mirror.html.erb +3 -3
  33. data/test/app_root/app/views/group/download_initial_down_mirror.html.erb +3 -3
  34. data/test/app_root/app/views/group/download_up_mirror.html.erb +5 -5
  35. data/test/app_root/app/views/layouts/mirror.html.erb +8 -8
  36. data/test/app_root/config/boot.rb +115 -115
  37. data/test/app_root/config/database-pg.yml +8 -8
  38. data/test/app_root/config/database.yml +5 -5
  39. data/test/app_root/config/environment.rb +24 -24
  40. data/test/app_root/config/environments/test.rb +17 -17
  41. data/test/app_root/config/offroad.yml +6 -6
  42. data/test/app_root/config/routes.rb +4 -4
  43. data/test/app_root/db/migrate/20100529235049_create_tables.rb +64 -64
  44. data/test/app_root/lib/common_hobo.rb +15 -15
  45. data/test/app_root/vendor/plugins/offroad/init.rb +2 -2
  46. data/test/functional/mirror_operations_test.rb +148 -148
  47. data/test/test_helper.rb +453 -453
  48. data/test/unit/app_state_tracking_test.rb +275 -275
  49. data/test/unit/cargo_streamer_test.rb +332 -332
  50. data/test/unit/global_data_test.rb +102 -102
  51. data/test/unit/group_controller_test.rb +152 -152
  52. data/test/unit/group_data_test.rb +442 -435
  53. data/test/unit/group_single_test.rb +136 -136
  54. data/test/unit/hobo_permissions_test.rb +57 -57
  55. data/test/unit/mirror_data_test.rb +1283 -1283
  56. data/test/unit/mirror_info_test.rb +31 -31
  57. data/test/unit/module_funcs_test.rb +37 -37
  58. data/test/unit/pathological_model_test.rb +62 -62
  59. data/test/unit/test_framework_test.rb +86 -86
  60. data/test/unit/unmirrored_data_test.rb +14 -14
  61. metadata +6 -8
@@ -1,136 +1,136 @@
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 models in group_single mode
4
-
5
- class GroupSingleTest < Test::Unit::TestCase
6
- def setup
7
- super
8
- self.class.const_set("GroupSingleRecord", Class.new(ActiveRecord::Base))
9
- GroupSingleRecord.send(:acts_as_offroadable, :group_single)
10
- end
11
-
12
- def teardown
13
- # Manually remove the group_single model after the test is done.
14
- # Otherwise no other tests will be able to work with multiple groups
15
- Offroad.send(:class_variable_set, :@@group_single_models, {})
16
- self.class.send(:remove_const, "GroupSingleRecord")
17
- super
18
- end
19
-
20
- empty_online_test "can create, alter, and destroy group single records if there are no offline groups" do
21
- assert_nothing_raised do
22
- rec = GroupSingleRecord.create(:description => "Foo")
23
- rec.description = "Bar"
24
- rec.save!
25
- rec.destroy
26
- end
27
- end
28
-
29
- empty_online_test "cannot create, alter, or destroy group single records if there are any offline groups" do
30
- rec = GroupSingleRecord.create(:description => "Foo")
31
- group = Group.create(:name => "Test Group")
32
- group.group_offline = true
33
-
34
- assert_raise ActiveRecord::ReadOnlyRecord do
35
- GroupSingleRecord.create(:description => "Bar")
36
- end
37
-
38
- assert_raise ActiveRecord::ReadOnlyRecord do
39
- rec.description = "Bar"
40
- rec.save!
41
- end
42
-
43
- assert_raise ActiveRecord::ReadOnlyRecord do
44
- rec.destroy
45
- end
46
- end
47
-
48
- empty_online_test "group single models are offroad_group_data" do
49
- GroupSingleRecord.offroad_group_data?
50
- end
51
-
52
- empty_online_test "group single records belong to nil if no groups are offline" do
53
- rec = GroupSingleRecord.create(:description => "Foo")
54
- group_a = Group.create(:name => "A")
55
- group_b = Group.create(:name => "B")
56
- assert_equal nil, rec.owning_group
57
- assert_equal 0, GroupSingleRecord.owned_by_offroad_group(group_a).count
58
- assert_equal 0, GroupSingleRecord.owned_by_offroad_group(group_b).count
59
- end
60
-
61
- empty_online_test "group single records belong to first offline group" do
62
- rec = GroupSingleRecord.create(:description => "Foo")
63
- group_a = Group.create(:name => "A")
64
- group_b = Group.create(:name => "B")
65
-
66
- group_a.group_offline = true
67
- assert_equal group_a, rec.owning_group
68
- assert_equal 1, GroupSingleRecord.owned_by_offroad_group(group_a).count
69
- assert_equal 0, GroupSingleRecord.owned_by_offroad_group(group_b).count
70
-
71
- group_a.group_offline = false
72
- group_b.group_offline = true
73
- assert_equal group_b, rec.owning_group
74
- assert_equal 0, GroupSingleRecord.owned_by_offroad_group(group_a).count
75
- assert_equal 1, GroupSingleRecord.owned_by_offroad_group(group_b).count
76
- end
77
-
78
- empty_online_test "cannot set more than one group offline if any group single models exist" do
79
- group_a = Group.create(:name => "A")
80
- group_b = Group.create(:name => "B")
81
-
82
- group_a.group_offline = true
83
- assert_raise Offroad::DataError do
84
- group_b.group_offline = true
85
- end
86
- group_a.group_offline = false
87
- group_b.group_offline = true
88
- assert_raise Offroad::DataError do
89
- group_a.group_offline = true
90
- end
91
- end
92
-
93
- cross_test "can insert and update and delete group single data using mirror files" do
94
- mirror_data = nil
95
-
96
- in_online_app(false, true) do
97
- GroupSingleRecord.create(:description => "Foo")
98
- GroupSingleRecord.create(:description => "Bar")
99
- group_a = Group.create(:name => "A")
100
- group_a.group_offline = true
101
- mirror_data = Offroad::MirrorData.new(group_a, :initial_mode => true).write_downwards_data
102
- end
103
-
104
- in_offline_app(false, true) do
105
- assert_equal 0, GroupSingleRecord.count
106
- Offroad::MirrorData.new(nil, :initial_mode => true).load_downwards_data(mirror_data)
107
- assert_equal 2, GroupSingleRecord.count
108
-
109
- foo_rec = GroupSingleRecord.find_by_description("Foo")
110
- assert foo_rec
111
- foo_rec.description = "Fu"
112
- foo_rec.save!
113
-
114
- bar_rec = GroupSingleRecord.find_by_description("Bar")
115
- assert bar_rec
116
- bar_rec.destroy
117
-
118
- GroupSingleRecord.create(:description => "One more for the road")
119
- GroupSingleRecord.create(:description => "Yet another for the road")
120
-
121
- mirror_data = Offroad::MirrorData.new(Group.first).write_upwards_data
122
- end
123
-
124
- in_online_app do
125
- assert_equal 2, GroupSingleRecord.count
126
- Offroad::MirrorData.new(Group.first).load_upwards_data(mirror_data)
127
- assert_equal 3, GroupSingleRecord.count # One record destroyed, two created
128
-
129
- assert_equal nil, GroupSingleRecord.find_by_description("Foo")
130
- assert GroupSingleRecord.find_by_description("Fu")
131
- assert_equal nil, GroupSingleRecord.find_by_description("Bar")
132
- assert GroupSingleRecord.find_by_description("One more for the road")
133
- assert GroupSingleRecord.find_by_description("Yet another for the road")
134
- end
135
- end
136
- end
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 models in group_single mode
4
+
5
+ class GroupSingleTest < Test::Unit::TestCase
6
+ def setup
7
+ super
8
+ self.class.const_set("GroupSingleRecord", Class.new(ActiveRecord::Base))
9
+ GroupSingleRecord.send(:acts_as_offroadable, :group_single)
10
+ end
11
+
12
+ def teardown
13
+ # Manually remove the group_single model after the test is done.
14
+ # Otherwise no other tests will be able to work with multiple groups
15
+ Offroad.send(:class_variable_set, :@@group_single_models, {})
16
+ self.class.send(:remove_const, "GroupSingleRecord")
17
+ super
18
+ end
19
+
20
+ empty_online_test "can create, alter, and destroy group single records if there are no offline groups" do
21
+ assert_nothing_raised do
22
+ rec = GroupSingleRecord.create(:description => "Foo")
23
+ rec.description = "Bar"
24
+ rec.save!
25
+ rec.destroy
26
+ end
27
+ end
28
+
29
+ empty_online_test "cannot create, alter, or destroy group single records if there are any offline groups" do
30
+ rec = GroupSingleRecord.create(:description => "Foo")
31
+ group = Group.create(:name => "Test Group")
32
+ group.group_offline = true
33
+
34
+ assert_raise ActiveRecord::ReadOnlyRecord do
35
+ GroupSingleRecord.create(:description => "Bar")
36
+ end
37
+
38
+ assert_raise ActiveRecord::ReadOnlyRecord do
39
+ rec.description = "Bar"
40
+ rec.save!
41
+ end
42
+
43
+ assert_raise ActiveRecord::ReadOnlyRecord do
44
+ rec.destroy
45
+ end
46
+ end
47
+
48
+ empty_online_test "group single models are offroad_group_data" do
49
+ GroupSingleRecord.offroad_group_data?
50
+ end
51
+
52
+ empty_online_test "group single records belong to nil if no groups are offline" do
53
+ rec = GroupSingleRecord.create(:description => "Foo")
54
+ group_a = Group.create(:name => "A")
55
+ group_b = Group.create(:name => "B")
56
+ assert_equal nil, rec.owning_group
57
+ assert_equal 0, GroupSingleRecord.owned_by_offroad_group(group_a).count
58
+ assert_equal 0, GroupSingleRecord.owned_by_offroad_group(group_b).count
59
+ end
60
+
61
+ empty_online_test "group single records belong to first offline group" do
62
+ rec = GroupSingleRecord.create(:description => "Foo")
63
+ group_a = Group.create(:name => "A")
64
+ group_b = Group.create(:name => "B")
65
+
66
+ group_a.group_offline = true
67
+ assert_equal group_a, rec.owning_group
68
+ assert_equal 1, GroupSingleRecord.owned_by_offroad_group(group_a).count
69
+ assert_equal 0, GroupSingleRecord.owned_by_offroad_group(group_b).count
70
+
71
+ group_a.group_offline = false
72
+ group_b.group_offline = true
73
+ assert_equal group_b, rec.owning_group
74
+ assert_equal 0, GroupSingleRecord.owned_by_offroad_group(group_a).count
75
+ assert_equal 1, GroupSingleRecord.owned_by_offroad_group(group_b).count
76
+ end
77
+
78
+ empty_online_test "cannot set more than one group offline if any group single models exist" do
79
+ group_a = Group.create(:name => "A")
80
+ group_b = Group.create(:name => "B")
81
+
82
+ group_a.group_offline = true
83
+ assert_raise Offroad::DataError do
84
+ group_b.group_offline = true
85
+ end
86
+ group_a.group_offline = false
87
+ group_b.group_offline = true
88
+ assert_raise Offroad::DataError do
89
+ group_a.group_offline = true
90
+ end
91
+ end
92
+
93
+ cross_test "can insert and update and delete group single data using mirror files" do
94
+ mirror_data = nil
95
+
96
+ in_online_app(false, true) do
97
+ GroupSingleRecord.create(:description => "Foo")
98
+ GroupSingleRecord.create(:description => "Bar")
99
+ group_a = Group.create(:name => "A")
100
+ group_a.group_offline = true
101
+ mirror_data = Offroad::MirrorData.new(group_a, :initial_mode => true).write_downwards_data
102
+ end
103
+
104
+ in_offline_app(false, true) do
105
+ assert_equal 0, GroupSingleRecord.count
106
+ Offroad::MirrorData.new(nil, :initial_mode => true).load_downwards_data(mirror_data)
107
+ assert_equal 2, GroupSingleRecord.count
108
+
109
+ foo_rec = GroupSingleRecord.find_by_description("Foo")
110
+ assert foo_rec
111
+ foo_rec.description = "Fu"
112
+ foo_rec.save!
113
+
114
+ bar_rec = GroupSingleRecord.find_by_description("Bar")
115
+ assert bar_rec
116
+ bar_rec.destroy
117
+
118
+ GroupSingleRecord.create(:description => "One more for the road")
119
+ GroupSingleRecord.create(:description => "Yet another for the road")
120
+
121
+ mirror_data = Offroad::MirrorData.new(Group.first).write_upwards_data
122
+ end
123
+
124
+ in_online_app do
125
+ assert_equal 2, GroupSingleRecord.count
126
+ Offroad::MirrorData.new(Group.first).load_upwards_data(mirror_data)
127
+ assert_equal 3, GroupSingleRecord.count # One record destroyed, two created
128
+
129
+ assert_equal nil, GroupSingleRecord.find_by_description("Foo")
130
+ assert GroupSingleRecord.find_by_description("Fu")
131
+ assert_equal nil, GroupSingleRecord.find_by_description("Bar")
132
+ assert GroupSingleRecord.find_by_description("One more for the road")
133
+ assert GroupSingleRecord.find_by_description("Yet another for the road")
134
+ end
135
+ end
136
+ end
@@ -1,57 +1,57 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
-
3
- # This is a unit test on the ability of model_extensions to override regular Hobo model permissions
4
-
5
- class HoboPermissionsTest < Test::Unit::TestCase
6
- if HOBO_TEST_MODE
7
- def setup
8
- @guest = Guest.new
9
- super
10
- end
11
-
12
- class HoboPermissionsTestModel < ActiveRecord::Base
13
- hobo_model
14
- set_table_name "broken_records"
15
-
16
- def create_permitted?
17
- true
18
- end
19
-
20
- def update_permitted?
21
- true
22
- end
23
-
24
- def destroy_permitted?
25
- true
26
- end
27
-
28
- acts_as_offroadable :global
29
- end
30
- end
31
-
32
- offline_test "can override hobo permissions" do
33
- if HOBO_TEST_MODE
34
- rec = HoboPermissionsTestModel.new
35
- force_save_and_reload(rec)
36
-
37
- # We are in offline mode and rec is offroad as global
38
- # Therefore we should not be able to edit it
39
- assert !rec.creatable_by?(@guest)
40
- assert !rec.updatable_by?(@guest)
41
- assert !rec.destroyable_by?(@guest)
42
- end
43
- end
44
-
45
- online_test "overriding hobo permissions does not block off user specified permissions" do
46
- if HOBO_TEST_MODE
47
- rec = HoboPermissionsTestModel.new
48
- force_save_and_reload(rec)
49
-
50
- # We are in offline mode and rec is offroad as global
51
- # Therefore we should be able to edit it
52
- assert rec.creatable_by?(@guest)
53
- assert rec.updatable_by?(@guest)
54
- assert rec.destroyable_by?(@guest)
55
- end
56
- end
57
- end
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ # This is a unit test on the ability of model_extensions to override regular Hobo model permissions
4
+
5
+ class HoboPermissionsTest < Test::Unit::TestCase
6
+ if HOBO_TEST_MODE
7
+ def setup
8
+ @guest = Guest.new
9
+ super
10
+ end
11
+
12
+ class HoboPermissionsTestModel < ActiveRecord::Base
13
+ hobo_model
14
+ set_table_name "broken_records"
15
+
16
+ def create_permitted?
17
+ true
18
+ end
19
+
20
+ def update_permitted?
21
+ true
22
+ end
23
+
24
+ def destroy_permitted?
25
+ true
26
+ end
27
+
28
+ acts_as_offroadable :global
29
+ end
30
+ end
31
+
32
+ offline_test "can override hobo permissions" do
33
+ if HOBO_TEST_MODE
34
+ rec = HoboPermissionsTestModel.new
35
+ force_save_and_reload(rec)
36
+
37
+ # We are in offline mode and rec is offroad as global
38
+ # Therefore we should not be able to edit it
39
+ assert !rec.creatable_by?(@guest)
40
+ assert !rec.updatable_by?(@guest)
41
+ assert !rec.destroyable_by?(@guest)
42
+ end
43
+ end
44
+
45
+ online_test "overriding hobo permissions does not block off user specified permissions" do
46
+ if HOBO_TEST_MODE
47
+ rec = HoboPermissionsTestModel.new
48
+ force_save_and_reload(rec)
49
+
50
+ # We are in offline mode and rec is offroad as global
51
+ # Therefore we should be able to edit it
52
+ assert rec.creatable_by?(@guest)
53
+ assert rec.updatable_by?(@guest)
54
+ assert rec.destroyable_by?(@guest)
55
+ end
56
+ end
57
+ end
@@ -1,1283 +1,1283 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
-
3
- class MirrorDataTest < Test::Unit::TestCase
4
- online_test "cannot create MirrorData instance for online group" do
5
- assert_raise Offroad::DataError do
6
- Offroad::MirrorData.new(@online_group)
7
- end
8
- end
9
-
10
- def all_records_from_section_named(cs, name)
11
- recs = []
12
- cs.each_cargo_section(name) do |batch|
13
- recs += batch
14
- end
15
- return recs
16
- end
17
-
18
- def assert_single_cargo_section_named(cs, name)
19
- count = 0
20
- cs.each_cargo_section(name) do |data|
21
- count += 1
22
- end
23
- assert_equal 1, count
24
- end
25
-
26
- def assert_no_cargo_sections_named(cs, name)
27
- assert_nothing_raised do
28
- cs.each_cargo_section(name) do |data|
29
- raise "There shouldn't be any cargo sections with that name"
30
- end
31
- end
32
- end
33
-
34
- def assert_common_mirror_elements_appear_valid(cs, mode)
35
- assert_single_cargo_section_named cs, "mirror_info"
36
-
37
- mirror_info = cs.first_cargo_element("mirror_info")
38
- assert_instance_of Offroad::MirrorInfo, mirror_info
39
- migration_query = "SELECT version FROM schema_migrations ORDER BY version"
40
- migrations = Group.connection.select_all(migration_query).map{ |r| r["version"] }
41
- assert_equal migrations, mirror_info.schema_migrations.split(",").sort
42
- assert_equal mirror_info.app, Offroad::app_name
43
- assert Time.now - mirror_info.created_at < 30
44
- assert mirror_info.app_mode.downcase.include?(mode.downcase)
45
-
46
- assert_single_cargo_section_named cs, "group_state"
47
- group_state = cs.first_cargo_element("group_state")
48
- assert_instance_of Offroad::GroupState, group_state
49
- assert_equal @offline_group.id, group_state.app_group_id
50
- end
51
-
52
- def strip_msecs_in_values(hash)
53
- new_hash = {}
54
- hash.each do |k,v|
55
- if v.is_a?(DateTime) || v.is_a?(Time)
56
- new_hash[k] = v.to_i
57
- else
58
- new_hash[k] = v
59
- end
60
- end
61
- new_hash
62
- end
63
-
64
- def assert_single_model_cargo_entry_matches(cs, record)
65
- record.reload
66
- data_name = Offroad::MirrorData.send(:data_cargo_name_for_model, record.class)
67
- assert_single_cargo_section_named cs, data_name
68
- assert_equal strip_msecs_in_values(record.attributes), strip_msecs_in_values(cs.first_cargo_element(data_name).attributes)
69
- end
70
-
71
- def assert_record_not_present(cs, record)
72
- record.reload
73
- data_name = Offroad::MirrorData.send(:data_cargo_name_for_model, record.class)
74
- assert_nothing_raised do
75
- cs.each_cargo_section(data_name) do |batch|
76
- batch.each do |cargo_record|
77
- raise "Undesired record found" if record.attributes == cargo_record.attributes
78
- end
79
- end
80
- end
81
- end
82
-
83
- cross_test "can pass data to MirrorData read methods as CargoStreamer, String, or IO" do
84
- mirror_data = nil
85
- in_online_app do
86
- GlobalRecord.create(:title => "Foo Bar")
87
- mirror_data = Offroad::MirrorData.new(@offline_group).write_downwards_data
88
- end
89
-
90
- sources = [
91
- Offroad::CargoStreamer.new(mirror_data, "r"),
92
- StringIO.new(mirror_data, "r"),
93
- mirror_data
94
- ]
95
- sources.each do |source|
96
- in_offline_app(true) do
97
- assert_equal 0, GlobalRecord.count
98
- Offroad::MirrorData.new(@offline_group).load_downwards_data(source)
99
- assert GlobalRecord.find_by_title("Foo Bar")
100
- end
101
- end
102
- end
103
-
104
- offline_test "can have MirrorData write methods send to CargoStreamer, IO, or return value" do
105
- cargo_streamer_sio = StringIO.new
106
- cargo_streamer = Offroad::CargoStreamer.new(cargo_streamer_sio, "w")
107
- direct_sio = StringIO.new
108
-
109
- writer = Offroad::MirrorData.new(@offline_group)
110
- writer.write_upwards_data(cargo_streamer)
111
- writer.write_upwards_data(direct_sio)
112
- str = writer.write_upwards_data
113
-
114
- cargo_streamer_sio.rewind
115
- direct_sio.rewind
116
- result_a = Offroad::CargoStreamer.new(cargo_streamer_sio, "r").cargo_section_names
117
- result_b = Offroad::CargoStreamer.new(direct_sio, "r").cargo_section_names
118
- result_c = Offroad::CargoStreamer.new(StringIO.new(str), "r").cargo_section_names
119
-
120
- assert result_a.size > 0
121
- assert result_a == result_b
122
- assert result_b == result_c
123
- end
124
-
125
- online_test "can generate a valid initial down mirror file for the offline group" do
126
- global_record = GlobalRecord.create(:title => "Foo Bar")
127
- global_record.reload # To clear the high time precision that is lost in the database
128
-
129
- str = Offroad::MirrorData.new(@offline_group, :initial_mode => true).write_downwards_data
130
- cs = Offroad::CargoStreamer.new(str, "r")
131
- assert_common_mirror_elements_appear_valid cs, "online"
132
- assert_single_model_cargo_entry_matches cs, global_record
133
- assert_single_model_cargo_entry_matches cs, @offline_group
134
- assert_single_model_cargo_entry_matches cs, @offline_group_data
135
- end
136
-
137
- online_test "can convert online group to an offline group and generate valid initial down mirror file" do
138
- global_record = GlobalRecord.create(:title => "Foo Bar")
139
- global_record.reload # To clear the high time precision that is lost in the database
140
-
141
- @online_group.group_offline = true
142
- str = Offroad::MirrorData.new(@online_group, :initial_mode => true).write_downwards_data
143
- cs = Offroad::CargoStreamer.new(str, "r")
144
- assert_single_model_cargo_entry_matches cs, global_record
145
- assert_single_model_cargo_entry_matches cs, @online_group
146
- assert_single_model_cargo_entry_matches cs, @online_group_data
147
- end
148
-
149
- online_test "can generate a valid down mirror file for the offline group" do
150
- global_record = GlobalRecord.create(:title => "Foo Bar")
151
- global_record.reload # To clear the high time precision that is lost in the database
152
-
153
- str = Offroad::MirrorData.new(@offline_group).write_downwards_data
154
- cs = Offroad::CargoStreamer.new(str, "r")
155
- assert_common_mirror_elements_appear_valid cs, "online"
156
- assert_single_model_cargo_entry_matches cs, global_record
157
- assert_record_not_present cs, @offline_group
158
- assert_record_not_present cs, @offline_group_data
159
- end
160
-
161
- online_test "initial down mirror files do not include irrelevant records" do
162
- another_offline_group = Group.create!(:name => "Another Group")
163
- another_group_data = GroupOwnedRecord.create!(:description => "Another Data", :group => another_offline_group)
164
- another_offline_group.group_offline = true
165
- [another_offline_group, another_group_data].each { |r| r.reload }
166
-
167
- str = Offroad::MirrorData.new(@offline_group, :initial_mode => true).write_downwards_data
168
- cs = Offroad::CargoStreamer.new(str, "r")
169
- assert_record_not_present cs, another_offline_group
170
- assert_record_not_present cs, another_group_data
171
- assert_single_model_cargo_entry_matches cs, @offline_group
172
- assert_single_model_cargo_entry_matches cs, @offline_group_data
173
- end
174
-
175
- online_test "down mirror files do not include irrelevant records" do
176
- global_record = GlobalRecord.create(:title => "Foo Bar")
177
- global_record.reload # To clear the high time precision that is lost in the database
178
- another_offline_group = Group.create!(:name => "Another Group")
179
- another_group_data = GroupOwnedRecord.create!(:description => "Another Data", :group => another_offline_group)
180
- another_offline_group.group_offline = true
181
- [another_offline_group, another_group_data].each { |r| r.reload }
182
-
183
- str = Offroad::MirrorData.new(@offline_group).write_downwards_data
184
- cs = Offroad::CargoStreamer.new(str, "r")
185
- assert_record_not_present cs, another_offline_group
186
- assert_record_not_present cs, another_group_data
187
- assert_record_not_present cs, @offline_group
188
- assert_record_not_present cs, @offline_group_data
189
- assert_single_model_cargo_entry_matches cs, global_record
190
- end
191
-
192
- offline_test "can generate a valid up mirror file for the offline group" do
193
- @offline_group.name = "Changed"
194
- @offline_group.save!
195
- @offline_group.reload
196
- @offline_group_data.some_integer = 5551212
197
- @offline_group_data.save!
198
- @offline_group_data.reload
199
- str = Offroad::MirrorData.new(@offline_group).write_upwards_data
200
- cs = Offroad::CargoStreamer.new(str, "r")
201
- assert_common_mirror_elements_appear_valid cs, "offline"
202
- assert_single_model_cargo_entry_matches cs, @offline_group
203
- assert_single_model_cargo_entry_matches cs, @offline_group_data
204
- end
205
-
206
- offline_test "up mirror files do not include irrelevant records" do
207
- fake_global_data = GlobalRecord.new(:title => "Fake Stuff")
208
- force_save_and_reload(fake_global_data)
209
-
210
- str = Offroad::MirrorData.new(@offline_group).write_upwards_data
211
- cs = Offroad::CargoStreamer.new(str, "r")
212
- assert_record_not_present cs, fake_global_data
213
- end
214
-
215
- offline_test "cannot upload an invalid down mirror file" do
216
- assert_raise Offroad::DataError do
217
- Offroad::MirrorData.new(@offline_group).load_downwards_data("FOO BAR BLAH")
218
- end
219
- end
220
-
221
- online_test "cannot upload an invalid up mirror file" do
222
- assert_raise Offroad::DataError do
223
- Offroad::MirrorData.new(@offline_group).load_upwards_data("FOO BAR BLAH")
224
- end
225
- end
226
-
227
- offline_test "cannot use load_upwards_data in offline mode" do
228
- assert_raise Offroad::PluginError do
229
- Offroad::MirrorData.new(@offline_group).load_upwards_data("FOO BAR BLAH")
230
- end
231
- end
232
-
233
- online_test "cannot use load_downwards_data in online mode" do
234
- assert_raise Offroad::PluginError do
235
- Offroad::MirrorData.new(@offline_group).load_downwards_data("FOO BAR BLAH")
236
- end
237
- end
238
-
239
- def assert_record_states_all_valid
240
- Offroad::ReceivedRecordState.all.each do |rrs|
241
- if not rrs.valid?
242
- flunk "Invalid RRS (#{rrs.attributes.map{|k,v| "#{k}:#{v}"}.join(",")}) : #{rrs.errors.full_messages.join(",")}"
243
- end
244
- end
245
- Offroad::SendableRecordState.all.each do |srs|
246
- if not srs.valid?
247
- flunk "Invalid SRS (#{srs.attributes.map{|k,v| "#{k}:#{v}"}.join(",")}) : #{srs.errors.full_messages.join(",")}"
248
- end
249
- end
250
- end
251
-
252
- online_test "initial online record states all valid" do
253
- assert_record_states_all_valid
254
- end
255
-
256
- offline_test "initial offline record states all valid" do
257
- assert_record_states_all_valid
258
- end
259
-
260
- cross_test "can insert and update group data using an up mirror file" do
261
- mirror_data = nil
262
-
263
- in_offline_app do
264
- @offline_group.name = "TEST 123"
265
- @offline_group.save!
266
- @offline_group_data.description = "TEST XYZ"
267
- @offline_group_data.save!
268
- GroupOwnedRecord.create!(:description => "TEST ABC", :group => @offline_group)
269
- mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
270
- end
271
-
272
- in_online_app do
273
- prior_rrs_count = Offroad::ReceivedRecordState.count
274
- Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
275
- assert_record_states_all_valid
276
- assert_equal prior_rrs_count+1, Offroad::ReceivedRecordState.count
277
- assert_equal @offline_group.id, Group.find_by_name("TEST 123").id
278
- assert GroupOwnedRecord.find_by_description("TEST ABC")
279
- assert_equal @offline_group_data.id, GroupOwnedRecord.find_by_description("TEST XYZ").id
280
- end
281
- end
282
-
283
- cross_test "records created by up mirror file did not have their callbacks called" do
284
- mirror_data = nil
285
- in_offline_app do
286
- GroupOwnedRecord.create(:description => "TEST ABC", :group => @offline_group)
287
- mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
288
- end
289
-
290
- in_online_app do
291
- GroupOwnedRecord.reset_callback_called
292
- Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
293
- assert !GroupOwnedRecord.callback_called
294
- end
295
- end
296
-
297
- cross_test "records updated by up mirror file did not have their callbacks called" do
298
- mirror_data = nil
299
- in_offline_app do
300
- @offline_group_data.description = "TEST XYZ"
301
- @offline_group_data.save!
302
- mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
303
- end
304
-
305
- in_online_app do
306
- GroupOwnedRecord.reset_callback_called
307
- Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
308
- assert !GroupOwnedRecord.callback_called
309
- end
310
- end
311
-
312
- cross_test "records destroyed by up mirror file did not have their callbacks called" do
313
- mirror_data = nil
314
- in_offline_app do
315
- @offline_group_data.destroy
316
- mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
317
- end
318
-
319
- in_online_app do
320
- GroupOwnedRecord.reset_callback_called
321
- Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
322
- assert !GroupOwnedRecord.callback_called
323
- end
324
- end
325
-
326
- cross_test "can delete group data using an up mirror file" do
327
- mirror_data = nil
328
-
329
- in_offline_app do
330
- @offline_group_data.destroy
331
- mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
332
- end
333
-
334
- in_online_app do
335
- prior_rrs_count = Offroad::ReceivedRecordState.count
336
- assert_equal 1, GroupOwnedRecord.count(:conditions => { :group_id => @offline_group.id })
337
- Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
338
- assert_record_states_all_valid
339
- assert_equal prior_rrs_count-1, Offroad::ReceivedRecordState.count
340
- assert_equal 0, GroupOwnedRecord.count(:conditions => { :group_id => @offline_group.id })
341
- end
342
- end
343
-
344
- cross_test "can insert and update and delete global records using a down mirror file" do
345
- mirror_data = nil
346
-
347
- in_online_app do
348
- GlobalRecord.create(:title => "ABC")
349
- GlobalRecord.create(:title => "123")
350
- mirror_data = Offroad::MirrorData.new(@offline_group).write_downwards_data
351
- end
352
-
353
- offline_number_rec_id = nil
354
- in_offline_app do
355
- rrs_scope = Offroad::ReceivedRecordState.for_model(GlobalRecord)
356
- assert_equal 0, rrs_scope.count
357
- assert_equal 0, GlobalRecord.count
358
- Offroad::MirrorData.new(@offline_group).load_downwards_data(mirror_data)
359
- assert_record_states_all_valid
360
- assert_equal 2, rrs_scope.count
361
- assert_equal 2, GlobalRecord.count
362
- assert_not_nil GlobalRecord.find_by_title("ABC")
363
- assert_not_nil GlobalRecord.find_by_title("123")
364
- offline_number_rec_id = GlobalRecord.find_by_title("123")
365
- end
366
-
367
- in_online_app do
368
- number_rec = GlobalRecord.find_by_title("123")
369
- number_rec.title = "789"
370
- number_rec.save!
371
-
372
- letter_rec = GlobalRecord.find_by_title("ABC")
373
- letter_rec.destroy
374
-
375
- mirror_data = Offroad::MirrorData.new(@offline_group).write_downwards_data
376
- end
377
-
378
- in_offline_app do
379
- rrs_scope = Offroad::ReceivedRecordState.for_model(GlobalRecord)
380
- Offroad::MirrorData.new(@offline_group).load_downwards_data(mirror_data)
381
- assert_record_states_all_valid
382
- assert_equal 1, rrs_scope.count
383
- assert_equal 1, GlobalRecord.count
384
- assert_nil GlobalRecord.find_by_title("ABC")
385
- assert_nil GlobalRecord.find_by_title("123")
386
- assert_not_nil GlobalRecord.find_by_title("789")
387
- assert_equal offline_number_rec_id, GlobalRecord.find_by_title("789")
388
- end
389
- end
390
-
391
- cross_test "can insert group records using an initial down mirror file" do
392
- mirror_data = nil
393
- in_online_app do
394
- mirror_data = Offroad::MirrorData.new(@offline_group, :initial_mode => true).write_downwards_data
395
- end
396
-
397
- in_offline_app(false, true) do
398
- assert_equal 0, Group.count
399
- assert_equal 0, GroupOwnedRecord.count
400
- assert_equal 0, Offroad::SendableRecordState.for_model(Group).count
401
- assert_equal 0, Offroad::SendableRecordState.for_model(GroupOwnedRecord).count
402
- Offroad::MirrorData.new(nil, :initial_mode => true).load_downwards_data(mirror_data)
403
- assert_record_states_all_valid
404
- assert_equal 1, Group.count
405
- assert_equal 1, GroupOwnedRecord.count
406
- assert_equal 1, Offroad::SendableRecordState.for_model(Group).count
407
- assert_equal 1, Offroad::SendableRecordState.for_model(GroupOwnedRecord).count
408
- end
409
- end
410
-
411
- cross_test "records created by initial down mirror file did not have their callbacks called" do
412
- mirror_data = nil
413
- in_online_app do
414
- mirror_data = Offroad::MirrorData.new(@offline_group, :initial_mode => true).write_downwards_data
415
- end
416
-
417
- in_offline_app(false, true) do
418
- GroupOwnedRecord.reset_callback_called
419
- Offroad::MirrorData.new(nil, :initial_mode => true).load_downwards_data(mirror_data)
420
- assert !GroupOwnedRecord.callback_called
421
- end
422
- end
423
-
424
- cross_test "can insert global records using an initial down mirror file" do
425
- mirror_data = nil
426
- in_online_app do
427
- GlobalRecord.create(:title => "Something")
428
- mirror_data = Offroad::MirrorData.new(@offline_group, :initial_mode => true).write_downwards_data
429
- end
430
-
431
- in_offline_app(false, true) do
432
- assert_equal 0, GlobalRecord.count
433
- assert_equal 0, Offroad::SendableRecordState.for_model(GlobalRecord).count
434
- assert_equal 0, Offroad::ReceivedRecordState.for_model(GlobalRecord).count
435
- Offroad::MirrorData.new(nil, :initial_mode => true).load_downwards_data(mirror_data)
436
- assert_record_states_all_valid
437
- assert_equal 1, GlobalRecord.count
438
- assert_not_nil GlobalRecord.find_by_title("Something")
439
- assert_equal 0, Offroad::SendableRecordState.for_model(GlobalRecord).count
440
- assert_equal 1, Offroad::ReceivedRecordState.for_model(GlobalRecord).count
441
- end
442
- end
443
-
444
- cross_test "cannot load regular down mirror file in empty offline app" do
445
- mirror_data = nil
446
- in_online_app { mirror_data = Offroad::MirrorData.new(@offline_group).write_downwards_data }
447
-
448
- in_offline_app(false, true) do
449
- assert_raise Offroad::PluginError do
450
- Offroad::MirrorData.new(nil).load_downwards_data(mirror_data)
451
- end
452
- end
453
- end
454
-
455
- cross_test "importing an initial down mirror file deletes all currently existing records" do
456
- mirror_data = nil
457
- in_online_app do
458
- mirror_data = Offroad::MirrorData.new(@offline_group, :initial_mode => true).write_downwards_data
459
- end
460
-
461
- in_offline_app do
462
- @offline_group.update_attribute(:name, "Old")
463
- GroupOwnedRecord.create!(:description => "Old", :group => @offline_group)
464
- UnmirroredRecord.create!(:content => "Old Old Old")
465
- global_data = GlobalRecord.new(:title => "Old")
466
- force_save_and_reload(global_data)
467
-
468
- Offroad::MirrorData.new(nil, :initial_mode => true).load_downwards_data(mirror_data)
469
-
470
- assert_equal nil, Group.find_by_name("Old")
471
- assert_equal nil, GroupOwnedRecord.find_by_description("Old")
472
- assert_equal 1, Group.count
473
- assert_equal 1, GroupOwnedRecord.count
474
- assert_equal 0, GlobalRecord.count
475
- assert_equal 0, UnmirroredRecord.count
476
- end
477
- end
478
-
479
- cross_test "importing an initial down mirror file resets autoincrement counters" do
480
- mirror_data = nil
481
- in_online_app do
482
- mirror_data = Offroad::MirrorData.new(@offline_group, :initial_mode => true).write_downwards_data
483
- end
484
-
485
- in_offline_app do
486
- global_rec_a = GlobalRecord.new(:title => "A")
487
- global_rec_b = GlobalRecord.new(:title => "B")
488
- global_rec_c = GlobalRecord.new(:title => "C")
489
- force_save_and_reload(global_rec_a, global_rec_b, global_rec_c)
490
-
491
- Offroad::MirrorData.new(nil, :initial_mode => true).load_downwards_data(mirror_data)
492
-
493
- global_rec = GlobalRecord.new(:title => "Test")
494
- force_save_and_reload(global_rec)
495
- assert_equal 1, global_rec.id
496
- end
497
- end
498
-
499
- cross_test "cannot upload an initial down mirror file unless passed :initial_mode => true to MirrorData.new" do
500
- mirror_data = nil
501
- in_online_app do
502
- mirror_data = Offroad::MirrorData.new(@offline_group, :initial_mode => true).write_downwards_data
503
- end
504
-
505
- in_offline_app do
506
- assert_raise Offroad::DataError do
507
- Offroad::MirrorData.new(@offline_group).load_downwards_data(mirror_data)
508
- end
509
- end
510
- end
511
-
512
- cross_test "cannot upload a non-initial down mirror file after passing :initial_mode => true to MirrorData.new" do
513
- mirror_data = nil
514
- in_online_app { mirror_data = Offroad::MirrorData.new(@offline_group).write_downwards_data }
515
-
516
- in_offline_app do
517
- assert_raise Offroad::DataError do
518
- Offroad::MirrorData.new(@offline_group, :initial_mode => true).load_downwards_data(mirror_data)
519
- end
520
- end
521
- end
522
-
523
- cross_test "cannot upload a non-initial down mirror file to a blank offline instance" do
524
- mirror_data = nil
525
- in_online_app { mirror_data = Offroad::MirrorData.new(@offline_group).write_downwards_data }
526
-
527
- in_offline_app(false, true) do
528
- assert_raise Offroad::DataError do
529
- Offroad::MirrorData.new(@offline_group).load_downwards_data(mirror_data)
530
- end
531
- end
532
- end
533
-
534
- cross_test "cannot pass a down mirror file to load_upwards_data" do
535
- mirror_data = nil
536
-
537
- in_online_app do
538
- mirror_data = Offroad::MirrorData.new(@offline_group).write_downwards_data
539
-
540
- assert_raise Offroad::DataError do
541
- Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
542
- end
543
- end
544
-
545
- in_offline_app do
546
- assert_nothing_raised do
547
- Offroad::MirrorData.new(@offline_group).load_downwards_data(mirror_data)
548
- end
549
- end
550
- end
551
-
552
- cross_test "cannot pass an up mirror file to load_downwards_data" do
553
- mirror_data = nil
554
-
555
- in_offline_app do
556
- mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
557
-
558
- assert_raise Offroad::DataError do
559
- Offroad::MirrorData.new(@offline_group).load_downwards_data(mirror_data)
560
- end
561
- end
562
-
563
- in_online_app do
564
- assert_nothing_raised do
565
- Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
566
- end
567
- end
568
- end
569
-
570
- cross_test "transformed ids are handled properly when loading an up mirror file" do
571
- in_online_app do
572
- another_online_record = GroupOwnedRecord.create(:description => "Yet Another", :group => @online_group)
573
- end
574
-
575
- mirror_data = nil
576
- offline_id_of_new_rec = nil
577
- in_offline_app do
578
- another_offline_rec = GroupOwnedRecord.create(:description => "One More", :group => @offline_group)
579
- offline_id_of_new_rec = another_offline_rec.id
580
- mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
581
- end
582
-
583
- in_online_app do
584
- Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
585
- assert_record_states_all_valid
586
- rec = GroupOwnedRecord.find_by_description("One More")
587
- assert rec
588
- assert_equal offline_id_of_new_rec, Offroad::ReceivedRecordState.for_record(rec).first.remote_record_id
589
- end
590
- end
591
-
592
- cross_test "transformed ids are handled properly when loading an initial down mirror file" do
593
- mirror_data = nil
594
- online_id_of_offline_rec = nil
595
- in_online_app do
596
- online_id_of_offline_rec = @offline_group_data.id
597
- mirror_data = Offroad::MirrorData.new(@offline_group, :initial_mode => true).write_downwards_data
598
- end
599
-
600
- in_offline_app do
601
- Offroad::MirrorData.new(nil, :initial_mode => true).load_downwards_data(mirror_data)
602
- assert_record_states_all_valid
603
- rec = GroupOwnedRecord.find_by_description("Sam")
604
- assert_equal online_id_of_offline_rec, rec.id
605
- rec.description = "Samuel Jackson"
606
- rec.save!
607
- mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
608
- end
609
-
610
- in_online_app do
611
- Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
612
- assert_equal nil, GroupOwnedRecord.find_by_description("Sam")
613
- assert_equal "Samuel Jackson", GroupOwnedRecord.find(online_id_of_offline_rec).description
614
- end
615
- end
616
-
617
- online_test "initial down mirror files do not include deletion entries" do
618
- global_record = GlobalRecord.create(:title => "Something")
619
- global_record.destroy
620
-
621
- str = Offroad::MirrorData.new(@offline_group, :initial_mode => true).write_downwards_data
622
- cs = Offroad::CargoStreamer.new(str, "r")
623
- deletion_cargo_name = Offroad::MirrorData.send(:deletion_cargo_name_for_model, GlobalRecord)
624
- assert_equal false, cs.has_cargo_named?(deletion_cargo_name)
625
- end
626
-
627
- offline_test "can only create mirror files containing invalid records when skip_validation is true" do
628
- group_rec = GroupOwnedRecord.new(:description => "Invalid record", :group => @offline_group, :should_be_even => 3)
629
- group_rec.save_without_validation
630
- assert_raise Offroad::DataError do
631
- Offroad::MirrorData.new(@offline_group).write_upwards_data
632
- end
633
- assert_nothing_raised do
634
- Offroad::MirrorData.new(@offline_group, :skip_validation => true).write_upwards_data
635
- end
636
- end
637
-
638
- cross_test "cannot import up mirror files with invalid records unless skip_validation is enabled" do
639
- mirror_data = nil
640
- in_offline_app do
641
- group_rec = GroupOwnedRecord.new(:description => "Invalid record", :group => @offline_group, :should_be_even => 3)
642
- group_rec.save_without_validation
643
- mirror_data = Offroad::MirrorData.new(@offline_group, :skip_validation => true).write_upwards_data
644
- end
645
-
646
- in_online_app do
647
- assert_raise Offroad::DataError do
648
- Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
649
- end
650
- assert_nothing_raised do
651
- Offroad::MirrorData.new(@offline_group, :skip_validation => true).load_upwards_data(mirror_data)
652
- end
653
- end
654
- end
655
-
656
- cross_test "cannot import down mirror files with invalid records unless skip_validation is enabled" do
657
- mirror_data = nil
658
- in_online_app do
659
- global_rec = GlobalRecord.new(:title => "Invalid record", :should_be_odd => 2)
660
- global_rec.save_without_validation
661
- mirror_data = Offroad::MirrorData.new(@offline_group, :skip_validation => true).write_downwards_data
662
- end
663
-
664
- in_offline_app do
665
- assert_raise Offroad::DataError do
666
- Offroad::MirrorData.new(@offline_group).load_downwards_data(mirror_data)
667
- end
668
- assert_nothing_raised do
669
- Offroad::MirrorData.new(@offline_group, :skip_validation => true).load_downwards_data(mirror_data)
670
- end
671
- end
672
- end
673
-
674
- cross_test "cannot import initial down mirror files with invalid records unless skip_validation is enabled" do
675
- mirror_data = nil
676
- in_online_app do
677
- group_rec = GroupOwnedRecord.new(:description => "Invalid record", :group => @online_group, :should_be_even => 3)
678
- group_rec.save_without_validation
679
- @online_group.group_offline = true
680
- writer = Offroad::MirrorData.new(@online_group, :skip_validation => true, :initial_mode => true)
681
- mirror_data = writer.write_downwards_data
682
- end
683
-
684
- in_offline_app(false, true) do
685
- assert_raise Offroad::DataError do
686
- Offroad::MirrorData.new(nil, :initial_mode => true).load_downwards_data(mirror_data)
687
- end
688
- assert_nothing_raised do
689
- Offroad::MirrorData.new(nil, :initial_mode => true, :skip_validation => true).load_downwards_data(mirror_data)
690
- end
691
- end
692
- end
693
-
694
- cross_test "foreign keys are transformed correctly on up mirror" do
695
- in_online_app do
696
- # Perturb the autoincrement a bit
697
- GroupOwnedRecord.create(:description => "Alice", :group => @online_group)
698
- GroupOwnedRecord.create(:description => "Bob", :group => @online_group)
699
- end
700
-
701
- mirror_data = nil
702
- in_offline_app do
703
- parent = GroupOwnedRecord.create(:description => "Celia", :group => @offline_group)
704
- child_a = GroupOwnedRecord.create(:description => "Daniel", :parent => parent, :group => @offline_group)
705
- child_b = GroupOwnedRecord.create(:description => "Eric", :parent => parent, :group => @offline_group)
706
- grandchild = GroupOwnedRecord.create(:description => "Fran", :parent => child_b, :group => @offline_group)
707
- time_traveler = GroupOwnedRecord.create(:description => "Philip J. Fry", :group => @offline_group)
708
- time_traveler.parent = time_traveler
709
- time_traveler.save!
710
- @offline_group.favorite = grandchild
711
- @offline_group.save!
712
- @offline_group_data.parent = grandchild
713
- @offline_group_data.save!
714
- mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
715
- end
716
-
717
- in_online_app do
718
- Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
719
- assert_record_states_all_valid
720
-
721
- @offline_group.reload
722
- @offline_group_data.reload
723
- parent = GroupOwnedRecord.find_by_description("Celia")
724
- child_a = GroupOwnedRecord.find_by_description("Daniel")
725
- child_b = GroupOwnedRecord.find_by_description("Eric")
726
- grandchild = GroupOwnedRecord.find_by_description("Fran")
727
- time_traveler = GroupOwnedRecord.find_by_description("Philip J. Fry")
728
-
729
- assert_equal parent, child_a.parent
730
- assert_equal parent, child_b.parent
731
- assert_equal child_b, grandchild.parent
732
- assert_equal grandchild, child_b.children.first
733
- assert_equal grandchild, @offline_group.favorite
734
- assert_equal @offline_group_data, grandchild.children.first
735
- assert_equal grandchild, @offline_group_data.parent
736
- assert_equal time_traveler, time_traveler.parent
737
- end
738
- end
739
-
740
- cross_test "foreign keys are transformed correctly on down mirror" do
741
- mirror_data = nil
742
- in_online_app do
743
- alice = GlobalRecord.create(:title => "Alice")
744
- alice.friend = alice
745
- alice.save!
746
- bob = GlobalRecord.create(:title => "Bob", :friend => alice)
747
- claire = GlobalRecord.create(:title => "Claire", :friend => bob)
748
- mirror_data = Offroad::MirrorData.new(@offline_group).write_downwards_data
749
- end
750
-
751
- in_offline_app do
752
- Offroad::MirrorData.new(@offline_group).load_downwards_data(mirror_data)
753
- assert_record_states_all_valid
754
- alice = GlobalRecord.find_by_title("Alice")
755
- bob = GlobalRecord.find_by_title("Bob")
756
- claire = GlobalRecord.find_by_title("Claire")
757
- assert_equal alice, alice.friend
758
- assert_equal alice, bob.friend
759
- assert_equal bob, claire.friend
760
- end
761
- end
762
-
763
- cross_test "loading up mirror file loads group state information" do
764
- in_online_app do
765
- assert_equal "Unknown", @offline_group.group_state.operating_system
766
- end
767
-
768
- mirror_data = nil
769
- offline_os = ""
770
- in_offline_app do
771
- mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
772
- offline_os = @offline_group.group_state.operating_system
773
- end
774
-
775
- in_online_app do
776
- Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
777
- assert_equal offline_os, @offline_group.group_state.operating_system
778
- end
779
- end
780
-
781
- offline_test "creating up mirror file increments current_mirror_version" do
782
- prior_version = Offroad::SystemState::current_mirror_version
783
- Offroad::MirrorData.new(@offline_group).write_upwards_data
784
- assert_equal prior_version+1, Offroad::SystemState::current_mirror_version
785
- end
786
-
787
- online_test "creating down mirror file increments current_mirror_version" do
788
- prior_version = Offroad::SystemState::current_mirror_version
789
- Offroad::MirrorData.new(@offline_group).write_downwards_data
790
- assert_equal prior_version+1, Offroad::SystemState::current_mirror_version
791
- end
792
-
793
- online_test "creating initial down mirror file increments current_mirror_version" do
794
- prior_version = Offroad::SystemState::current_mirror_version
795
- Offroad::MirrorData.new(@offline_group, :initial_mode => true).write_downwards_data
796
- assert_equal prior_version+1, Offroad::SystemState::current_mirror_version
797
- end
798
-
799
- cross_test "receiving an up mirror file increments confirmed_group_data_version to the indicated value if larger" do
800
- mirror_data = nil
801
- in_offline_app do
802
- @offline_group_data.description = "New Name"
803
- @offline_group_data.save!
804
-
805
- Offroad::SystemState::instance_record.update_attribute(:current_mirror_version, 42)
806
-
807
- mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
808
- end
809
-
810
- in_online_app do
811
- assert_equal 1, @offline_group.group_state.confirmed_group_data_version
812
- Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
813
- assert_equal 42, @offline_group.group_state.confirmed_group_data_version
814
- end
815
- end
816
-
817
- cross_test "received up mirror files are rejected if their version is equal to or lower than current version" do
818
- [42, 41].each do |sending_version|
819
- mirror_data = nil
820
- in_offline_app(true) do
821
- @offline_group_data.description = "New Name"
822
- @offline_group_data.save!
823
-
824
- Offroad::SystemState::instance_record.update_attribute(:current_mirror_version, sending_version)
825
-
826
- mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
827
- end
828
-
829
- in_online_app do
830
- group_state = @offline_group.group_state
831
- group_state.confirmed_group_data_version = 42
832
- group_state.save!
833
-
834
- assert_raise Offroad::OldDataError do
835
- Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
836
- end
837
- end
838
- end
839
- end
840
-
841
- cross_test "receiving a down mirror file increments confirmed_global_data_version to the indicated value if larger" do
842
- mirror_data = nil
843
- in_online_app do
844
- GlobalRecord.create(:title => "Testing")
845
-
846
- Offroad::SystemState::instance_record.update_attribute(:current_mirror_version, 42)
847
-
848
- mirror_data = Offroad::MirrorData.new(@offline_group).write_downwards_data
849
- end
850
-
851
- in_offline_app do
852
- assert_equal 1, @offline_group.group_state.confirmed_global_data_version
853
- Offroad::MirrorData.new(@offline_group).load_downwards_data(mirror_data)
854
- assert_equal 42, @offline_group.group_state.confirmed_global_data_version
855
- end
856
- end
857
-
858
- cross_test "received down mirror files are rejected if their version is equal to or lower than current version" do
859
- [42, 41].each do |sending_version|
860
- mirror_data = nil
861
- in_online_app do
862
- GlobalRecord.create(:title => "Testing")
863
-
864
- Offroad::SystemState::instance_record.update_attribute(:current_mirror_version, sending_version)
865
-
866
- mirror_data = Offroad::MirrorData.new(@offline_group).write_downwards_data
867
- end
868
-
869
- in_offline_app do
870
- group_state = @offline_group.group_state
871
- group_state.confirmed_global_data_version = 42
872
- group_state.save!
873
-
874
- assert_raise Offroad::OldDataError do
875
- Offroad::MirrorData.new(@offline_group).load_downwards_data(mirror_data)
876
- end
877
- end
878
- end
879
- end
880
-
881
- cross_test "after loading initial down mirror file global_data_version matches online prior current_mirror_version" do
882
- mirror_data = nil
883
- online_version = nil
884
- in_online_app do
885
- Offroad::SystemState::instance_record.update_attribute(:current_mirror_version, 3)
886
- online_version = Offroad::SystemState::current_mirror_version
887
- mirror_data = Offroad::MirrorData.new(@offline_group, :initial_mode => true).write_downwards_data
888
- end
889
-
890
- in_offline_app(false, true) do
891
- Offroad::MirrorData.new(nil, :initial_mode => true).load_downwards_data(mirror_data)
892
- assert_equal online_version, @offline_group.group_state.confirmed_global_data_version
893
- end
894
- end
895
-
896
- cross_test "down mirror files do not include records which offline is known to already have the latest version of" do
897
- mirror_data = nil
898
- in_online_app do
899
- GlobalRecord.create!(:title => "Record A", :some_boolean => false)
900
- GlobalRecord.create!(:title => "Record B", :some_boolean => false)
901
- mirror_data = Offroad::MirrorData.new(@offline_group).write_downwards_data
902
- end
903
-
904
- in_offline_app do
905
- Offroad::MirrorData.new(@offline_group).load_downwards_data(mirror_data)
906
- mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
907
- end
908
-
909
- in_online_app do
910
- Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
911
- rec_a = GlobalRecord.find_by_title("Record A")
912
- rec_a.some_boolean = true
913
- rec_a.save!
914
- mirror_data = Offroad::MirrorData.new(@offline_group).write_downwards_data
915
- end
916
-
917
- cs = Offroad::CargoStreamer.new(mirror_data, "r")
918
- recs = []
919
- cs.each_cargo_section(Offroad::MirrorData.send(:data_cargo_name_for_model, GlobalRecord)) do |batch|
920
- recs += batch
921
- end
922
- assert_equal 1, recs.size
923
- assert_equal "Record A", recs[0].title
924
- assert_equal true, recs[0].some_boolean
925
- end
926
-
927
- cross_test "up mirror files do not include records which online is known to already have the latest version of" do
928
- mirror_data = nil
929
- in_offline_app do
930
- GroupOwnedRecord.create!(:description => "Another Record", :group => @offline_group)
931
- @offline_group_data.description = "Changed"
932
- @offline_group_data.save!
933
- mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
934
- end
935
-
936
- in_online_app do
937
- Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
938
- mirror_data = Offroad::MirrorData.new(@offline_group).write_downwards_data
939
- end
940
-
941
- in_offline_app do
942
- Offroad::MirrorData.new(@offline_group).load_downwards_data(mirror_data)
943
- @offline_group_data.description = "Changed Again"
944
- @offline_group_data.save!
945
- mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
946
- end
947
-
948
- cs = Offroad::CargoStreamer.new(mirror_data, "r")
949
- recs = []
950
- cs.each_cargo_section(Offroad::MirrorData.send(:data_cargo_name_for_model, GroupOwnedRecord)) do |batch|
951
- recs += batch
952
- end
953
- assert_equal 1, recs.size
954
- assert_equal "Changed Again", recs[0].description
955
- end
956
-
957
- offline_test "changed records are re-included in new up mirror files if their reception is not confirmed" do
958
- @offline_group_data.description = "Changed"
959
- @offline_group_data.save!
960
-
961
- 2.times do
962
- cs = Offroad::CargoStreamer.new(Offroad::MirrorData.new(@offline_group).write_upwards_data, "r")
963
- assert_single_model_cargo_entry_matches(cs, @offline_group_data)
964
- end
965
- end
966
-
967
- online_test "changed records are re-included in new down mirror files if their reception is not confirmed" do
968
- global_rec = GlobalRecord.create(:title => "Testing")
969
-
970
- 2.times do
971
- cs = Offroad::CargoStreamer.new(Offroad::MirrorData.new(@offline_group).write_downwards_data, "r")
972
- assert_single_model_cargo_entry_matches(cs, global_rec)
973
- end
974
- end
975
-
976
- cross_test "up mirror files do not include deletion requests for records known to be deleted on online system" do
977
- sec_name = Offroad::MirrorData.send(:deletion_cargo_name_for_model, GroupOwnedRecord)
978
-
979
- mirror_data = nil
980
- in_offline_app do
981
- @offline_group_data.destroy
982
- mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
983
- end
984
-
985
- assert_equal 1, all_records_from_section_named(Offroad::CargoStreamer.new(mirror_data, "r"), sec_name).size
986
-
987
- in_online_app do
988
- Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
989
- mirror_data = Offroad::MirrorData.new(@offline_group).write_downwards_data
990
- end
991
-
992
- in_offline_app do
993
- Offroad::MirrorData.new(@offline_group).load_downwards_data(mirror_data)
994
- mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
995
- end
996
-
997
- assert_equal 0, all_records_from_section_named(Offroad::CargoStreamer.new(mirror_data, "r"), sec_name).size
998
- end
999
-
1000
- cross_test "down mirror files do not include deletion requests for records known to be deleted on offline system" do
1001
- sec_name = Offroad::MirrorData.send(:deletion_cargo_name_for_model, GlobalRecord)
1002
-
1003
- mirror_data = nil
1004
- in_online_app do
1005
- GlobalRecord.create(:title => "Testing")
1006
- mirror_data = Offroad::MirrorData.new(@offline_group).write_downwards_data
1007
- end
1008
-
1009
- in_offline_app do
1010
- Offroad::MirrorData.new(@offline_group).load_downwards_data(mirror_data)
1011
- mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
1012
- end
1013
-
1014
- in_online_app do
1015
- Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
1016
- GlobalRecord.find_by_title("Testing").destroy
1017
- mirror_data = Offroad::MirrorData.new(@offline_group).write_downwards_data
1018
- end
1019
-
1020
- assert_equal 1, all_records_from_section_named(Offroad::CargoStreamer.new(mirror_data, "r"), sec_name).size
1021
-
1022
- in_offline_app do
1023
- Offroad::MirrorData.new(@offline_group).load_downwards_data(mirror_data)
1024
- mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
1025
- end
1026
-
1027
- in_online_app do
1028
- Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
1029
- mirror_data = Offroad::MirrorData.new(@offline_group).write_downwards_data
1030
- end
1031
-
1032
- assert_equal 0, all_records_from_section_named(Offroad::CargoStreamer.new(mirror_data, "r"), sec_name).size
1033
- end
1034
-
1035
- offline_test "deletions are re-included in new up mirror files if their reception is not confirmed" do
1036
- sec_name = Offroad::MirrorData.send(:deletion_cargo_name_for_model, GroupOwnedRecord)
1037
- @offline_group_data.destroy
1038
-
1039
- 2.times do
1040
- cs = Offroad::CargoStreamer.new(Offroad::MirrorData.new(@offline_group).write_upwards_data, "r")
1041
- assert_equal 1, all_records_from_section_named(cs, sec_name).size
1042
- end
1043
- end
1044
-
1045
- cross_test "deletions are re-included in new down mirror files if their reception is not confirmed" do
1046
- mirror_data = nil
1047
- in_online_app do
1048
- global_rec = GlobalRecord.create(:title => "Testing")
1049
- mirror_data = Offroad::MirrorData.new(@offline_group).write_downwards_data
1050
- end
1051
-
1052
- in_offline_app do
1053
- Offroad::MirrorData.new(@offline_group).load_downwards_data(mirror_data)
1054
- mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
1055
- end
1056
-
1057
- in_online_app do
1058
- Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
1059
-
1060
- GlobalRecord.find_by_title("Testing").destroy
1061
- sec_name = Offroad::MirrorData.send(:deletion_cargo_name_for_model, GlobalRecord)
1062
- 2.times do
1063
- cs = Offroad::CargoStreamer.new(Offroad::MirrorData.new(@offline_group).write_downwards_data, "r")
1064
- assert_equal 1, all_records_from_section_named(cs, sec_name).size
1065
- end
1066
- end
1067
- end
1068
-
1069
- online_test "records from other offline groups are not included in initial down mirror files" do
1070
- another_offline_group = Group.create(:name => "One More Offline Group")
1071
- data = GroupOwnedRecord.create(:description => "One More Offline Data", :group => another_offline_group)
1072
- another_offline_group.group_offline = true
1073
- mirror_data = Offroad::MirrorData.new(@offline_group, :initial_mode => true).write_downwards_data
1074
- cs = Offroad::CargoStreamer.new(mirror_data, "r")
1075
- assert_record_not_present(cs, data)
1076
- end
1077
-
1078
- cross_test "protected attributes can be updated from up mirror files" do
1079
- mirror_data = nil
1080
- in_offline_app do
1081
- @offline_group_data.protected_integer = 123
1082
- @offline_group_data.save!
1083
- mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
1084
- end
1085
-
1086
- in_online_app do
1087
- assert_not_equal 123, @offline_group_data.protected_integer
1088
- Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
1089
- @offline_group_data.reload
1090
- assert_equal 123, @offline_group_data.protected_integer
1091
- end
1092
- end
1093
-
1094
- cross_test "protected attributes can be updated from down mirror files" do
1095
- mirror_data = nil
1096
- in_online_app do
1097
- GlobalRecord.create(:title => "Testing")
1098
- mirror_data = Offroad::MirrorData.new(@offline_group).write_downwards_data
1099
- end
1100
-
1101
- in_offline_app do
1102
- Offroad::MirrorData.new(@offline_group).load_downwards_data(mirror_data)
1103
- mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
1104
- end
1105
-
1106
- in_online_app do
1107
- Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
1108
- grec = GlobalRecord.find_by_title("Testing")
1109
- grec.protected_integer = 789
1110
- grec.save!
1111
- mirror_data = Offroad::MirrorData.new(@offline_group).write_downwards_data
1112
- end
1113
-
1114
- in_offline_app do
1115
- assert_not_equal 789, GlobalRecord.find_by_title("Testing").protected_integer
1116
- Offroad::MirrorData.new(@offline_group).load_downwards_data(mirror_data)
1117
- assert_equal 789, GlobalRecord.find_by_title("Testing").protected_integer
1118
- end
1119
- end
1120
-
1121
- cross_test "cannot use an up mirror file to delete the group record itself" do
1122
- mirror_data = nil
1123
- in_offline_app do
1124
- mirror_data = StringIO.open do |sio|
1125
- cs = Offroad::CargoStreamer.new(sio, "w")
1126
- Offroad::MirrorData.new(@offline_group).write_upwards_data(cs)
1127
-
1128
- sec_name = Offroad::MirrorData.send(:deletion_cargo_name_for_model, Group)
1129
- deletion_srs = Offroad::SendableRecordState.for_record(@offline_group).first
1130
- deletion_srs.deleted = true
1131
- cs.write_cargo_section(sec_name, [deletion_srs])
1132
-
1133
- sec_name = Offroad::MirrorData.send(:deletion_cargo_name_for_model, GroupOwnedRecord)
1134
- deletion_srs = Offroad::SendableRecordState.for_record(@offline_group_data).first
1135
- deletion_srs.deleted = true
1136
- cs.write_cargo_section(sec_name, [deletion_srs])
1137
-
1138
- sio.string
1139
- end
1140
- end
1141
-
1142
- in_online_app do
1143
- Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
1144
- assert_nil GroupOwnedRecord.find_by_description("Sam") # Make sure the deletion faking method actually works...
1145
- assert_not_nil Group.find_by_name("An Offline Group") # Except on group base records
1146
- end
1147
- end
1148
-
1149
- cross_test "after loading an initial down mirror file only changed records appear in up mirror" do
1150
- mirror_data = nil
1151
- in_online_app do
1152
- mirror_data = Offroad::MirrorData.new(@offline_group, :initial_mode => true).write_downwards_data
1153
- end
1154
-
1155
- in_offline_app(false, true) do
1156
- Offroad::MirrorData.new(nil, :initial_mode => true).load_downwards_data(mirror_data)
1157
- group = Group.first
1158
- group.name = "Weird Al"
1159
- group.save!
1160
- group.reload
1161
- mirror_data = Offroad::MirrorData.new(group).write_upwards_data
1162
- cs = Offroad::CargoStreamer.new(mirror_data, "r")
1163
- assert_single_model_cargo_entry_matches(cs, group)
1164
- assert_record_not_present(cs, GroupOwnedRecord.first)
1165
- end
1166
- end
1167
-
1168
- cross_test "cannot affect group records in offline app using a non-initial down mirror file" do
1169
- mirror_data = nil
1170
- in_online_app do
1171
- mirror_data = StringIO.open do |sio|
1172
- cs = Offroad::CargoStreamer.new(sio, "w")
1173
- Offroad::MirrorData.new(@offline_group).write_downwards_data(cs)
1174
-
1175
- grec = GlobalRecord.create(:title => "Testing 123")
1176
- sec_name = Offroad::MirrorData.send(:data_cargo_name_for_model, GlobalRecord)
1177
- cs.write_cargo_section(sec_name, [grec])
1178
-
1179
- sec_name = Offroad::MirrorData.send(:data_cargo_name_for_model, GroupOwnedRecord)
1180
- new_rec = GroupOwnedRecord.new(:description => "Brand New Thing", :group => @offline_group)
1181
- new_rec.id = 1234
1182
- cs.write_cargo_section(sec_name, [new_rec])
1183
-
1184
- sec_name = Offroad::MirrorData.send(:deletion_cargo_name_for_model, GroupOwnedRecord)
1185
- deletion_srs = Offroad::SendableRecordState.for_record(@offline_group_data).new
1186
- deletion_srs.deleted = true
1187
- cs.write_cargo_section(sec_name, [deletion_srs])
1188
-
1189
- sio.string
1190
- end
1191
- end
1192
-
1193
- in_offline_app do
1194
- Offroad::MirrorData.new(@offline_group).load_downwards_data(mirror_data)
1195
-
1196
- # Make sure the section faking method actually works...
1197
- assert_not_nil GlobalRecord.find_by_title("Testing 123")
1198
-
1199
- # Except on group records
1200
- assert_nil GroupOwnedRecord.find_by_description("Brand New Thing")
1201
- assert_not_nil GroupOwnedRecord.find_by_description("Sam")
1202
- end
1203
- end
1204
-
1205
- cross_test "can transfer self-referencing records" do
1206
- mirror_data = nil
1207
- in_offline_app do
1208
- # Create a new self-referencing record
1209
- new_self_ref = GroupOwnedRecord.create(:description => "Phillip J. Fry", :group => @offline_group)
1210
- new_self_ref.parent = new_self_ref
1211
- new_self_ref.save!
1212
- assert_equal new_self_ref.id, new_self_ref.parent.id
1213
-
1214
- # Alter an existing record to be self-referencing
1215
- @offline_group_data.parent = @offline_group_data
1216
- @offline_group_data.save!
1217
-
1218
- mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
1219
- end
1220
-
1221
- in_online_app do
1222
- Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
1223
- assert_record_states_all_valid
1224
-
1225
- fry = GroupOwnedRecord.find_by_description("Phillip J. Fry")
1226
- assert fry
1227
- assert_equal fry.id, fry.parent.id
1228
-
1229
- @offline_group_data.reload
1230
- assert_equal @offline_group_data.id, @offline_group_data.parent.id
1231
- end
1232
- end
1233
-
1234
- cross_test "when a locked group is loaded by an up mirror, it is brought online" do
1235
- mirror_data = nil
1236
- in_offline_app do
1237
- @offline_group.offroad_group_lock!
1238
- mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
1239
- end
1240
- in_online_app do
1241
- Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
1242
- assert @offline_group.group_online?
1243
- end
1244
- end
1245
-
1246
- cross_test "model method after_offroad_upload is called after it is uploaded to initial offline app" do
1247
- mirror_data = nil
1248
- in_online_app do
1249
- mirror_data = Offroad::MirrorData.new(@offline_group, :initial_mode => true).write_downwards_data
1250
- end
1251
-
1252
- in_offline_app(false, true) do
1253
- GroupOwnedRecord.reset_after_upload_count
1254
- assert_equal 0, GroupOwnedRecord.after_upload_count
1255
- Offroad::MirrorData.new(nil, :initial_mode => true).load_downwards_data(mirror_data)
1256
- assert_equal GroupOwnedRecord.count, GroupOwnedRecord.after_upload_count
1257
- end
1258
- end
1259
-
1260
- cross_test "model method after_offroad_upload is called after it is uploaded to online app" do
1261
- mirror_data = nil
1262
- in_offline_app do
1263
- @offline_group_data.description = "The Mystery Spot"
1264
- @offline_group_data.save!
1265
- mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
1266
- end
1267
- end
1268
-
1269
- cross_test "model method after_offroad_destroy is called after object destruction propagated to online app" do
1270
- mirror_data = nil
1271
- in_offline_app do
1272
- @offline_group_data.destroy
1273
- mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
1274
- end
1275
-
1276
- in_online_app do
1277
- GroupOwnedRecord.reset_after_destroy_count
1278
- assert_equal 0, GroupOwnedRecord.after_destroy_count
1279
- Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
1280
- assert_equal 1, GroupOwnedRecord.after_destroy_count # One record destroyed
1281
- end
1282
- end
1283
- end
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ class MirrorDataTest < Test::Unit::TestCase
4
+ online_test "cannot create MirrorData instance for online group" do
5
+ assert_raise Offroad::DataError do
6
+ Offroad::MirrorData.new(@online_group)
7
+ end
8
+ end
9
+
10
+ def all_records_from_section_named(cs, name)
11
+ recs = []
12
+ cs.each_cargo_section(name) do |batch|
13
+ recs += batch
14
+ end
15
+ return recs
16
+ end
17
+
18
+ def assert_single_cargo_section_named(cs, name)
19
+ count = 0
20
+ cs.each_cargo_section(name) do |data|
21
+ count += 1
22
+ end
23
+ assert_equal 1, count
24
+ end
25
+
26
+ def assert_no_cargo_sections_named(cs, name)
27
+ assert_nothing_raised do
28
+ cs.each_cargo_section(name) do |data|
29
+ raise "There shouldn't be any cargo sections with that name"
30
+ end
31
+ end
32
+ end
33
+
34
+ def assert_common_mirror_elements_appear_valid(cs, mode)
35
+ assert_single_cargo_section_named cs, "mirror_info"
36
+
37
+ mirror_info = cs.first_cargo_element("mirror_info")
38
+ assert_instance_of Offroad::MirrorInfo, mirror_info
39
+ migration_query = "SELECT version FROM schema_migrations ORDER BY version"
40
+ migrations = Group.connection.select_all(migration_query).map{ |r| r["version"] }
41
+ assert_equal migrations, mirror_info.schema_migrations.split(",").sort
42
+ assert_equal mirror_info.app, Offroad::app_name
43
+ assert Time.now - mirror_info.created_at < 30
44
+ assert mirror_info.app_mode.downcase.include?(mode.downcase)
45
+
46
+ assert_single_cargo_section_named cs, "group_state"
47
+ group_state = cs.first_cargo_element("group_state")
48
+ assert_instance_of Offroad::GroupState, group_state
49
+ assert_equal @offline_group.id, group_state.app_group_id
50
+ end
51
+
52
+ def strip_msecs_in_values(hash)
53
+ new_hash = {}
54
+ hash.each do |k,v|
55
+ if v.is_a?(DateTime) || v.is_a?(Time)
56
+ new_hash[k] = v.to_i
57
+ else
58
+ new_hash[k] = v
59
+ end
60
+ end
61
+ new_hash
62
+ end
63
+
64
+ def assert_single_model_cargo_entry_matches(cs, record)
65
+ record.reload
66
+ data_name = Offroad::MirrorData.send(:data_cargo_name_for_model, record.class)
67
+ assert_single_cargo_section_named cs, data_name
68
+ assert_equal strip_msecs_in_values(record.attributes), strip_msecs_in_values(cs.first_cargo_element(data_name).attributes)
69
+ end
70
+
71
+ def assert_record_not_present(cs, record)
72
+ record.reload
73
+ data_name = Offroad::MirrorData.send(:data_cargo_name_for_model, record.class)
74
+ assert_nothing_raised do
75
+ cs.each_cargo_section(data_name) do |batch|
76
+ batch.each do |cargo_record|
77
+ raise "Undesired record found" if record.attributes == cargo_record.attributes
78
+ end
79
+ end
80
+ end
81
+ end
82
+
83
+ cross_test "can pass data to MirrorData read methods as CargoStreamer, String, or IO" do
84
+ mirror_data = nil
85
+ in_online_app do
86
+ GlobalRecord.create(:title => "Foo Bar")
87
+ mirror_data = Offroad::MirrorData.new(@offline_group).write_downwards_data
88
+ end
89
+
90
+ sources = [
91
+ Offroad::CargoStreamer.new(mirror_data, "r"),
92
+ StringIO.new(mirror_data, "r"),
93
+ mirror_data
94
+ ]
95
+ sources.each do |source|
96
+ in_offline_app(true) do
97
+ assert_equal 0, GlobalRecord.count
98
+ Offroad::MirrorData.new(@offline_group).load_downwards_data(source)
99
+ assert GlobalRecord.find_by_title("Foo Bar")
100
+ end
101
+ end
102
+ end
103
+
104
+ offline_test "can have MirrorData write methods send to CargoStreamer, IO, or return value" do
105
+ cargo_streamer_sio = StringIO.new
106
+ cargo_streamer = Offroad::CargoStreamer.new(cargo_streamer_sio, "w")
107
+ direct_sio = StringIO.new
108
+
109
+ writer = Offroad::MirrorData.new(@offline_group)
110
+ writer.write_upwards_data(cargo_streamer)
111
+ writer.write_upwards_data(direct_sio)
112
+ str = writer.write_upwards_data
113
+
114
+ cargo_streamer_sio.rewind
115
+ direct_sio.rewind
116
+ result_a = Offroad::CargoStreamer.new(cargo_streamer_sio, "r").cargo_section_names
117
+ result_b = Offroad::CargoStreamer.new(direct_sio, "r").cargo_section_names
118
+ result_c = Offroad::CargoStreamer.new(StringIO.new(str), "r").cargo_section_names
119
+
120
+ assert result_a.size > 0
121
+ assert result_a == result_b
122
+ assert result_b == result_c
123
+ end
124
+
125
+ online_test "can generate a valid initial down mirror file for the offline group" do
126
+ global_record = GlobalRecord.create(:title => "Foo Bar")
127
+ global_record.reload # To clear the high time precision that is lost in the database
128
+
129
+ str = Offroad::MirrorData.new(@offline_group, :initial_mode => true).write_downwards_data
130
+ cs = Offroad::CargoStreamer.new(str, "r")
131
+ assert_common_mirror_elements_appear_valid cs, "online"
132
+ assert_single_model_cargo_entry_matches cs, global_record
133
+ assert_single_model_cargo_entry_matches cs, @offline_group
134
+ assert_single_model_cargo_entry_matches cs, @offline_group_data
135
+ end
136
+
137
+ online_test "can convert online group to an offline group and generate valid initial down mirror file" do
138
+ global_record = GlobalRecord.create(:title => "Foo Bar")
139
+ global_record.reload # To clear the high time precision that is lost in the database
140
+
141
+ @online_group.group_offline = true
142
+ str = Offroad::MirrorData.new(@online_group, :initial_mode => true).write_downwards_data
143
+ cs = Offroad::CargoStreamer.new(str, "r")
144
+ assert_single_model_cargo_entry_matches cs, global_record
145
+ assert_single_model_cargo_entry_matches cs, @online_group
146
+ assert_single_model_cargo_entry_matches cs, @online_group_data
147
+ end
148
+
149
+ online_test "can generate a valid down mirror file for the offline group" do
150
+ global_record = GlobalRecord.create(:title => "Foo Bar")
151
+ global_record.reload # To clear the high time precision that is lost in the database
152
+
153
+ str = Offroad::MirrorData.new(@offline_group).write_downwards_data
154
+ cs = Offroad::CargoStreamer.new(str, "r")
155
+ assert_common_mirror_elements_appear_valid cs, "online"
156
+ assert_single_model_cargo_entry_matches cs, global_record
157
+ assert_record_not_present cs, @offline_group
158
+ assert_record_not_present cs, @offline_group_data
159
+ end
160
+
161
+ online_test "initial down mirror files do not include irrelevant records" do
162
+ another_offline_group = Group.create!(:name => "Another Group")
163
+ another_group_data = GroupOwnedRecord.create!(:description => "Another Data", :group => another_offline_group)
164
+ another_offline_group.group_offline = true
165
+ [another_offline_group, another_group_data].each { |r| r.reload }
166
+
167
+ str = Offroad::MirrorData.new(@offline_group, :initial_mode => true).write_downwards_data
168
+ cs = Offroad::CargoStreamer.new(str, "r")
169
+ assert_record_not_present cs, another_offline_group
170
+ assert_record_not_present cs, another_group_data
171
+ assert_single_model_cargo_entry_matches cs, @offline_group
172
+ assert_single_model_cargo_entry_matches cs, @offline_group_data
173
+ end
174
+
175
+ online_test "down mirror files do not include irrelevant records" do
176
+ global_record = GlobalRecord.create(:title => "Foo Bar")
177
+ global_record.reload # To clear the high time precision that is lost in the database
178
+ another_offline_group = Group.create!(:name => "Another Group")
179
+ another_group_data = GroupOwnedRecord.create!(:description => "Another Data", :group => another_offline_group)
180
+ another_offline_group.group_offline = true
181
+ [another_offline_group, another_group_data].each { |r| r.reload }
182
+
183
+ str = Offroad::MirrorData.new(@offline_group).write_downwards_data
184
+ cs = Offroad::CargoStreamer.new(str, "r")
185
+ assert_record_not_present cs, another_offline_group
186
+ assert_record_not_present cs, another_group_data
187
+ assert_record_not_present cs, @offline_group
188
+ assert_record_not_present cs, @offline_group_data
189
+ assert_single_model_cargo_entry_matches cs, global_record
190
+ end
191
+
192
+ offline_test "can generate a valid up mirror file for the offline group" do
193
+ @offline_group.name = "Changed"
194
+ @offline_group.save!
195
+ @offline_group.reload
196
+ @offline_group_data.some_integer = 5551212
197
+ @offline_group_data.save!
198
+ @offline_group_data.reload
199
+ str = Offroad::MirrorData.new(@offline_group).write_upwards_data
200
+ cs = Offroad::CargoStreamer.new(str, "r")
201
+ assert_common_mirror_elements_appear_valid cs, "offline"
202
+ assert_single_model_cargo_entry_matches cs, @offline_group
203
+ assert_single_model_cargo_entry_matches cs, @offline_group_data
204
+ end
205
+
206
+ offline_test "up mirror files do not include irrelevant records" do
207
+ fake_global_data = GlobalRecord.new(:title => "Fake Stuff")
208
+ force_save_and_reload(fake_global_data)
209
+
210
+ str = Offroad::MirrorData.new(@offline_group).write_upwards_data
211
+ cs = Offroad::CargoStreamer.new(str, "r")
212
+ assert_record_not_present cs, fake_global_data
213
+ end
214
+
215
+ offline_test "cannot upload an invalid down mirror file" do
216
+ assert_raise Offroad::DataError do
217
+ Offroad::MirrorData.new(@offline_group).load_downwards_data("FOO BAR BLAH")
218
+ end
219
+ end
220
+
221
+ online_test "cannot upload an invalid up mirror file" do
222
+ assert_raise Offroad::DataError do
223
+ Offroad::MirrorData.new(@offline_group).load_upwards_data("FOO BAR BLAH")
224
+ end
225
+ end
226
+
227
+ offline_test "cannot use load_upwards_data in offline mode" do
228
+ assert_raise Offroad::PluginError do
229
+ Offroad::MirrorData.new(@offline_group).load_upwards_data("FOO BAR BLAH")
230
+ end
231
+ end
232
+
233
+ online_test "cannot use load_downwards_data in online mode" do
234
+ assert_raise Offroad::PluginError do
235
+ Offroad::MirrorData.new(@offline_group).load_downwards_data("FOO BAR BLAH")
236
+ end
237
+ end
238
+
239
+ def assert_record_states_all_valid
240
+ Offroad::ReceivedRecordState.all.each do |rrs|
241
+ if not rrs.valid?
242
+ flunk "Invalid RRS (#{rrs.attributes.map{|k,v| "#{k}:#{v}"}.join(",")}) : #{rrs.errors.full_messages.join(",")}"
243
+ end
244
+ end
245
+ Offroad::SendableRecordState.all.each do |srs|
246
+ if not srs.valid?
247
+ flunk "Invalid SRS (#{srs.attributes.map{|k,v| "#{k}:#{v}"}.join(",")}) : #{srs.errors.full_messages.join(",")}"
248
+ end
249
+ end
250
+ end
251
+
252
+ online_test "initial online record states all valid" do
253
+ assert_record_states_all_valid
254
+ end
255
+
256
+ offline_test "initial offline record states all valid" do
257
+ assert_record_states_all_valid
258
+ end
259
+
260
+ cross_test "can insert and update group data using an up mirror file" do
261
+ mirror_data = nil
262
+
263
+ in_offline_app do
264
+ @offline_group.name = "TEST 123"
265
+ @offline_group.save!
266
+ @offline_group_data.description = "TEST XYZ"
267
+ @offline_group_data.save!
268
+ GroupOwnedRecord.create!(:description => "TEST ABC", :group => @offline_group)
269
+ mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
270
+ end
271
+
272
+ in_online_app do
273
+ prior_rrs_count = Offroad::ReceivedRecordState.count
274
+ Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
275
+ assert_record_states_all_valid
276
+ assert_equal prior_rrs_count+1, Offroad::ReceivedRecordState.count
277
+ assert_equal @offline_group.id, Group.find_by_name("TEST 123").id
278
+ assert GroupOwnedRecord.find_by_description("TEST ABC")
279
+ assert_equal @offline_group_data.id, GroupOwnedRecord.find_by_description("TEST XYZ").id
280
+ end
281
+ end
282
+
283
+ cross_test "records created by up mirror file did not have their callbacks called" do
284
+ mirror_data = nil
285
+ in_offline_app do
286
+ GroupOwnedRecord.create(:description => "TEST ABC", :group => @offline_group)
287
+ mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
288
+ end
289
+
290
+ in_online_app do
291
+ GroupOwnedRecord.reset_callback_called
292
+ Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
293
+ assert !GroupOwnedRecord.callback_called
294
+ end
295
+ end
296
+
297
+ cross_test "records updated by up mirror file did not have their callbacks called" do
298
+ mirror_data = nil
299
+ in_offline_app do
300
+ @offline_group_data.description = "TEST XYZ"
301
+ @offline_group_data.save!
302
+ mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
303
+ end
304
+
305
+ in_online_app do
306
+ GroupOwnedRecord.reset_callback_called
307
+ Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
308
+ assert !GroupOwnedRecord.callback_called
309
+ end
310
+ end
311
+
312
+ cross_test "records destroyed by up mirror file did not have their callbacks called" do
313
+ mirror_data = nil
314
+ in_offline_app do
315
+ @offline_group_data.destroy
316
+ mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
317
+ end
318
+
319
+ in_online_app do
320
+ GroupOwnedRecord.reset_callback_called
321
+ Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
322
+ assert !GroupOwnedRecord.callback_called
323
+ end
324
+ end
325
+
326
+ cross_test "can delete group data using an up mirror file" do
327
+ mirror_data = nil
328
+
329
+ in_offline_app do
330
+ @offline_group_data.destroy
331
+ mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
332
+ end
333
+
334
+ in_online_app do
335
+ prior_rrs_count = Offroad::ReceivedRecordState.count
336
+ assert_equal 1, GroupOwnedRecord.count(:conditions => { :group_id => @offline_group.id })
337
+ Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
338
+ assert_record_states_all_valid
339
+ assert_equal prior_rrs_count-1, Offroad::ReceivedRecordState.count
340
+ assert_equal 0, GroupOwnedRecord.count(:conditions => { :group_id => @offline_group.id })
341
+ end
342
+ end
343
+
344
+ cross_test "can insert and update and delete global records using a down mirror file" do
345
+ mirror_data = nil
346
+
347
+ in_online_app do
348
+ GlobalRecord.create(:title => "ABC")
349
+ GlobalRecord.create(:title => "123")
350
+ mirror_data = Offroad::MirrorData.new(@offline_group).write_downwards_data
351
+ end
352
+
353
+ offline_number_rec_id = nil
354
+ in_offline_app do
355
+ rrs_scope = Offroad::ReceivedRecordState.for_model(GlobalRecord)
356
+ assert_equal 0, rrs_scope.count
357
+ assert_equal 0, GlobalRecord.count
358
+ Offroad::MirrorData.new(@offline_group).load_downwards_data(mirror_data)
359
+ assert_record_states_all_valid
360
+ assert_equal 2, rrs_scope.count
361
+ assert_equal 2, GlobalRecord.count
362
+ assert_not_nil GlobalRecord.find_by_title("ABC")
363
+ assert_not_nil GlobalRecord.find_by_title("123")
364
+ offline_number_rec_id = GlobalRecord.find_by_title("123")
365
+ end
366
+
367
+ in_online_app do
368
+ number_rec = GlobalRecord.find_by_title("123")
369
+ number_rec.title = "789"
370
+ number_rec.save!
371
+
372
+ letter_rec = GlobalRecord.find_by_title("ABC")
373
+ letter_rec.destroy
374
+
375
+ mirror_data = Offroad::MirrorData.new(@offline_group).write_downwards_data
376
+ end
377
+
378
+ in_offline_app do
379
+ rrs_scope = Offroad::ReceivedRecordState.for_model(GlobalRecord)
380
+ Offroad::MirrorData.new(@offline_group).load_downwards_data(mirror_data)
381
+ assert_record_states_all_valid
382
+ assert_equal 1, rrs_scope.count
383
+ assert_equal 1, GlobalRecord.count
384
+ assert_nil GlobalRecord.find_by_title("ABC")
385
+ assert_nil GlobalRecord.find_by_title("123")
386
+ assert_not_nil GlobalRecord.find_by_title("789")
387
+ assert_equal offline_number_rec_id, GlobalRecord.find_by_title("789")
388
+ end
389
+ end
390
+
391
+ cross_test "can insert group records using an initial down mirror file" do
392
+ mirror_data = nil
393
+ in_online_app do
394
+ mirror_data = Offroad::MirrorData.new(@offline_group, :initial_mode => true).write_downwards_data
395
+ end
396
+
397
+ in_offline_app(false, true) do
398
+ assert_equal 0, Group.count
399
+ assert_equal 0, GroupOwnedRecord.count
400
+ assert_equal 0, Offroad::SendableRecordState.for_model(Group).count
401
+ assert_equal 0, Offroad::SendableRecordState.for_model(GroupOwnedRecord).count
402
+ Offroad::MirrorData.new(nil, :initial_mode => true).load_downwards_data(mirror_data)
403
+ assert_record_states_all_valid
404
+ assert_equal 1, Group.count
405
+ assert_equal 1, GroupOwnedRecord.count
406
+ assert_equal 1, Offroad::SendableRecordState.for_model(Group).count
407
+ assert_equal 1, Offroad::SendableRecordState.for_model(GroupOwnedRecord).count
408
+ end
409
+ end
410
+
411
+ cross_test "records created by initial down mirror file did not have their callbacks called" do
412
+ mirror_data = nil
413
+ in_online_app do
414
+ mirror_data = Offroad::MirrorData.new(@offline_group, :initial_mode => true).write_downwards_data
415
+ end
416
+
417
+ in_offline_app(false, true) do
418
+ GroupOwnedRecord.reset_callback_called
419
+ Offroad::MirrorData.new(nil, :initial_mode => true).load_downwards_data(mirror_data)
420
+ assert !GroupOwnedRecord.callback_called
421
+ end
422
+ end
423
+
424
+ cross_test "can insert global records using an initial down mirror file" do
425
+ mirror_data = nil
426
+ in_online_app do
427
+ GlobalRecord.create(:title => "Something")
428
+ mirror_data = Offroad::MirrorData.new(@offline_group, :initial_mode => true).write_downwards_data
429
+ end
430
+
431
+ in_offline_app(false, true) do
432
+ assert_equal 0, GlobalRecord.count
433
+ assert_equal 0, Offroad::SendableRecordState.for_model(GlobalRecord).count
434
+ assert_equal 0, Offroad::ReceivedRecordState.for_model(GlobalRecord).count
435
+ Offroad::MirrorData.new(nil, :initial_mode => true).load_downwards_data(mirror_data)
436
+ assert_record_states_all_valid
437
+ assert_equal 1, GlobalRecord.count
438
+ assert_not_nil GlobalRecord.find_by_title("Something")
439
+ assert_equal 0, Offroad::SendableRecordState.for_model(GlobalRecord).count
440
+ assert_equal 1, Offroad::ReceivedRecordState.for_model(GlobalRecord).count
441
+ end
442
+ end
443
+
444
+ cross_test "cannot load regular down mirror file in empty offline app" do
445
+ mirror_data = nil
446
+ in_online_app { mirror_data = Offroad::MirrorData.new(@offline_group).write_downwards_data }
447
+
448
+ in_offline_app(false, true) do
449
+ assert_raise Offroad::PluginError do
450
+ Offroad::MirrorData.new(nil).load_downwards_data(mirror_data)
451
+ end
452
+ end
453
+ end
454
+
455
+ cross_test "importing an initial down mirror file deletes all currently existing records" do
456
+ mirror_data = nil
457
+ in_online_app do
458
+ mirror_data = Offroad::MirrorData.new(@offline_group, :initial_mode => true).write_downwards_data
459
+ end
460
+
461
+ in_offline_app do
462
+ @offline_group.update_attribute(:name, "Old")
463
+ GroupOwnedRecord.create!(:description => "Old", :group => @offline_group)
464
+ UnmirroredRecord.create!(:content => "Old Old Old")
465
+ global_data = GlobalRecord.new(:title => "Old")
466
+ force_save_and_reload(global_data)
467
+
468
+ Offroad::MirrorData.new(nil, :initial_mode => true).load_downwards_data(mirror_data)
469
+
470
+ assert_equal nil, Group.find_by_name("Old")
471
+ assert_equal nil, GroupOwnedRecord.find_by_description("Old")
472
+ assert_equal 1, Group.count
473
+ assert_equal 1, GroupOwnedRecord.count
474
+ assert_equal 0, GlobalRecord.count
475
+ assert_equal 0, UnmirroredRecord.count
476
+ end
477
+ end
478
+
479
+ cross_test "importing an initial down mirror file resets autoincrement counters" do
480
+ mirror_data = nil
481
+ in_online_app do
482
+ mirror_data = Offroad::MirrorData.new(@offline_group, :initial_mode => true).write_downwards_data
483
+ end
484
+
485
+ in_offline_app do
486
+ global_rec_a = GlobalRecord.new(:title => "A")
487
+ global_rec_b = GlobalRecord.new(:title => "B")
488
+ global_rec_c = GlobalRecord.new(:title => "C")
489
+ force_save_and_reload(global_rec_a, global_rec_b, global_rec_c)
490
+
491
+ Offroad::MirrorData.new(nil, :initial_mode => true).load_downwards_data(mirror_data)
492
+
493
+ global_rec = GlobalRecord.new(:title => "Test")
494
+ force_save_and_reload(global_rec)
495
+ assert_equal 1, global_rec.id
496
+ end
497
+ end
498
+
499
+ cross_test "cannot upload an initial down mirror file unless passed :initial_mode => true to MirrorData.new" do
500
+ mirror_data = nil
501
+ in_online_app do
502
+ mirror_data = Offroad::MirrorData.new(@offline_group, :initial_mode => true).write_downwards_data
503
+ end
504
+
505
+ in_offline_app do
506
+ assert_raise Offroad::DataError do
507
+ Offroad::MirrorData.new(@offline_group).load_downwards_data(mirror_data)
508
+ end
509
+ end
510
+ end
511
+
512
+ cross_test "cannot upload a non-initial down mirror file after passing :initial_mode => true to MirrorData.new" do
513
+ mirror_data = nil
514
+ in_online_app { mirror_data = Offroad::MirrorData.new(@offline_group).write_downwards_data }
515
+
516
+ in_offline_app do
517
+ assert_raise Offroad::DataError do
518
+ Offroad::MirrorData.new(@offline_group, :initial_mode => true).load_downwards_data(mirror_data)
519
+ end
520
+ end
521
+ end
522
+
523
+ cross_test "cannot upload a non-initial down mirror file to a blank offline instance" do
524
+ mirror_data = nil
525
+ in_online_app { mirror_data = Offroad::MirrorData.new(@offline_group).write_downwards_data }
526
+
527
+ in_offline_app(false, true) do
528
+ assert_raise Offroad::DataError do
529
+ Offroad::MirrorData.new(@offline_group).load_downwards_data(mirror_data)
530
+ end
531
+ end
532
+ end
533
+
534
+ cross_test "cannot pass a down mirror file to load_upwards_data" do
535
+ mirror_data = nil
536
+
537
+ in_online_app do
538
+ mirror_data = Offroad::MirrorData.new(@offline_group).write_downwards_data
539
+
540
+ assert_raise Offroad::DataError do
541
+ Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
542
+ end
543
+ end
544
+
545
+ in_offline_app do
546
+ assert_nothing_raised do
547
+ Offroad::MirrorData.new(@offline_group).load_downwards_data(mirror_data)
548
+ end
549
+ end
550
+ end
551
+
552
+ cross_test "cannot pass an up mirror file to load_downwards_data" do
553
+ mirror_data = nil
554
+
555
+ in_offline_app do
556
+ mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
557
+
558
+ assert_raise Offroad::DataError do
559
+ Offroad::MirrorData.new(@offline_group).load_downwards_data(mirror_data)
560
+ end
561
+ end
562
+
563
+ in_online_app do
564
+ assert_nothing_raised do
565
+ Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
566
+ end
567
+ end
568
+ end
569
+
570
+ cross_test "transformed ids are handled properly when loading an up mirror file" do
571
+ in_online_app do
572
+ another_online_record = GroupOwnedRecord.create(:description => "Yet Another", :group => @online_group)
573
+ end
574
+
575
+ mirror_data = nil
576
+ offline_id_of_new_rec = nil
577
+ in_offline_app do
578
+ another_offline_rec = GroupOwnedRecord.create(:description => "One More", :group => @offline_group)
579
+ offline_id_of_new_rec = another_offline_rec.id
580
+ mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
581
+ end
582
+
583
+ in_online_app do
584
+ Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
585
+ assert_record_states_all_valid
586
+ rec = GroupOwnedRecord.find_by_description("One More")
587
+ assert rec
588
+ assert_equal offline_id_of_new_rec, Offroad::ReceivedRecordState.for_record(rec).first.remote_record_id
589
+ end
590
+ end
591
+
592
+ cross_test "transformed ids are handled properly when loading an initial down mirror file" do
593
+ mirror_data = nil
594
+ online_id_of_offline_rec = nil
595
+ in_online_app do
596
+ online_id_of_offline_rec = @offline_group_data.id
597
+ mirror_data = Offroad::MirrorData.new(@offline_group, :initial_mode => true).write_downwards_data
598
+ end
599
+
600
+ in_offline_app do
601
+ Offroad::MirrorData.new(nil, :initial_mode => true).load_downwards_data(mirror_data)
602
+ assert_record_states_all_valid
603
+ rec = GroupOwnedRecord.find_by_description("Sam")
604
+ assert_equal online_id_of_offline_rec, rec.id
605
+ rec.description = "Samuel Jackson"
606
+ rec.save!
607
+ mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
608
+ end
609
+
610
+ in_online_app do
611
+ Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
612
+ assert_equal nil, GroupOwnedRecord.find_by_description("Sam")
613
+ assert_equal "Samuel Jackson", GroupOwnedRecord.find(online_id_of_offline_rec).description
614
+ end
615
+ end
616
+
617
+ online_test "initial down mirror files do not include deletion entries" do
618
+ global_record = GlobalRecord.create(:title => "Something")
619
+ global_record.destroy
620
+
621
+ str = Offroad::MirrorData.new(@offline_group, :initial_mode => true).write_downwards_data
622
+ cs = Offroad::CargoStreamer.new(str, "r")
623
+ deletion_cargo_name = Offroad::MirrorData.send(:deletion_cargo_name_for_model, GlobalRecord)
624
+ assert_equal false, cs.has_cargo_named?(deletion_cargo_name)
625
+ end
626
+
627
+ offline_test "can only create mirror files containing invalid records when skip_validation is true" do
628
+ group_rec = GroupOwnedRecord.new(:description => "Invalid record", :group => @offline_group, :should_be_even => 3)
629
+ group_rec.save_without_validation
630
+ assert_raise Offroad::DataError do
631
+ Offroad::MirrorData.new(@offline_group).write_upwards_data
632
+ end
633
+ assert_nothing_raised do
634
+ Offroad::MirrorData.new(@offline_group, :skip_validation => true).write_upwards_data
635
+ end
636
+ end
637
+
638
+ cross_test "cannot import up mirror files with invalid records unless skip_validation is enabled" do
639
+ mirror_data = nil
640
+ in_offline_app do
641
+ group_rec = GroupOwnedRecord.new(:description => "Invalid record", :group => @offline_group, :should_be_even => 3)
642
+ group_rec.save_without_validation
643
+ mirror_data = Offroad::MirrorData.new(@offline_group, :skip_validation => true).write_upwards_data
644
+ end
645
+
646
+ in_online_app do
647
+ assert_raise Offroad::DataError do
648
+ Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
649
+ end
650
+ assert_nothing_raised do
651
+ Offroad::MirrorData.new(@offline_group, :skip_validation => true).load_upwards_data(mirror_data)
652
+ end
653
+ end
654
+ end
655
+
656
+ cross_test "cannot import down mirror files with invalid records unless skip_validation is enabled" do
657
+ mirror_data = nil
658
+ in_online_app do
659
+ global_rec = GlobalRecord.new(:title => "Invalid record", :should_be_odd => 2)
660
+ global_rec.save_without_validation
661
+ mirror_data = Offroad::MirrorData.new(@offline_group, :skip_validation => true).write_downwards_data
662
+ end
663
+
664
+ in_offline_app do
665
+ assert_raise Offroad::DataError do
666
+ Offroad::MirrorData.new(@offline_group).load_downwards_data(mirror_data)
667
+ end
668
+ assert_nothing_raised do
669
+ Offroad::MirrorData.new(@offline_group, :skip_validation => true).load_downwards_data(mirror_data)
670
+ end
671
+ end
672
+ end
673
+
674
+ cross_test "cannot import initial down mirror files with invalid records unless skip_validation is enabled" do
675
+ mirror_data = nil
676
+ in_online_app do
677
+ group_rec = GroupOwnedRecord.new(:description => "Invalid record", :group => @online_group, :should_be_even => 3)
678
+ group_rec.save_without_validation
679
+ @online_group.group_offline = true
680
+ writer = Offroad::MirrorData.new(@online_group, :skip_validation => true, :initial_mode => true)
681
+ mirror_data = writer.write_downwards_data
682
+ end
683
+
684
+ in_offline_app(false, true) do
685
+ assert_raise Offroad::DataError do
686
+ Offroad::MirrorData.new(nil, :initial_mode => true).load_downwards_data(mirror_data)
687
+ end
688
+ assert_nothing_raised do
689
+ Offroad::MirrorData.new(nil, :initial_mode => true, :skip_validation => true).load_downwards_data(mirror_data)
690
+ end
691
+ end
692
+ end
693
+
694
+ cross_test "foreign keys are transformed correctly on up mirror" do
695
+ in_online_app do
696
+ # Perturb the autoincrement a bit
697
+ GroupOwnedRecord.create(:description => "Alice", :group => @online_group)
698
+ GroupOwnedRecord.create(:description => "Bob", :group => @online_group)
699
+ end
700
+
701
+ mirror_data = nil
702
+ in_offline_app do
703
+ parent = GroupOwnedRecord.create(:description => "Celia", :group => @offline_group)
704
+ child_a = GroupOwnedRecord.create(:description => "Daniel", :parent => parent, :group => @offline_group)
705
+ child_b = GroupOwnedRecord.create(:description => "Eric", :parent => parent, :group => @offline_group)
706
+ grandchild = GroupOwnedRecord.create(:description => "Fran", :parent => child_b, :group => @offline_group)
707
+ time_traveler = GroupOwnedRecord.create(:description => "Philip J. Fry", :group => @offline_group)
708
+ time_traveler.parent = time_traveler
709
+ time_traveler.save!
710
+ @offline_group.favorite = grandchild
711
+ @offline_group.save!
712
+ @offline_group_data.parent = grandchild
713
+ @offline_group_data.save!
714
+ mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
715
+ end
716
+
717
+ in_online_app do
718
+ Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
719
+ assert_record_states_all_valid
720
+
721
+ @offline_group.reload
722
+ @offline_group_data.reload
723
+ parent = GroupOwnedRecord.find_by_description("Celia")
724
+ child_a = GroupOwnedRecord.find_by_description("Daniel")
725
+ child_b = GroupOwnedRecord.find_by_description("Eric")
726
+ grandchild = GroupOwnedRecord.find_by_description("Fran")
727
+ time_traveler = GroupOwnedRecord.find_by_description("Philip J. Fry")
728
+
729
+ assert_equal parent, child_a.parent
730
+ assert_equal parent, child_b.parent
731
+ assert_equal child_b, grandchild.parent
732
+ assert_equal grandchild, child_b.children.first
733
+ assert_equal grandchild, @offline_group.favorite
734
+ assert_equal @offline_group_data, grandchild.children.first
735
+ assert_equal grandchild, @offline_group_data.parent
736
+ assert_equal time_traveler, time_traveler.parent
737
+ end
738
+ end
739
+
740
+ cross_test "foreign keys are transformed correctly on down mirror" do
741
+ mirror_data = nil
742
+ in_online_app do
743
+ alice = GlobalRecord.create(:title => "Alice")
744
+ alice.friend = alice
745
+ alice.save!
746
+ bob = GlobalRecord.create(:title => "Bob", :friend => alice)
747
+ claire = GlobalRecord.create(:title => "Claire", :friend => bob)
748
+ mirror_data = Offroad::MirrorData.new(@offline_group).write_downwards_data
749
+ end
750
+
751
+ in_offline_app do
752
+ Offroad::MirrorData.new(@offline_group).load_downwards_data(mirror_data)
753
+ assert_record_states_all_valid
754
+ alice = GlobalRecord.find_by_title("Alice")
755
+ bob = GlobalRecord.find_by_title("Bob")
756
+ claire = GlobalRecord.find_by_title("Claire")
757
+ assert_equal alice, alice.friend
758
+ assert_equal alice, bob.friend
759
+ assert_equal bob, claire.friend
760
+ end
761
+ end
762
+
763
+ cross_test "loading up mirror file loads group state information" do
764
+ in_online_app do
765
+ assert_equal "Unknown", @offline_group.group_state.operating_system
766
+ end
767
+
768
+ mirror_data = nil
769
+ offline_os = ""
770
+ in_offline_app do
771
+ mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
772
+ offline_os = @offline_group.group_state.operating_system
773
+ end
774
+
775
+ in_online_app do
776
+ Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
777
+ assert_equal offline_os, @offline_group.group_state.operating_system
778
+ end
779
+ end
780
+
781
+ offline_test "creating up mirror file increments current_mirror_version" do
782
+ prior_version = Offroad::SystemState::current_mirror_version
783
+ Offroad::MirrorData.new(@offline_group).write_upwards_data
784
+ assert_equal prior_version+1, Offroad::SystemState::current_mirror_version
785
+ end
786
+
787
+ online_test "creating down mirror file increments current_mirror_version" do
788
+ prior_version = Offroad::SystemState::current_mirror_version
789
+ Offroad::MirrorData.new(@offline_group).write_downwards_data
790
+ assert_equal prior_version+1, Offroad::SystemState::current_mirror_version
791
+ end
792
+
793
+ online_test "creating initial down mirror file increments current_mirror_version" do
794
+ prior_version = Offroad::SystemState::current_mirror_version
795
+ Offroad::MirrorData.new(@offline_group, :initial_mode => true).write_downwards_data
796
+ assert_equal prior_version+1, Offroad::SystemState::current_mirror_version
797
+ end
798
+
799
+ cross_test "receiving an up mirror file increments confirmed_group_data_version to the indicated value if larger" do
800
+ mirror_data = nil
801
+ in_offline_app do
802
+ @offline_group_data.description = "New Name"
803
+ @offline_group_data.save!
804
+
805
+ Offroad::SystemState::instance_record.update_attribute(:current_mirror_version, 42)
806
+
807
+ mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
808
+ end
809
+
810
+ in_online_app do
811
+ assert_equal 1, @offline_group.group_state.confirmed_group_data_version
812
+ Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
813
+ assert_equal 42, @offline_group.group_state.confirmed_group_data_version
814
+ end
815
+ end
816
+
817
+ cross_test "received up mirror files are rejected if their version is equal to or lower than current version" do
818
+ [42, 41].each do |sending_version|
819
+ mirror_data = nil
820
+ in_offline_app(true) do
821
+ @offline_group_data.description = "New Name"
822
+ @offline_group_data.save!
823
+
824
+ Offroad::SystemState::instance_record.update_attribute(:current_mirror_version, sending_version)
825
+
826
+ mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
827
+ end
828
+
829
+ in_online_app do
830
+ group_state = @offline_group.group_state
831
+ group_state.confirmed_group_data_version = 42
832
+ group_state.save!
833
+
834
+ assert_raise Offroad::OldDataError do
835
+ Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
836
+ end
837
+ end
838
+ end
839
+ end
840
+
841
+ cross_test "receiving a down mirror file increments confirmed_global_data_version to the indicated value if larger" do
842
+ mirror_data = nil
843
+ in_online_app do
844
+ GlobalRecord.create(:title => "Testing")
845
+
846
+ Offroad::SystemState::instance_record.update_attribute(:current_mirror_version, 42)
847
+
848
+ mirror_data = Offroad::MirrorData.new(@offline_group).write_downwards_data
849
+ end
850
+
851
+ in_offline_app do
852
+ assert_equal 1, @offline_group.group_state.confirmed_global_data_version
853
+ Offroad::MirrorData.new(@offline_group).load_downwards_data(mirror_data)
854
+ assert_equal 42, @offline_group.group_state.confirmed_global_data_version
855
+ end
856
+ end
857
+
858
+ cross_test "received down mirror files are rejected if their version is equal to or lower than current version" do
859
+ [42, 41].each do |sending_version|
860
+ mirror_data = nil
861
+ in_online_app do
862
+ GlobalRecord.create(:title => "Testing")
863
+
864
+ Offroad::SystemState::instance_record.update_attribute(:current_mirror_version, sending_version)
865
+
866
+ mirror_data = Offroad::MirrorData.new(@offline_group).write_downwards_data
867
+ end
868
+
869
+ in_offline_app do
870
+ group_state = @offline_group.group_state
871
+ group_state.confirmed_global_data_version = 42
872
+ group_state.save!
873
+
874
+ assert_raise Offroad::OldDataError do
875
+ Offroad::MirrorData.new(@offline_group).load_downwards_data(mirror_data)
876
+ end
877
+ end
878
+ end
879
+ end
880
+
881
+ cross_test "after loading initial down mirror file global_data_version matches online prior current_mirror_version" do
882
+ mirror_data = nil
883
+ online_version = nil
884
+ in_online_app do
885
+ Offroad::SystemState::instance_record.update_attribute(:current_mirror_version, 3)
886
+ online_version = Offroad::SystemState::current_mirror_version
887
+ mirror_data = Offroad::MirrorData.new(@offline_group, :initial_mode => true).write_downwards_data
888
+ end
889
+
890
+ in_offline_app(false, true) do
891
+ Offroad::MirrorData.new(nil, :initial_mode => true).load_downwards_data(mirror_data)
892
+ assert_equal online_version, @offline_group.group_state.confirmed_global_data_version
893
+ end
894
+ end
895
+
896
+ cross_test "down mirror files do not include records which offline is known to already have the latest version of" do
897
+ mirror_data = nil
898
+ in_online_app do
899
+ GlobalRecord.create!(:title => "Record A", :some_boolean => false)
900
+ GlobalRecord.create!(:title => "Record B", :some_boolean => false)
901
+ mirror_data = Offroad::MirrorData.new(@offline_group).write_downwards_data
902
+ end
903
+
904
+ in_offline_app do
905
+ Offroad::MirrorData.new(@offline_group).load_downwards_data(mirror_data)
906
+ mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
907
+ end
908
+
909
+ in_online_app do
910
+ Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
911
+ rec_a = GlobalRecord.find_by_title("Record A")
912
+ rec_a.some_boolean = true
913
+ rec_a.save!
914
+ mirror_data = Offroad::MirrorData.new(@offline_group).write_downwards_data
915
+ end
916
+
917
+ cs = Offroad::CargoStreamer.new(mirror_data, "r")
918
+ recs = []
919
+ cs.each_cargo_section(Offroad::MirrorData.send(:data_cargo_name_for_model, GlobalRecord)) do |batch|
920
+ recs += batch
921
+ end
922
+ assert_equal 1, recs.size
923
+ assert_equal "Record A", recs[0].title
924
+ assert_equal true, recs[0].some_boolean
925
+ end
926
+
927
+ cross_test "up mirror files do not include records which online is known to already have the latest version of" do
928
+ mirror_data = nil
929
+ in_offline_app do
930
+ GroupOwnedRecord.create!(:description => "Another Record", :group => @offline_group)
931
+ @offline_group_data.description = "Changed"
932
+ @offline_group_data.save!
933
+ mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
934
+ end
935
+
936
+ in_online_app do
937
+ Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
938
+ mirror_data = Offroad::MirrorData.new(@offline_group).write_downwards_data
939
+ end
940
+
941
+ in_offline_app do
942
+ Offroad::MirrorData.new(@offline_group).load_downwards_data(mirror_data)
943
+ @offline_group_data.description = "Changed Again"
944
+ @offline_group_data.save!
945
+ mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
946
+ end
947
+
948
+ cs = Offroad::CargoStreamer.new(mirror_data, "r")
949
+ recs = []
950
+ cs.each_cargo_section(Offroad::MirrorData.send(:data_cargo_name_for_model, GroupOwnedRecord)) do |batch|
951
+ recs += batch
952
+ end
953
+ assert_equal 1, recs.size
954
+ assert_equal "Changed Again", recs[0].description
955
+ end
956
+
957
+ offline_test "changed records are re-included in new up mirror files if their reception is not confirmed" do
958
+ @offline_group_data.description = "Changed"
959
+ @offline_group_data.save!
960
+
961
+ 2.times do
962
+ cs = Offroad::CargoStreamer.new(Offroad::MirrorData.new(@offline_group).write_upwards_data, "r")
963
+ assert_single_model_cargo_entry_matches(cs, @offline_group_data)
964
+ end
965
+ end
966
+
967
+ online_test "changed records are re-included in new down mirror files if their reception is not confirmed" do
968
+ global_rec = GlobalRecord.create(:title => "Testing")
969
+
970
+ 2.times do
971
+ cs = Offroad::CargoStreamer.new(Offroad::MirrorData.new(@offline_group).write_downwards_data, "r")
972
+ assert_single_model_cargo_entry_matches(cs, global_rec)
973
+ end
974
+ end
975
+
976
+ cross_test "up mirror files do not include deletion requests for records known to be deleted on online system" do
977
+ sec_name = Offroad::MirrorData.send(:deletion_cargo_name_for_model, GroupOwnedRecord)
978
+
979
+ mirror_data = nil
980
+ in_offline_app do
981
+ @offline_group_data.destroy
982
+ mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
983
+ end
984
+
985
+ assert_equal 1, all_records_from_section_named(Offroad::CargoStreamer.new(mirror_data, "r"), sec_name).size
986
+
987
+ in_online_app do
988
+ Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
989
+ mirror_data = Offroad::MirrorData.new(@offline_group).write_downwards_data
990
+ end
991
+
992
+ in_offline_app do
993
+ Offroad::MirrorData.new(@offline_group).load_downwards_data(mirror_data)
994
+ mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
995
+ end
996
+
997
+ assert_equal 0, all_records_from_section_named(Offroad::CargoStreamer.new(mirror_data, "r"), sec_name).size
998
+ end
999
+
1000
+ cross_test "down mirror files do not include deletion requests for records known to be deleted on offline system" do
1001
+ sec_name = Offroad::MirrorData.send(:deletion_cargo_name_for_model, GlobalRecord)
1002
+
1003
+ mirror_data = nil
1004
+ in_online_app do
1005
+ GlobalRecord.create(:title => "Testing")
1006
+ mirror_data = Offroad::MirrorData.new(@offline_group).write_downwards_data
1007
+ end
1008
+
1009
+ in_offline_app do
1010
+ Offroad::MirrorData.new(@offline_group).load_downwards_data(mirror_data)
1011
+ mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
1012
+ end
1013
+
1014
+ in_online_app do
1015
+ Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
1016
+ GlobalRecord.find_by_title("Testing").destroy
1017
+ mirror_data = Offroad::MirrorData.new(@offline_group).write_downwards_data
1018
+ end
1019
+
1020
+ assert_equal 1, all_records_from_section_named(Offroad::CargoStreamer.new(mirror_data, "r"), sec_name).size
1021
+
1022
+ in_offline_app do
1023
+ Offroad::MirrorData.new(@offline_group).load_downwards_data(mirror_data)
1024
+ mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
1025
+ end
1026
+
1027
+ in_online_app do
1028
+ Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
1029
+ mirror_data = Offroad::MirrorData.new(@offline_group).write_downwards_data
1030
+ end
1031
+
1032
+ assert_equal 0, all_records_from_section_named(Offroad::CargoStreamer.new(mirror_data, "r"), sec_name).size
1033
+ end
1034
+
1035
+ offline_test "deletions are re-included in new up mirror files if their reception is not confirmed" do
1036
+ sec_name = Offroad::MirrorData.send(:deletion_cargo_name_for_model, GroupOwnedRecord)
1037
+ @offline_group_data.destroy
1038
+
1039
+ 2.times do
1040
+ cs = Offroad::CargoStreamer.new(Offroad::MirrorData.new(@offline_group).write_upwards_data, "r")
1041
+ assert_equal 1, all_records_from_section_named(cs, sec_name).size
1042
+ end
1043
+ end
1044
+
1045
+ cross_test "deletions are re-included in new down mirror files if their reception is not confirmed" do
1046
+ mirror_data = nil
1047
+ in_online_app do
1048
+ global_rec = GlobalRecord.create(:title => "Testing")
1049
+ mirror_data = Offroad::MirrorData.new(@offline_group).write_downwards_data
1050
+ end
1051
+
1052
+ in_offline_app do
1053
+ Offroad::MirrorData.new(@offline_group).load_downwards_data(mirror_data)
1054
+ mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
1055
+ end
1056
+
1057
+ in_online_app do
1058
+ Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
1059
+
1060
+ GlobalRecord.find_by_title("Testing").destroy
1061
+ sec_name = Offroad::MirrorData.send(:deletion_cargo_name_for_model, GlobalRecord)
1062
+ 2.times do
1063
+ cs = Offroad::CargoStreamer.new(Offroad::MirrorData.new(@offline_group).write_downwards_data, "r")
1064
+ assert_equal 1, all_records_from_section_named(cs, sec_name).size
1065
+ end
1066
+ end
1067
+ end
1068
+
1069
+ online_test "records from other offline groups are not included in initial down mirror files" do
1070
+ another_offline_group = Group.create(:name => "One More Offline Group")
1071
+ data = GroupOwnedRecord.create(:description => "One More Offline Data", :group => another_offline_group)
1072
+ another_offline_group.group_offline = true
1073
+ mirror_data = Offroad::MirrorData.new(@offline_group, :initial_mode => true).write_downwards_data
1074
+ cs = Offroad::CargoStreamer.new(mirror_data, "r")
1075
+ assert_record_not_present(cs, data)
1076
+ end
1077
+
1078
+ cross_test "protected attributes can be updated from up mirror files" do
1079
+ mirror_data = nil
1080
+ in_offline_app do
1081
+ @offline_group_data.protected_integer = 123
1082
+ @offline_group_data.save!
1083
+ mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
1084
+ end
1085
+
1086
+ in_online_app do
1087
+ assert_not_equal 123, @offline_group_data.protected_integer
1088
+ Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
1089
+ @offline_group_data.reload
1090
+ assert_equal 123, @offline_group_data.protected_integer
1091
+ end
1092
+ end
1093
+
1094
+ cross_test "protected attributes can be updated from down mirror files" do
1095
+ mirror_data = nil
1096
+ in_online_app do
1097
+ GlobalRecord.create(:title => "Testing")
1098
+ mirror_data = Offroad::MirrorData.new(@offline_group).write_downwards_data
1099
+ end
1100
+
1101
+ in_offline_app do
1102
+ Offroad::MirrorData.new(@offline_group).load_downwards_data(mirror_data)
1103
+ mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
1104
+ end
1105
+
1106
+ in_online_app do
1107
+ Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
1108
+ grec = GlobalRecord.find_by_title("Testing")
1109
+ grec.protected_integer = 789
1110
+ grec.save!
1111
+ mirror_data = Offroad::MirrorData.new(@offline_group).write_downwards_data
1112
+ end
1113
+
1114
+ in_offline_app do
1115
+ assert_not_equal 789, GlobalRecord.find_by_title("Testing").protected_integer
1116
+ Offroad::MirrorData.new(@offline_group).load_downwards_data(mirror_data)
1117
+ assert_equal 789, GlobalRecord.find_by_title("Testing").protected_integer
1118
+ end
1119
+ end
1120
+
1121
+ cross_test "cannot use an up mirror file to delete the group record itself" do
1122
+ mirror_data = nil
1123
+ in_offline_app do
1124
+ mirror_data = StringIO.open do |sio|
1125
+ cs = Offroad::CargoStreamer.new(sio, "w")
1126
+ Offroad::MirrorData.new(@offline_group).write_upwards_data(cs)
1127
+
1128
+ sec_name = Offroad::MirrorData.send(:deletion_cargo_name_for_model, Group)
1129
+ deletion_srs = Offroad::SendableRecordState.for_record(@offline_group).first
1130
+ deletion_srs.deleted = true
1131
+ cs.write_cargo_section(sec_name, [deletion_srs])
1132
+
1133
+ sec_name = Offroad::MirrorData.send(:deletion_cargo_name_for_model, GroupOwnedRecord)
1134
+ deletion_srs = Offroad::SendableRecordState.for_record(@offline_group_data).first
1135
+ deletion_srs.deleted = true
1136
+ cs.write_cargo_section(sec_name, [deletion_srs])
1137
+
1138
+ sio.string
1139
+ end
1140
+ end
1141
+
1142
+ in_online_app do
1143
+ Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
1144
+ assert_nil GroupOwnedRecord.find_by_description("Sam") # Make sure the deletion faking method actually works...
1145
+ assert_not_nil Group.find_by_name("An Offline Group") # Except on group base records
1146
+ end
1147
+ end
1148
+
1149
+ cross_test "after loading an initial down mirror file only changed records appear in up mirror" do
1150
+ mirror_data = nil
1151
+ in_online_app do
1152
+ mirror_data = Offroad::MirrorData.new(@offline_group, :initial_mode => true).write_downwards_data
1153
+ end
1154
+
1155
+ in_offline_app(false, true) do
1156
+ Offroad::MirrorData.new(nil, :initial_mode => true).load_downwards_data(mirror_data)
1157
+ group = Group.first
1158
+ group.name = "Weird Al"
1159
+ group.save!
1160
+ group.reload
1161
+ mirror_data = Offroad::MirrorData.new(group).write_upwards_data
1162
+ cs = Offroad::CargoStreamer.new(mirror_data, "r")
1163
+ assert_single_model_cargo_entry_matches(cs, group)
1164
+ assert_record_not_present(cs, GroupOwnedRecord.first)
1165
+ end
1166
+ end
1167
+
1168
+ cross_test "cannot affect group records in offline app using a non-initial down mirror file" do
1169
+ mirror_data = nil
1170
+ in_online_app do
1171
+ mirror_data = StringIO.open do |sio|
1172
+ cs = Offroad::CargoStreamer.new(sio, "w")
1173
+ Offroad::MirrorData.new(@offline_group).write_downwards_data(cs)
1174
+
1175
+ grec = GlobalRecord.create(:title => "Testing 123")
1176
+ sec_name = Offroad::MirrorData.send(:data_cargo_name_for_model, GlobalRecord)
1177
+ cs.write_cargo_section(sec_name, [grec])
1178
+
1179
+ sec_name = Offroad::MirrorData.send(:data_cargo_name_for_model, GroupOwnedRecord)
1180
+ new_rec = GroupOwnedRecord.new(:description => "Brand New Thing", :group => @offline_group)
1181
+ new_rec.id = 1234
1182
+ cs.write_cargo_section(sec_name, [new_rec])
1183
+
1184
+ sec_name = Offroad::MirrorData.send(:deletion_cargo_name_for_model, GroupOwnedRecord)
1185
+ deletion_srs = Offroad::SendableRecordState.for_record(@offline_group_data).new
1186
+ deletion_srs.deleted = true
1187
+ cs.write_cargo_section(sec_name, [deletion_srs])
1188
+
1189
+ sio.string
1190
+ end
1191
+ end
1192
+
1193
+ in_offline_app do
1194
+ Offroad::MirrorData.new(@offline_group).load_downwards_data(mirror_data)
1195
+
1196
+ # Make sure the section faking method actually works...
1197
+ assert_not_nil GlobalRecord.find_by_title("Testing 123")
1198
+
1199
+ # Except on group records
1200
+ assert_nil GroupOwnedRecord.find_by_description("Brand New Thing")
1201
+ assert_not_nil GroupOwnedRecord.find_by_description("Sam")
1202
+ end
1203
+ end
1204
+
1205
+ cross_test "can transfer self-referencing records" do
1206
+ mirror_data = nil
1207
+ in_offline_app do
1208
+ # Create a new self-referencing record
1209
+ new_self_ref = GroupOwnedRecord.create(:description => "Phillip J. Fry", :group => @offline_group)
1210
+ new_self_ref.parent = new_self_ref
1211
+ new_self_ref.save!
1212
+ assert_equal new_self_ref.id, new_self_ref.parent.id
1213
+
1214
+ # Alter an existing record to be self-referencing
1215
+ @offline_group_data.parent = @offline_group_data
1216
+ @offline_group_data.save!
1217
+
1218
+ mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
1219
+ end
1220
+
1221
+ in_online_app do
1222
+ Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
1223
+ assert_record_states_all_valid
1224
+
1225
+ fry = GroupOwnedRecord.find_by_description("Phillip J. Fry")
1226
+ assert fry
1227
+ assert_equal fry.id, fry.parent.id
1228
+
1229
+ @offline_group_data.reload
1230
+ assert_equal @offline_group_data.id, @offline_group_data.parent.id
1231
+ end
1232
+ end
1233
+
1234
+ cross_test "when a locked group is loaded by an up mirror, it is brought online" do
1235
+ mirror_data = nil
1236
+ in_offline_app do
1237
+ @offline_group.offroad_group_lock!
1238
+ mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
1239
+ end
1240
+ in_online_app do
1241
+ Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
1242
+ assert @offline_group.group_online?
1243
+ end
1244
+ end
1245
+
1246
+ cross_test "model method after_offroad_upload is called after it is uploaded to initial offline app" do
1247
+ mirror_data = nil
1248
+ in_online_app do
1249
+ mirror_data = Offroad::MirrorData.new(@offline_group, :initial_mode => true).write_downwards_data
1250
+ end
1251
+
1252
+ in_offline_app(false, true) do
1253
+ GroupOwnedRecord.reset_after_upload_count
1254
+ assert_equal 0, GroupOwnedRecord.after_upload_count
1255
+ Offroad::MirrorData.new(nil, :initial_mode => true).load_downwards_data(mirror_data)
1256
+ assert_equal GroupOwnedRecord.count, GroupOwnedRecord.after_upload_count
1257
+ end
1258
+ end
1259
+
1260
+ cross_test "model method after_offroad_upload is called after it is uploaded to online app" do
1261
+ mirror_data = nil
1262
+ in_offline_app do
1263
+ @offline_group_data.description = "The Mystery Spot"
1264
+ @offline_group_data.save!
1265
+ mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
1266
+ end
1267
+ end
1268
+
1269
+ cross_test "model method after_offroad_destroy is called after object destruction propagated to online app" do
1270
+ mirror_data = nil
1271
+ in_offline_app do
1272
+ @offline_group_data.destroy
1273
+ mirror_data = Offroad::MirrorData.new(@offline_group).write_upwards_data
1274
+ end
1275
+
1276
+ in_online_app do
1277
+ GroupOwnedRecord.reset_after_destroy_count
1278
+ assert_equal 0, GroupOwnedRecord.after_destroy_count
1279
+ Offroad::MirrorData.new(@offline_group).load_upwards_data(mirror_data)
1280
+ assert_equal 1, GroupOwnedRecord.after_destroy_count # One record destroyed
1281
+ end
1282
+ end
1283
+ end