offroad 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +674 -0
- data/README.rdoc +29 -0
- data/Rakefile +75 -0
- data/TODO +42 -0
- data/lib/app/models/offroad/group_state.rb +85 -0
- data/lib/app/models/offroad/mirror_info.rb +53 -0
- data/lib/app/models/offroad/model_state.rb +36 -0
- data/lib/app/models/offroad/received_record_state.rb +109 -0
- data/lib/app/models/offroad/sendable_record_state.rb +91 -0
- data/lib/app/models/offroad/system_state.rb +33 -0
- data/lib/cargo_streamer.rb +222 -0
- data/lib/controller_extensions.rb +74 -0
- data/lib/exceptions.rb +16 -0
- data/lib/migrate/20100512164608_create_offroad_tables.rb +72 -0
- data/lib/mirror_data.rb +354 -0
- data/lib/model_extensions.rb +377 -0
- data/lib/module_funcs.rb +94 -0
- data/lib/offroad.rb +30 -0
- data/lib/version.rb +3 -0
- data/lib/view_helper.rb +7 -0
- data/templates/offline.rb +36 -0
- data/templates/offline_database.yml +7 -0
- data/templates/offroad.yml +6 -0
- data/test/app_root/app/controllers/application_controller.rb +2 -0
- data/test/app_root/app/controllers/group_controller.rb +28 -0
- data/test/app_root/app/models/global_record.rb +10 -0
- data/test/app_root/app/models/group.rb +12 -0
- data/test/app_root/app/models/group_owned_record.rb +68 -0
- data/test/app_root/app/models/guest.rb +7 -0
- data/test/app_root/app/models/subrecord.rb +12 -0
- data/test/app_root/app/models/unmirrored_record.rb +4 -0
- data/test/app_root/app/views/group/download_down_mirror.html.erb +4 -0
- data/test/app_root/app/views/group/download_initial_down_mirror.html.erb +4 -0
- data/test/app_root/app/views/group/download_up_mirror.html.erb +6 -0
- data/test/app_root/app/views/group/upload_down_mirror.html.erb +1 -0
- data/test/app_root/app/views/group/upload_up_mirror.html.erb +1 -0
- data/test/app_root/app/views/layouts/mirror.html.erb +9 -0
- data/test/app_root/config/boot.rb +115 -0
- data/test/app_root/config/database.yml +6 -0
- data/test/app_root/config/environment.rb +15 -0
- data/test/app_root/config/environments/test.rb +17 -0
- data/test/app_root/config/offroad.yml +6 -0
- data/test/app_root/config/routes.rb +4 -0
- data/test/app_root/db/migrate/20100529235049_create_tables.rb +64 -0
- data/test/app_root/lib/common_hobo.rb +15 -0
- data/test/app_root/vendor/plugins/offroad/init.rb +2 -0
- data/test/functional/mirror_operations_test.rb +148 -0
- data/test/test_helper.rb +405 -0
- data/test/unit/app_state_tracking_test.rb +275 -0
- data/test/unit/cargo_streamer_test.rb +332 -0
- data/test/unit/global_data_test.rb +102 -0
- data/test/unit/group_controller_test.rb +152 -0
- data/test/unit/group_data_test.rb +435 -0
- data/test/unit/group_single_test.rb +136 -0
- data/test/unit/hobo_permissions_test.rb +57 -0
- data/test/unit/mirror_data_test.rb +1271 -0
- data/test/unit/mirror_info_test.rb +31 -0
- data/test/unit/module_funcs_test.rb +37 -0
- data/test/unit/pathological_model_test.rb +62 -0
- data/test/unit/test_framework_test.rb +86 -0
- data/test/unit/unmirrored_data_test.rb +14 -0
- metadata +140 -0
@@ -0,0 +1,12 @@
|
|
1
|
+
class SubRecord < ActiveRecord::Base
|
2
|
+
include CommonHobo if HOBO_TEST_MODE
|
3
|
+
belongs_to :group_owned_record
|
4
|
+
acts_as_offroadable :group_owned, :parent => :group_owned_record
|
5
|
+
|
6
|
+
belongs_to :buddy, :class_name => "SubRecord"
|
7
|
+
belongs_to :unmirrored_record
|
8
|
+
|
9
|
+
def to_s
|
10
|
+
description
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
Accepted this data from the Test App online system.
|
@@ -0,0 +1 @@
|
|
1
|
+
Accepted this data from the Test App offline system.
|
@@ -0,0 +1,9 @@
|
|
1
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
2
|
+
<html xmlns="http://www.w3.org/1999/xhtml">
|
3
|
+
<head>
|
4
|
+
<title><%= yield :title %></title>
|
5
|
+
</head>
|
6
|
+
<body>
|
7
|
+
<%= yield %>
|
8
|
+
</body>
|
9
|
+
</html>
|
@@ -0,0 +1,115 @@
|
|
1
|
+
# Allow customization of the rails framework path
|
2
|
+
RAILS_FRAMEWORK_ROOT = (ENV['RAILS_FRAMEWORK_ROOT'] || "#{File.dirname(__FILE__)}/../../../../../../vendor/rails") unless defined?(RAILS_FRAMEWORK_ROOT)
|
3
|
+
|
4
|
+
# Don't change this file!
|
5
|
+
# Configure your app in config/environment.rb and config/environments/*.rb
|
6
|
+
|
7
|
+
RAILS_ROOT = "#{File.dirname(__FILE__)}/.." unless defined?(RAILS_ROOT)
|
8
|
+
|
9
|
+
module Rails
|
10
|
+
class << self
|
11
|
+
def boot!
|
12
|
+
unless booted?
|
13
|
+
preinitialize
|
14
|
+
pick_boot.run
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def booted?
|
19
|
+
defined? Rails::Initializer
|
20
|
+
end
|
21
|
+
|
22
|
+
def pick_boot
|
23
|
+
(vendor_rails? ? VendorBoot : GemBoot).new
|
24
|
+
end
|
25
|
+
|
26
|
+
def vendor_rails?
|
27
|
+
File.exist?(RAILS_FRAMEWORK_ROOT)
|
28
|
+
end
|
29
|
+
|
30
|
+
def preinitialize
|
31
|
+
load(preinitializer_path) if File.exist?(preinitializer_path)
|
32
|
+
end
|
33
|
+
|
34
|
+
def preinitializer_path
|
35
|
+
"#{RAILS_ROOT}/config/preinitializer.rb"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class Boot
|
40
|
+
def run
|
41
|
+
load_initializer
|
42
|
+
Rails::Initializer.run(:set_load_path)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class VendorBoot < Boot
|
47
|
+
def load_initializer
|
48
|
+
require "#{RAILS_FRAMEWORK_ROOT}/railties/lib/initializer"
|
49
|
+
Rails::Initializer.run(:install_gem_spec_stubs)
|
50
|
+
Rails::GemDependency.add_frozen_gem_path
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
class GemBoot < Boot
|
55
|
+
def load_initializer
|
56
|
+
self.class.load_rubygems
|
57
|
+
load_rails_gem
|
58
|
+
require 'initializer'
|
59
|
+
end
|
60
|
+
|
61
|
+
def load_rails_gem
|
62
|
+
if version = self.class.gem_version
|
63
|
+
gem 'rails', version
|
64
|
+
else
|
65
|
+
gem 'rails'
|
66
|
+
end
|
67
|
+
rescue Gem::LoadError => load_error
|
68
|
+
$stderr.puts %(Missing the Rails #{version} gem. Please `gem install -v=#{version} rails`, update your RAILS_GEM_VERSION setting in config/environment.rb for the Rails version you do have installed, or comment out RAILS_GEM_VERSION to use the latest version installed.)
|
69
|
+
exit 1
|
70
|
+
end
|
71
|
+
|
72
|
+
class << self
|
73
|
+
def rubygems_version
|
74
|
+
Gem::RubyGemsVersion rescue nil
|
75
|
+
end
|
76
|
+
|
77
|
+
def gem_version
|
78
|
+
if defined? RAILS_GEM_VERSION
|
79
|
+
RAILS_GEM_VERSION
|
80
|
+
elsif ENV.include?('RAILS_GEM_VERSION')
|
81
|
+
ENV['RAILS_GEM_VERSION']
|
82
|
+
else
|
83
|
+
parse_gem_version(read_environment_rb)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def load_rubygems
|
88
|
+
require 'rubygems'
|
89
|
+
min_version = '1.3.1'
|
90
|
+
unless rubygems_version >= min_version
|
91
|
+
$stderr.puts %Q(Rails requires RubyGems >= #{min_version} (you have #{rubygems_version}). Please `gem update --system` and try again.)
|
92
|
+
exit 1
|
93
|
+
end
|
94
|
+
|
95
|
+
rescue LoadError
|
96
|
+
$stderr.puts %Q(Rails requires RubyGems >= #{min_version}. Please install RubyGems and try again: http://rubygems.rubyforge.org)
|
97
|
+
exit 1
|
98
|
+
end
|
99
|
+
|
100
|
+
def parse_gem_version(text)
|
101
|
+
$1 if text =~ /^[^#]*RAILS_GEM_VERSION\s*=\s*["']([!~<>=]*\s*[\d.]+)["']/
|
102
|
+
end
|
103
|
+
|
104
|
+
private
|
105
|
+
def read_environment_rb
|
106
|
+
environment_rb = "#{RAILS_ROOT}/config/environment.rb"
|
107
|
+
environment_rb = "#{HELPER_RAILS_ROOT}/config/environment.rb" unless File.exists?(environment_rb)
|
108
|
+
File.read(environment_rb)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# All that for this:
|
115
|
+
Rails.boot!
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'boot')
|
2
|
+
|
3
|
+
Rails::Initializer.run do |config|
|
4
|
+
config.cache_classes = false
|
5
|
+
config.whiny_nils = true
|
6
|
+
config.action_controller.session = {:key => 'rails_session', :secret => 'd229e4d22437432705ab3985d4d246'}
|
7
|
+
|
8
|
+
if ENV['HOBO_TEST_MODE']
|
9
|
+
puts "Loading Hobo gem"
|
10
|
+
config.gem 'hobo'
|
11
|
+
HOBO_TEST_MODE = true
|
12
|
+
else
|
13
|
+
HOBO_TEST_MODE = false
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
config.cache_classes = true
|
2
|
+
|
3
|
+
# Log error messages when you accidentally call methods on nil.
|
4
|
+
config.whiny_nils = true
|
5
|
+
|
6
|
+
# Show full error reports and disable caching
|
7
|
+
config.action_controller.consider_all_requests_local = true
|
8
|
+
config.action_controller.perform_caching = false
|
9
|
+
config.action_view.cache_template_loading = true
|
10
|
+
|
11
|
+
# Disable request forgery protection in test environment
|
12
|
+
config.action_controller.allow_forgery_protection = false
|
13
|
+
|
14
|
+
# Tell Action Mailer not to deliver emails to the real world.
|
15
|
+
# The :test delivery method accumulates sent emails in the
|
16
|
+
# ActionMailer::Base.deliveries array.
|
17
|
+
config.action_mailer.delivery_method = :test
|
@@ -0,0 +1,6 @@
|
|
1
|
+
# Configuration for Offroad
|
2
|
+
# :online_url: The URL for the regular online version of the app
|
3
|
+
# :app_name: The name of the application, to be used in helpful messages in the generated mirror data files.
|
4
|
+
|
5
|
+
:online_url: "http://example.com"
|
6
|
+
:app_name: Example Application
|
@@ -0,0 +1,64 @@
|
|
1
|
+
class CreateTables < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :groups do |t|
|
4
|
+
t.string :name
|
5
|
+
t.integer :favorite_id
|
6
|
+
t.integer :unmirrored_record_id
|
7
|
+
t.integer :global_record_id
|
8
|
+
t.timestamps
|
9
|
+
end
|
10
|
+
|
11
|
+
create_table :group_owned_records do |t|
|
12
|
+
t.string :description
|
13
|
+
t.integer :some_integer
|
14
|
+
t.integer :should_be_even, :default => 0
|
15
|
+
t.integer :group_id
|
16
|
+
t.integer :parent_id
|
17
|
+
t.integer :unmirrored_record_id
|
18
|
+
t.integer :global_record_id
|
19
|
+
t.integer :protected_integer, :default => 1
|
20
|
+
t.timestamps
|
21
|
+
end
|
22
|
+
|
23
|
+
create_table :sub_records do |t|
|
24
|
+
t.string :description
|
25
|
+
t.integer :group_owned_record_id
|
26
|
+
t.integer :unmirrored_record_id
|
27
|
+
t.integer :buddy_id
|
28
|
+
t.timestamps
|
29
|
+
end
|
30
|
+
|
31
|
+
create_table :group_single_records do |t|
|
32
|
+
t.string :description
|
33
|
+
t.timestamps
|
34
|
+
end
|
35
|
+
|
36
|
+
create_table :global_records do |t|
|
37
|
+
t.string :title
|
38
|
+
t.boolean :some_boolean, :default => false
|
39
|
+
t.integer :should_be_odd, :default => 1
|
40
|
+
t.integer :unmirrored_record_id
|
41
|
+
t.integer :friend_id
|
42
|
+
t.integer :some_group_id
|
43
|
+
t.integer :protected_integer, :default => 1
|
44
|
+
t.timestamps
|
45
|
+
end
|
46
|
+
|
47
|
+
create_table :unmirrored_records do |t|
|
48
|
+
t.string :content
|
49
|
+
t.float :some_float
|
50
|
+
t.timestamps
|
51
|
+
end
|
52
|
+
|
53
|
+
create_table :broken_records do |t|
|
54
|
+
t.integer :group_id
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.down
|
59
|
+
drop_table :groups
|
60
|
+
drop_table :group_owned_records
|
61
|
+
drop_table :unmirrored_records
|
62
|
+
drop_table :broken_records
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module CommonHobo
|
2
|
+
def self.included(base)
|
3
|
+
base.class_eval do
|
4
|
+
hobo_model
|
5
|
+
attr_accessor :permissive
|
6
|
+
include InstanceMethods
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
module InstanceMethods
|
11
|
+
def create_permitted?() @permissive; end
|
12
|
+
def update_permitted?() @permissive; end
|
13
|
+
def destroy_permitted?() @permissive; end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,148 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
|
2
|
+
|
3
|
+
class MirrorOperationsTest < ActionController::TestCase
|
4
|
+
tests GroupController
|
5
|
+
|
6
|
+
cross_test "can create an offline app then use it to work with the online app" do
|
7
|
+
mirror_data = ""
|
8
|
+
in_online_app do
|
9
|
+
Group.create(:name => "Some Other Group")
|
10
|
+
Group.create(:name => "Some Other Offline Group").group_offline = true
|
11
|
+
test_group = Group.create(:name => "Test Group")
|
12
|
+
|
13
|
+
grec_a = GlobalRecord.create(:title => "Important Announcement", :some_boolean => true)
|
14
|
+
GlobalRecord.create(:title => "Trivial Announcement", :some_boolean => true, :friend => grec_a)
|
15
|
+
|
16
|
+
GroupOwnedRecord.create(:description => "First Item", :group => test_group)
|
17
|
+
GroupOwnedRecord.create(:description => "Second Item", :group => test_group)
|
18
|
+
third = GroupOwnedRecord.create(:description => "Third Item", :group => test_group)
|
19
|
+
SubRecord.create(:description => "Subitem A", :group_owned_record => third)
|
20
|
+
SubRecord.create(:description => "Subitem B", :group_owned_record => third)
|
21
|
+
|
22
|
+
test_group.favorite = GroupOwnedRecord.find_by_description("Third Item")
|
23
|
+
test_group.save
|
24
|
+
|
25
|
+
test_group.group_offline = true
|
26
|
+
get :download_initial_down_mirror, "id" => test_group.id
|
27
|
+
mirror_data = @response.binary_content
|
28
|
+
end
|
29
|
+
|
30
|
+
in_offline_app(false, true) do
|
31
|
+
assert_equal 0, Group.count
|
32
|
+
assert_equal 0, GlobalRecord.count
|
33
|
+
assert_equal 0, GroupOwnedRecord.count
|
34
|
+
|
35
|
+
post :upload_initial_down_mirror, "mirror_data" => mirror_data
|
36
|
+
|
37
|
+
assert_equal 1, Group.count
|
38
|
+
test_group = Group.find_by_name("Test Group")
|
39
|
+
assert_not_nil test_group
|
40
|
+
|
41
|
+
assert_equal 3, GroupOwnedRecord.count
|
42
|
+
assert_not_nil GroupOwnedRecord.find_by_description("First Item")
|
43
|
+
assert_not_nil GroupOwnedRecord.find_by_description("Second Item")
|
44
|
+
assert_not_nil GroupOwnedRecord.find_by_description("Third Item")
|
45
|
+
assert_not_nil SubRecord.find_by_description("Subitem A")
|
46
|
+
assert_not_nil SubRecord.find_by_description("Subitem B")
|
47
|
+
|
48
|
+
assert_equal GroupOwnedRecord.find_by_description("Third Item"), test_group.favorite
|
49
|
+
assert_equal GroupOwnedRecord.find_by_description("Third Item"), SubRecord.find_by_description("Subitem A").group_owned_record
|
50
|
+
assert_equal GroupOwnedRecord.find_by_description("Third Item"), SubRecord.find_by_description("Subitem B").group_owned_record
|
51
|
+
|
52
|
+
assert_equal 2, GlobalRecord.count
|
53
|
+
grec_a = GlobalRecord.find_by_title("Important Announcement")
|
54
|
+
grec_b = GlobalRecord.find_by_title("Trivial Announcement")
|
55
|
+
assert_not_nil grec_a
|
56
|
+
assert_not_nil grec_b
|
57
|
+
assert_equal grec_a, grec_b.friend
|
58
|
+
|
59
|
+
group = Group.first
|
60
|
+
group.name = "Renamed Group"
|
61
|
+
group.save!
|
62
|
+
|
63
|
+
first_item = GroupOwnedRecord.find_by_description("First Item")
|
64
|
+
first_item.description = "Absolutely The First Item"
|
65
|
+
first_item.save!
|
66
|
+
|
67
|
+
second_item = GroupOwnedRecord.find_by_description("Second Item")
|
68
|
+
second_item.destroy
|
69
|
+
|
70
|
+
subitem_a = SubRecord.find_by_description("Subitem A")
|
71
|
+
subitem_a.description = "Subitem Apple"
|
72
|
+
subitem_a.save!
|
73
|
+
|
74
|
+
subitem_b = SubRecord.find_by_description("Subitem B")
|
75
|
+
subitem_b.destroy
|
76
|
+
|
77
|
+
get :download_up_mirror, "id" => group.id
|
78
|
+
mirror_data = @response.binary_content
|
79
|
+
end
|
80
|
+
|
81
|
+
in_online_app do
|
82
|
+
GlobalRecord.find_by_title("Trivial Announcement").destroy
|
83
|
+
GlobalRecord.create(:title => "Yet Another Announcement")
|
84
|
+
rec = GlobalRecord.find_by_title("Important Announcement")
|
85
|
+
rec.title = "Very Important Announcement"
|
86
|
+
rec.save
|
87
|
+
|
88
|
+
assert_equal 3, Group.find_by_name("Test Group").group_owned_records.size
|
89
|
+
|
90
|
+
post :upload_up_mirror, "id" => Group.find_by_name("Test Group").id, "mirror_data" => mirror_data
|
91
|
+
|
92
|
+
assert_nil Group.find_by_name("Test Group")
|
93
|
+
assert_not_nil Group.find_by_name("Renamed Group")
|
94
|
+
|
95
|
+
assert_equal 2, Group.find_by_name("Renamed Group").group_owned_records.size
|
96
|
+
assert_nil GroupOwnedRecord.find_by_description("First Item")
|
97
|
+
assert_not_nil GroupOwnedRecord.find_by_description("Absolutely The First Item")
|
98
|
+
assert_nil GroupOwnedRecord.find_by_description("Second Item")
|
99
|
+
assert_not_nil GroupOwnedRecord.find_by_description("Third Item")
|
100
|
+
assert_nil SubRecord.find_by_description("Subitem A")
|
101
|
+
assert_not_nil SubRecord.find_by_description("Subitem Apple")
|
102
|
+
assert_nil SubRecord.find_by_description("Subitem B")
|
103
|
+
|
104
|
+
get :download_down_mirror, "id" => Group.find_by_name("Renamed Group").id
|
105
|
+
mirror_data = @response.binary_content
|
106
|
+
end
|
107
|
+
|
108
|
+
in_offline_app do
|
109
|
+
post :upload_down_mirror, "id" => Group.first.id, "mirror_data" => mirror_data
|
110
|
+
|
111
|
+
assert_equal 2, GlobalRecord.count
|
112
|
+
assert_nil GlobalRecord.find_by_title("Important Announcement")
|
113
|
+
assert_not_nil GlobalRecord.find_by_title("Very Important Announcement")
|
114
|
+
assert_nil GlobalRecord.find_by_title("Trivial Announcement")
|
115
|
+
assert_not_nil GlobalRecord.find_by_title("Yet Another Announcement")
|
116
|
+
|
117
|
+
group = Group.first
|
118
|
+
first_item = GroupOwnedRecord.find_by_description("Absolutely The First Item")
|
119
|
+
third_item = GroupOwnedRecord.find_by_description("Third Item")
|
120
|
+
group.favorite = first_item
|
121
|
+
group.save
|
122
|
+
first_item.parent = third_item
|
123
|
+
first_item.save
|
124
|
+
third_item.parent = third_item
|
125
|
+
third_item.save
|
126
|
+
|
127
|
+
subitem = SubRecord.find_by_description("Subitem Apple")
|
128
|
+
subitem.group_owned_record = first_item
|
129
|
+
subitem.save
|
130
|
+
|
131
|
+
get :download_up_mirror, "id" => Group.first.id
|
132
|
+
mirror_data = @response.binary_content
|
133
|
+
end
|
134
|
+
|
135
|
+
in_online_app do
|
136
|
+
post :upload_up_mirror, "id" => Group.find_by_name("Renamed Group").id, "mirror_data" => mirror_data
|
137
|
+
|
138
|
+
group = Group.find_by_name("Renamed Group")
|
139
|
+
first_item = GroupOwnedRecord.find_by_description("Absolutely The First Item")
|
140
|
+
third_item = GroupOwnedRecord.find_by_description("Third Item")
|
141
|
+
subrec = SubRecord.find_by_description("Subitem Apple")
|
142
|
+
assert_equal first_item, group.favorite
|
143
|
+
assert_equal third_item, first_item.parent
|
144
|
+
assert_equal third_item, third_item.parent
|
145
|
+
assert_equal first_item, subrec.group_owned_record
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|