offroad 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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