offroad 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. data/LICENSE +674 -0
  2. data/README.rdoc +29 -0
  3. data/Rakefile +75 -0
  4. data/TODO +42 -0
  5. data/lib/app/models/offroad/group_state.rb +85 -0
  6. data/lib/app/models/offroad/mirror_info.rb +53 -0
  7. data/lib/app/models/offroad/model_state.rb +36 -0
  8. data/lib/app/models/offroad/received_record_state.rb +109 -0
  9. data/lib/app/models/offroad/sendable_record_state.rb +91 -0
  10. data/lib/app/models/offroad/system_state.rb +33 -0
  11. data/lib/cargo_streamer.rb +222 -0
  12. data/lib/controller_extensions.rb +74 -0
  13. data/lib/exceptions.rb +16 -0
  14. data/lib/migrate/20100512164608_create_offroad_tables.rb +72 -0
  15. data/lib/mirror_data.rb +354 -0
  16. data/lib/model_extensions.rb +377 -0
  17. data/lib/module_funcs.rb +94 -0
  18. data/lib/offroad.rb +30 -0
  19. data/lib/version.rb +3 -0
  20. data/lib/view_helper.rb +7 -0
  21. data/templates/offline.rb +36 -0
  22. data/templates/offline_database.yml +7 -0
  23. data/templates/offroad.yml +6 -0
  24. data/test/app_root/app/controllers/application_controller.rb +2 -0
  25. data/test/app_root/app/controllers/group_controller.rb +28 -0
  26. data/test/app_root/app/models/global_record.rb +10 -0
  27. data/test/app_root/app/models/group.rb +12 -0
  28. data/test/app_root/app/models/group_owned_record.rb +68 -0
  29. data/test/app_root/app/models/guest.rb +7 -0
  30. data/test/app_root/app/models/subrecord.rb +12 -0
  31. data/test/app_root/app/models/unmirrored_record.rb +4 -0
  32. data/test/app_root/app/views/group/download_down_mirror.html.erb +4 -0
  33. data/test/app_root/app/views/group/download_initial_down_mirror.html.erb +4 -0
  34. data/test/app_root/app/views/group/download_up_mirror.html.erb +6 -0
  35. data/test/app_root/app/views/group/upload_down_mirror.html.erb +1 -0
  36. data/test/app_root/app/views/group/upload_up_mirror.html.erb +1 -0
  37. data/test/app_root/app/views/layouts/mirror.html.erb +9 -0
  38. data/test/app_root/config/boot.rb +115 -0
  39. data/test/app_root/config/database.yml +6 -0
  40. data/test/app_root/config/environment.rb +15 -0
  41. data/test/app_root/config/environments/test.rb +17 -0
  42. data/test/app_root/config/offroad.yml +6 -0
  43. data/test/app_root/config/routes.rb +4 -0
  44. data/test/app_root/db/migrate/20100529235049_create_tables.rb +64 -0
  45. data/test/app_root/lib/common_hobo.rb +15 -0
  46. data/test/app_root/vendor/plugins/offroad/init.rb +2 -0
  47. data/test/functional/mirror_operations_test.rb +148 -0
  48. data/test/test_helper.rb +405 -0
  49. data/test/unit/app_state_tracking_test.rb +275 -0
  50. data/test/unit/cargo_streamer_test.rb +332 -0
  51. data/test/unit/global_data_test.rb +102 -0
  52. data/test/unit/group_controller_test.rb +152 -0
  53. data/test/unit/group_data_test.rb +435 -0
  54. data/test/unit/group_single_test.rb +136 -0
  55. data/test/unit/hobo_permissions_test.rb +57 -0
  56. data/test/unit/mirror_data_test.rb +1271 -0
  57. data/test/unit/mirror_info_test.rb +31 -0
  58. data/test/unit/module_funcs_test.rb +37 -0
  59. data/test/unit/pathological_model_test.rb +62 -0
  60. data/test/unit/test_framework_test.rb +86 -0
  61. data/test/unit/unmirrored_data_test.rb +14 -0
  62. metadata +140 -0
@@ -0,0 +1,7 @@
1
+ if HOBO_TEST_MODE
2
+ class Guest < Hobo::Guest
3
+ def administrator?
4
+ false
5
+ end
6
+ end
7
+ end
@@ -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,4 @@
1
+ class UnmirroredRecord < ActiveRecord::Base
2
+ include CommonHobo if HOBO_TEST_MODE
3
+ validates_presence_of :content
4
+ end
@@ -0,0 +1,4 @@
1
+ <% content_for :title do %>Test App Downloaded Data<% end %>
2
+
3
+ This file contains information downloaded from the Test App online system.<br/>
4
+ Please take it to your offline Test App system and load it there.
@@ -0,0 +1,4 @@
1
+ <% content_for :title do %>Test App Downloaded Data<% end %>
2
+
3
+ This file contains information downloaded from the Test App online system.<br/>
4
+ Please take it to your offline Test App system and load it there.
@@ -0,0 +1,6 @@
1
+ <% content_for :title do %>Test App Data For Upload<% end %>
2
+
3
+ This file contains your data that is to be sent to the Test App online system.<br/>
4
+ Take this file to a computer with Internet access, then go to this website:<br/><br/>
5
+
6
+ <%= link_to_online_app %>
@@ -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,6 @@
1
+ test:
2
+ adapter: sqlite3
3
+ database: ":memory:"
4
+ verbosity: quiet
5
+ pool: 5
6
+ timeout: 5000
@@ -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,4 @@
1
+ ActionController::Routing::Routes.draw do |map|
2
+ map.connect ':controller/:action/:id'
3
+ map.connect ':controller/:action/:id.:format'
4
+ end
@@ -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,2 @@
1
+ # Pretend the offroad gem is a plugin for the test environment
2
+ require "#{File.dirname(__FILE__)}/../../../../../lib/offroad.rb"
@@ -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