rhosync 2.0.0.beta1
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/CHANGELOG +5 -0
- data/LICENSE +674 -0
- data/README.md +26 -0
- data/Rakefile +109 -0
- data/bench/bench +6 -0
- data/bench/benchapp/Rakefile +14 -0
- data/bench/benchapp/application.rb +13 -0
- data/bench/benchapp/config.ru +32 -0
- data/bench/benchapp/settings/license.key +1 -0
- data/bench/benchapp/settings/settings.yml +18 -0
- data/bench/benchapp/sources/mock_adapter.rb +55 -0
- data/bench/benchapp/sources/queue_mock_adapter.rb +2 -0
- data/bench/benchapp/vendor/rhosync/lib/rhosync.rb +7 -0
- data/bench/lib/bench/cli.rb +16 -0
- data/bench/lib/bench/logging.rb +18 -0
- data/bench/lib/bench/mock_client.rb +41 -0
- data/bench/lib/bench/result.rb +50 -0
- data/bench/lib/bench/runner.rb +44 -0
- data/bench/lib/bench/session.rb +65 -0
- data/bench/lib/bench/statistics.rb +56 -0
- data/bench/lib/bench/test_data.rb +55 -0
- data/bench/lib/bench/timer.rb +10 -0
- data/bench/lib/bench/utils.rb +49 -0
- data/bench/lib/bench.rb +128 -0
- data/bench/lib/testdata/100-data.txt +148 -0
- data/bench/lib/testdata/5-data.txt +11 -0
- data/bench/scripts/cud_script.rb +77 -0
- data/bench/scripts/helpers.rb +101 -0
- data/bench/scripts/query_md_script.rb +46 -0
- data/bench/scripts/query_script.rb +46 -0
- data/bench/spec/bench_spec_helper.rb +65 -0
- data/bench/spec/logging_spec.rb +19 -0
- data/bench/spec/mock_adapter_spec.rb +61 -0
- data/bench/spec/mock_client_spec.rb +64 -0
- data/bench/spec/result_spec.rb +59 -0
- data/bench/spec/utils_spec.rb +35 -0
- data/bin/rhosync +34 -0
- data/doc/protocol.html +1901 -0
- data/doc/public/css/print.css +29 -0
- data/doc/public/css/screen.css +257 -0
- data/doc/public/css/style.css +20 -0
- data/examples/simple/application.rb +13 -0
- data/examples/simple/sources/sample_adapter.rb +5 -0
- data/examples/simple/sources/simple_adapter.rb +5 -0
- data/examples/simple/vendor/rhosync/lib/rhosync.rb +7 -0
- data/generators/rhosync.rb +98 -0
- data/generators/templates/application/Rakefile +19 -0
- data/generators/templates/application/application.rb +27 -0
- data/generators/templates/application/config.ru +33 -0
- data/generators/templates/application/settings/license.key +1 -0
- data/generators/templates/application/settings/settings.yml +14 -0
- data/generators/templates/source/source_adapter.rb +49 -0
- data/lib/rhosync/api/create_client.rb +3 -0
- data/lib/rhosync/api/create_user.rb +7 -0
- data/lib/rhosync/api/delete_client.rb +5 -0
- data/lib/rhosync/api/delete_user.rb +5 -0
- data/lib/rhosync/api/get_api_token.rb +7 -0
- data/lib/rhosync/api/get_client_params.rb +3 -0
- data/lib/rhosync/api/get_db_doc.rb +7 -0
- data/lib/rhosync/api/get_license_info.rb +7 -0
- data/lib/rhosync/api/get_source_params.rb +3 -0
- data/lib/rhosync/api/list_client_docs.rb +12 -0
- data/lib/rhosync/api/list_clients.rb +3 -0
- data/lib/rhosync/api/list_source_docs.rb +10 -0
- data/lib/rhosync/api/list_sources.rb +15 -0
- data/lib/rhosync/api/list_users.rb +3 -0
- data/lib/rhosync/api/ping.rb +7 -0
- data/lib/rhosync/api/push_deletes.rb +6 -0
- data/lib/rhosync/api/push_objects.rb +6 -0
- data/lib/rhosync/api/reset.rb +10 -0
- data/lib/rhosync/api/set_db_doc.rb +8 -0
- data/lib/rhosync/api/set_refresh_time.rb +8 -0
- data/lib/rhosync/api/update_user.rb +4 -0
- data/lib/rhosync/api/upload_file.rb +4 -0
- data/lib/rhosync/api_token.rb +19 -0
- data/lib/rhosync/app.rb +69 -0
- data/lib/rhosync/bulk_data/bulk_data.rb +75 -0
- data/lib/rhosync/bulk_data/syncdb.index.schema +3 -0
- data/lib/rhosync/bulk_data/syncdb.schema +37 -0
- data/lib/rhosync/bulk_data.rb +2 -0
- data/lib/rhosync/client.rb +74 -0
- data/lib/rhosync/client_sync.rb +296 -0
- data/lib/rhosync/console/app/helpers/auth_helper.rb +18 -0
- data/lib/rhosync/console/app/helpers/extensions.rb +19 -0
- data/lib/rhosync/console/app/helpers/helpers.rb +52 -0
- data/lib/rhosync/console/app/public/main.css +7 -0
- data/lib/rhosync/console/app/public/text.txt +0 -0
- data/lib/rhosync/console/app/routes/auth.rb +29 -0
- data/lib/rhosync/console/app/routes/client.rb +32 -0
- data/lib/rhosync/console/app/routes/docs.rb +84 -0
- data/lib/rhosync/console/app/routes/home.rb +22 -0
- data/lib/rhosync/console/app/routes/user.rb +63 -0
- data/lib/rhosync/console/app/views/client.erb +30 -0
- data/lib/rhosync/console/app/views/doc.erb +56 -0
- data/lib/rhosync/console/app/views/docs.erb +29 -0
- data/lib/rhosync/console/app/views/index.erb +50 -0
- data/lib/rhosync/console/app/views/layout.erb +12 -0
- data/lib/rhosync/console/app/views/newuser.erb +17 -0
- data/lib/rhosync/console/app/views/ping.erb +28 -0
- data/lib/rhosync/console/app/views/result.erb +11 -0
- data/lib/rhosync/console/app/views/user.erb +32 -0
- data/lib/rhosync/console/app/views/users.erb +14 -0
- data/lib/rhosync/console/rhosync_api.rb +102 -0
- data/lib/rhosync/console/server.rb +27 -0
- data/lib/rhosync/credential.rb +9 -0
- data/lib/rhosync/document.rb +43 -0
- data/lib/rhosync/indifferent_access.rb +132 -0
- data/lib/rhosync/jobs/bulk_data_job.rb +104 -0
- data/lib/rhosync/jobs/ping_job.rb +19 -0
- data/lib/rhosync/jobs/source_job.rb +16 -0
- data/lib/rhosync/license.rb +79 -0
- data/lib/rhosync/lock_ops.rb +11 -0
- data/lib/rhosync/model.rb +410 -0
- data/lib/rhosync/ping/blackberry.rb +55 -0
- data/lib/rhosync/ping/iphone.rb +44 -0
- data/lib/rhosync/ping.rb +2 -0
- data/lib/rhosync/read_state.rb +27 -0
- data/lib/rhosync/server/views/index.erb +12 -0
- data/lib/rhosync/server.rb +242 -0
- data/lib/rhosync/source.rb +112 -0
- data/lib/rhosync/source_adapter.rb +95 -0
- data/lib/rhosync/source_sync.rb +245 -0
- data/lib/rhosync/store.rb +199 -0
- data/lib/rhosync/tasks.rb +151 -0
- data/lib/rhosync/user.rb +83 -0
- data/lib/rhosync/version.rb +3 -0
- data/lib/rhosync.rb +251 -0
- data/spec/api/api_helper.rb +44 -0
- data/spec/api/create_client_spec.rb +13 -0
- data/spec/api/create_user_spec.rb +16 -0
- data/spec/api/delete_client_spec.rb +13 -0
- data/spec/api/delete_user_spec.rb +18 -0
- data/spec/api/get_api_token_spec.rb +25 -0
- data/spec/api/get_client_params_spec.rb +18 -0
- data/spec/api/get_db_doc_spec.rb +21 -0
- data/spec/api/get_license_info_spec.rb +16 -0
- data/spec/api/get_source_params_spec.rb +26 -0
- data/spec/api/list_client_docs_spec.rb +33 -0
- data/spec/api/list_clients_spec.rb +23 -0
- data/spec/api/list_source_docs_spec.rb +26 -0
- data/spec/api/list_sources_spec.rb +27 -0
- data/spec/api/list_users_spec.rb +21 -0
- data/spec/api/ping_spec.rb +24 -0
- data/spec/api/push_deletes_spec.rb +16 -0
- data/spec/api/push_objects_spec.rb +27 -0
- data/spec/api/reset_spec.rb +22 -0
- data/spec/api/set_db_doc_spec.rb +20 -0
- data/spec/api/set_refresh_time_spec.rb +43 -0
- data/spec/api/update_user_spec.rb +31 -0
- data/spec/api/upload_file_spec.rb +26 -0
- data/spec/api_token_spec.rb +13 -0
- data/spec/app_spec.rb +20 -0
- data/spec/apps/rhotestapp/Rakefile +1 -0
- data/spec/apps/rhotestapp/application.rb +16 -0
- data/spec/apps/rhotestapp/config.ru +1 -0
- data/spec/apps/rhotestapp/settings/apple_fake_cert.pem +1 -0
- data/spec/apps/rhotestapp/settings/license.key +1 -0
- data/spec/apps/rhotestapp/settings/settings.yml +23 -0
- data/spec/apps/rhotestapp/sources/base_adapter.rb +9 -0
- data/spec/apps/rhotestapp/sources/sample_adapter.rb +66 -0
- data/spec/apps/rhotestapp/sources/simple_adapter.rb +39 -0
- data/spec/apps/rhotestapp/sources/sub_adapter.rb +7 -0
- data/spec/apps/rhotestapp/vendor/mygem-0.1.0/lib/mygem/mygem.rb +8 -0
- data/spec/apps/rhotestapp/vendor/mygem-0.1.0/lib/mygem.rb +1 -0
- data/spec/bulk_data/bulk_data_spec.rb +79 -0
- data/spec/client_spec.rb +58 -0
- data/spec/client_sync_spec.rb +377 -0
- data/spec/doc/base.html +72 -0
- data/spec/doc/doc_spec.rb +303 -0
- data/spec/doc/footer.html +4 -0
- data/spec/doc/header.html +30 -0
- data/spec/document_spec.rb +27 -0
- data/spec/generator/generator_spec.rb +53 -0
- data/spec/generator/generator_spec_helper.rb +8 -0
- data/spec/jobs/bulk_data_job_spec.rb +76 -0
- data/spec/jobs/ping_job_spec.rb +26 -0
- data/spec/jobs/source_job_spec.rb +25 -0
- data/spec/license_spec.rb +48 -0
- data/spec/model_spec.rb +269 -0
- data/spec/perf/bulk_data_perf_spec.rb +33 -0
- data/spec/perf/perf_spec_helper.rb +51 -0
- data/spec/perf/store_perf_spec.rb +28 -0
- data/spec/ping/blackberry_spec.rb +62 -0
- data/spec/ping/iphone_spec.rb +50 -0
- data/spec/read_state_spec.rb +25 -0
- data/spec/rhosync_spec.rb +43 -0
- data/spec/server/server_spec.rb +341 -0
- data/spec/source_adapter_spec.rb +114 -0
- data/spec/source_spec.rb +77 -0
- data/spec/source_sync_spec.rb +248 -0
- data/spec/spec_helper.rb +240 -0
- data/spec/store_spec.rb +149 -0
- data/spec/sync_states_spec.rb +101 -0
- data/spec/testdata/1000-data.txt +1414 -0
- data/spec/testdata/compressed/compress-data.txt +1 -0
- data/spec/testdata/upload1.txt +1 -0
- data/spec/testdata/upload2.txt +1 -0
- data/spec/user_spec.rb +79 -0
- data/tasks/redis.rake +134 -0
- metadata +545 -0
data/spec/model_spec.rb
ADDED
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
# Taken from http://github.com/voloko/redis-model
|
|
2
|
+
require File.join(File.dirname(__FILE__),'spec_helper')
|
|
3
|
+
|
|
4
|
+
describe Rhosync::Model do
|
|
5
|
+
|
|
6
|
+
context "DSL" do
|
|
7
|
+
class TestDSL < Rhosync::Model
|
|
8
|
+
field :foo
|
|
9
|
+
list :bar
|
|
10
|
+
set :sloppy
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
before(:each) do
|
|
14
|
+
@x = TestDSL.with_key(1)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "should define rw accessors for field" do
|
|
18
|
+
@x.should respond_to(:foo)
|
|
19
|
+
@x.should respond_to(:foo=)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it "should define r accessor for list" do
|
|
23
|
+
@x.should respond_to(:bar)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it "should define r accessor for set" do
|
|
27
|
+
@x.should respond_to(:sloppy)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it "should raise error on invalid type" do
|
|
31
|
+
lambda do
|
|
32
|
+
class TestInvalidType < Rhosync::Model
|
|
33
|
+
field :invalid, :invalid_type
|
|
34
|
+
end
|
|
35
|
+
end.should raise_error(ArgumentError, 'Unknown type invalid_type for field invalid')
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
context "field type cast" do
|
|
40
|
+
class TestType < Rhosync::Model
|
|
41
|
+
field :foo_string, :string
|
|
42
|
+
field :foo_json, :json
|
|
43
|
+
field :foo_date, :datetime
|
|
44
|
+
field :foo_int, :int
|
|
45
|
+
field :foo_float, :float
|
|
46
|
+
|
|
47
|
+
list :list_date, :datetime
|
|
48
|
+
set :set_date, :datetime
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
class TestValidateType < Rhosync::Model
|
|
52
|
+
field :v_field, :string
|
|
53
|
+
validates_presence_of :v_field
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
class TestLoadType < Rhosync::Model
|
|
57
|
+
field :something, :string
|
|
58
|
+
attr_accessor :foo
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
before(:each) do
|
|
62
|
+
@xRedisMock = Spec::Mocks::Mock.new
|
|
63
|
+
@yRedisMock = Spec::Mocks::Mock.new
|
|
64
|
+
@x = TestType.with_key(1)
|
|
65
|
+
@y = TestType.with_key(1)
|
|
66
|
+
@x.stub!(:redis).and_return(@xRedisMock)
|
|
67
|
+
@y.stub!(:redis).and_return(@yRedisMock)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it "should create with string id" do
|
|
71
|
+
@x = TestType.create(:id => 'test')
|
|
72
|
+
@x.id.should == 'test'
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it "should create with auto-increment id" do
|
|
76
|
+
@x = TestType.create
|
|
77
|
+
@x1 = TestType.create
|
|
78
|
+
@x1.id.should == @x.id + 1
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
it "should raise ArgumentError on create with duplicate id" do
|
|
82
|
+
@x = TestType.create(:id => 'test1')
|
|
83
|
+
lambda { TestType.create(:id => 'test1') }.should
|
|
84
|
+
raise_error(ArgumentError, "Record already exists for 'test1'")
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it "should validate_presence_of v_field" do
|
|
88
|
+
lambda { TestValidateType.create(:id => 'test2') }.should
|
|
89
|
+
raise_error(ArgumentError, "Missing required field 'v_field'")
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
it "should load with attributes set" do
|
|
93
|
+
TestLoadType.create(:id => 'test2')
|
|
94
|
+
@x = TestLoadType.load('test2',{:foo => 'bar'})
|
|
95
|
+
@x.foo.should == 'bar'
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
it "should save string as is" do
|
|
99
|
+
@xRedisMock.should_receive(:[]=).with('test_type:1:foo_string', 'xxx')
|
|
100
|
+
@yRedisMock.should_receive(:[]).with('test_type:1:foo_string').and_return('xxx')
|
|
101
|
+
@x.foo_string = 'xxx'
|
|
102
|
+
@y.foo_string.should be_instance_of(String)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
it "should marshal integer fields" do
|
|
106
|
+
@xRedisMock.should_receive(:[]=).with('test_type:1:foo_int', '12')
|
|
107
|
+
@yRedisMock.should_receive(:[]).with('test_type:1:foo_int').and_return('12')
|
|
108
|
+
@x.foo_int = 12
|
|
109
|
+
@y.foo_int.should be_kind_of(Integer)
|
|
110
|
+
@y.foo_int.should == 12
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
it "should marshal float fields" do
|
|
114
|
+
@xRedisMock.should_receive(:[]=).with('test_type:1:foo_float', '12.1')
|
|
115
|
+
@yRedisMock.should_receive(:[]).with('test_type:1:foo_float').and_return('12.1')
|
|
116
|
+
@x.foo_float = 12.1
|
|
117
|
+
@y.foo_float.should be_kind_of(Float)
|
|
118
|
+
@y.foo_float.should == 12.1
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
it "should marshal datetime fields" do
|
|
122
|
+
time = DateTime.now
|
|
123
|
+
str = time.strftime('%FT%T%z')
|
|
124
|
+
@xRedisMock.should_receive(:[]=).with('test_type:1:foo_date', str)
|
|
125
|
+
@yRedisMock.should_receive(:[]).with('test_type:1:foo_date').and_return(str)
|
|
126
|
+
@x.foo_date = time
|
|
127
|
+
@y.foo_date.should be_kind_of(DateTime)
|
|
128
|
+
@y.foo_date.should.to_s == time.to_s
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
it "should marshal json structs" do
|
|
132
|
+
data = {'foo' => 'bar', 'x' => 2}
|
|
133
|
+
str = JSON.dump(data)
|
|
134
|
+
@xRedisMock.should_receive(:[]=).with('test_type:1:foo_json', str)
|
|
135
|
+
@yRedisMock.should_receive(:[]).with('test_type:1:foo_json').and_return(str)
|
|
136
|
+
@x.foo_json = data
|
|
137
|
+
@y.foo_json.should be_kind_of(Hash)
|
|
138
|
+
@y.foo_json.should.inspect == data.inspect
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
it "should return nil for empty fields" do
|
|
142
|
+
@xRedisMock.should_receive(:[]).with('test_type:1:foo_date').and_return(nil)
|
|
143
|
+
@x.foo_date.should be_nil
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
it "should marshal list values" do
|
|
147
|
+
data = DateTime.now
|
|
148
|
+
str = data.strftime('%FT%T%z')
|
|
149
|
+
|
|
150
|
+
@xRedisMock.should_receive('rpush').with('test_type:1:list_date', str)
|
|
151
|
+
@xRedisMock.should_receive('lset').with('test_type:1:list_date', 1, str)
|
|
152
|
+
@xRedisMock.should_receive('exists').with('test_type:1:list_date', str)
|
|
153
|
+
@xRedisMock.should_receive('lrem').with('test_type:1:list_date', 0, str)
|
|
154
|
+
@xRedisMock.should_receive('lpush').with('test_type:1:list_date', str)
|
|
155
|
+
@xRedisMock.should_receive('lrange').with('test_type:1:list_date', 0, 1).and_return([str])
|
|
156
|
+
@xRedisMock.should_receive('rpop').with('test_type:1:list_date').and_return(str)
|
|
157
|
+
@xRedisMock.should_receive('lpop').with('test_type:1:list_date').and_return(str)
|
|
158
|
+
@xRedisMock.should_receive('lindex').with('test_type:1:list_date', 0).and_return(str)
|
|
159
|
+
@x.list_date << data
|
|
160
|
+
@x.list_date[1] = data
|
|
161
|
+
@x.list_date.include?(data)
|
|
162
|
+
@x.list_date.remove(0, data)
|
|
163
|
+
@x.list_date.push_head(data)
|
|
164
|
+
@x.list_date[0].should be_kind_of(DateTime)
|
|
165
|
+
@x.list_date[0, 1][0].should be_kind_of(DateTime)
|
|
166
|
+
@x.list_date.pop_tail.should be_kind_of(DateTime)
|
|
167
|
+
@x.list_date.pop_head.should be_kind_of(DateTime)
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
it "should marshal set values" do
|
|
171
|
+
data = DateTime.now
|
|
172
|
+
str = data.strftime('%FT%T%z')
|
|
173
|
+
|
|
174
|
+
@xRedisMock.should_receive('sadd').with('test_type:1:set_date', str)
|
|
175
|
+
@xRedisMock.should_receive('srem').with('test_type:1:set_date', str)
|
|
176
|
+
@xRedisMock.should_receive('sismember').with('test_type:1:set_date', str)
|
|
177
|
+
@xRedisMock.should_receive('smembers').with('test_type:1:set_date').and_return([str])
|
|
178
|
+
@xRedisMock.should_receive('sinter').with('test_type:1:set_date', 'x').and_return([str])
|
|
179
|
+
@xRedisMock.should_receive('sunion').with('test_type:1:set_date', 'x').and_return([str])
|
|
180
|
+
@xRedisMock.should_receive('sdiff').with('test_type:1:set_date', 'x', 'y').and_return([str])
|
|
181
|
+
@x.set_date << data
|
|
182
|
+
@x.set_date.delete(data)
|
|
183
|
+
@x.set_date.include?(data)
|
|
184
|
+
@x.set_date.members[0].should be_kind_of(DateTime)
|
|
185
|
+
@x.set_date.intersect('x')[0].should be_kind_of(DateTime)
|
|
186
|
+
@x.set_date.union('x')[0].should be_kind_of(DateTime)
|
|
187
|
+
@x.set_date.diff('x', 'y')[0].should be_kind_of(DateTime)
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
context "increment/decrement" do
|
|
193
|
+
class TestIncrements < Rhosync::Model
|
|
194
|
+
field :foo, :integer
|
|
195
|
+
field :bar, :string
|
|
196
|
+
field :baz, :float
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
before do
|
|
200
|
+
@redisMock = Spec::Mocks::Mock.new
|
|
201
|
+
@x = TestIncrements.with_key(1)
|
|
202
|
+
@x.stub!(:redis).and_return(@redisMock)
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
it "should send INCR when #increment! is called on an integer" do
|
|
206
|
+
@redisMock.should_receive(:incr).with("test_increments:1:foo", 1)
|
|
207
|
+
@x.increment!(:foo)
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
it "should send DECR when #decrement! is called on an integer" do
|
|
211
|
+
@redisMock.should_receive(:decr).with("test_increments:1:foo", 1)
|
|
212
|
+
@x.decrement!(:foo)
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
it "should raise an ArgumentError when called on non-integers" do
|
|
216
|
+
[:bar, :baz].each do |f|
|
|
217
|
+
lambda{@x.increment!(f)}.should raise_error(ArgumentError)
|
|
218
|
+
lambda{@x.decrement!(f)}.should raise_error(ArgumentError)
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
context "redis commands" do
|
|
224
|
+
class TestCommands < Rhosync::Model
|
|
225
|
+
field :foo
|
|
226
|
+
list :bar
|
|
227
|
+
set :sloppy
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
before(:each) do
|
|
231
|
+
@redisMock = Spec::Mocks::Mock.new
|
|
232
|
+
@x = TestCommands.with_key(1)
|
|
233
|
+
@x.stub!(:redis).and_return(@redisMock)
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
it "should send GET on field read" do
|
|
237
|
+
@redisMock.should_receive(:[]).with('test_commands:1:foo')
|
|
238
|
+
@x.foo
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
it "should send SET on field write" do
|
|
242
|
+
@redisMock.should_receive(:[]=).with('test_commands:1:foo', 'bar')
|
|
243
|
+
@x.foo = 'bar'
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
it "should send RPUSH on list <<" do
|
|
247
|
+
@redisMock.should_receive(:rpush).with('test_commands:1:bar', 'bar')
|
|
248
|
+
@x.bar << 'bar'
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
it "should send SADD on set <<" do
|
|
252
|
+
@redisMock.should_receive(:sadd).with('test_commands:1:sloppy', 'bar')
|
|
253
|
+
@x.sloppy << 'bar'
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
it "should delete separate fields" do
|
|
257
|
+
@redisMock.should_receive(:del).with('test_commands:1:foo')
|
|
258
|
+
@x.delete :foo
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
it "should delete all field" do
|
|
262
|
+
@redisMock.should_receive(:del).with('test_commands:1:foo')
|
|
263
|
+
@redisMock.should_receive(:del).with('test_commands:1:rho__id')
|
|
264
|
+
@redisMock.should_receive(:del).with('test_commands:1:bar')
|
|
265
|
+
@redisMock.should_receive(:del).with('test_commands:1:sloppy')
|
|
266
|
+
@x.delete
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
require File.join(File.dirname(__FILE__),'..','spec_helper')
|
|
2
|
+
require File.join(File.dirname(__FILE__),'perf_spec_helper')
|
|
3
|
+
|
|
4
|
+
describe "BulkData Performance" do
|
|
5
|
+
it_should_behave_like "SourceAdapterHelper"
|
|
6
|
+
it_should_behave_like "PerfSpecHelper"
|
|
7
|
+
|
|
8
|
+
before(:each) do
|
|
9
|
+
basedir = File.join(File.dirname(__FILE__),'..','apps','rhotestapp')
|
|
10
|
+
Rhosync.bootstrap(basedir) do |rhosync|
|
|
11
|
+
rhosync.vendor_directory = File.join(basedir,'..','vendor')
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
after(:each) do
|
|
16
|
+
delete_data_directory
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "should generate sqlite bulk data for 1000 objects (6000 attributes)" do
|
|
20
|
+
start = start_timer
|
|
21
|
+
@data = get_test_data(1000)
|
|
22
|
+
start = lap_timer('generate data',start)
|
|
23
|
+
set_state('test_db_storage' => @data)
|
|
24
|
+
start = lap_timer('set_state masterdoc',start)
|
|
25
|
+
data = BulkData.create(:name => bulk_data_docname(@a.id,@u.id),
|
|
26
|
+
:state => :inprogress,
|
|
27
|
+
:app_id => @a.id,
|
|
28
|
+
:user_id => @u.id,
|
|
29
|
+
:sources => [@s_fields[:name]])
|
|
30
|
+
BulkDataJob.perform("data_name" => data.name)
|
|
31
|
+
lap_timer('BulkDataJob.perform duration',start)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
require 'faker'
|
|
2
|
+
|
|
3
|
+
describe "PerfSpecHelper", :shared => true do
|
|
4
|
+
|
|
5
|
+
def get_test_data(num=1000)
|
|
6
|
+
file = File.join("spec","testdata","#{num}-data.txt")
|
|
7
|
+
data = nil
|
|
8
|
+
if File.exists?(file)
|
|
9
|
+
data = open(file, 'r') {|f| Marshal.load(f)}
|
|
10
|
+
else
|
|
11
|
+
data = generate_fake_data(num)
|
|
12
|
+
f = File.new(file, 'w')
|
|
13
|
+
f.write Marshal.dump(data)
|
|
14
|
+
f.close
|
|
15
|
+
end
|
|
16
|
+
data
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
PREFIX = ["Account", "Administrative", "Advertising", "Assistant", "Banking", "Business Systems",
|
|
22
|
+
"Computer", "Distribution", "IT", "Electronics", "Environmental", "Financial", "General", "Head",
|
|
23
|
+
"Laboratory", "Maintenance", "Medical", "Production", "Quality Assurance", "Software", "Technical",
|
|
24
|
+
"Chief", "Senior"] unless defined? PREFIX
|
|
25
|
+
SUFFIX = ["Clerk", "Analyst", "Manager", "Supervisor", "Plant Manager", "Mechanic", "Technician", "Engineer",
|
|
26
|
+
"Director", "Superintendent", "Specialist", "Technologist", "Estimator", "Scientist", "Foreman", "Nurse",
|
|
27
|
+
"Worker", "Helper", "Intern", "Sales", "Mechanic", "Planner", "Recruiter", "Officer", "Superintendent",
|
|
28
|
+
"Vice President", "Buyer", "Production Supervisor", "Chef", "Accountant", "Executive"] unless defined? SUFFIX
|
|
29
|
+
|
|
30
|
+
def title
|
|
31
|
+
prefix = PREFIX[rand(PREFIX.length)]
|
|
32
|
+
suffix = SUFFIX[rand(SUFFIX.length)]
|
|
33
|
+
|
|
34
|
+
"#{prefix} #{suffix}"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def generate_fake_data(num=1000)
|
|
38
|
+
res = {}
|
|
39
|
+
num.times do |n|
|
|
40
|
+
res[n.to_s] = {
|
|
41
|
+
"FirstName" => Faker::Name.first_name,
|
|
42
|
+
"LastName" => Faker::Name.last_name,
|
|
43
|
+
"Email" => Faker::Internet.free_email,
|
|
44
|
+
"Company" => Faker::Company.name,
|
|
45
|
+
"JobTitle" => title,
|
|
46
|
+
"Phone1" => Faker::PhoneNumber.phone_number
|
|
47
|
+
}
|
|
48
|
+
end
|
|
49
|
+
res
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
require File.join(File.dirname(__FILE__),'..','spec_helper')
|
|
2
|
+
require File.join(File.dirname(__FILE__),'perf_spec_helper')
|
|
3
|
+
|
|
4
|
+
describe "Rhosync Performance" do
|
|
5
|
+
it_should_behave_like "SourceAdapterHelper"
|
|
6
|
+
it_should_behave_like "PerfSpecHelper"
|
|
7
|
+
|
|
8
|
+
it "should process get/put for 1000 records (6000 elements)" do
|
|
9
|
+
@data = get_test_data(1000)
|
|
10
|
+
start = start_timer
|
|
11
|
+
Store.put_data('mdoc',@data).should == true
|
|
12
|
+
start = lap_timer('put_data duration',start)
|
|
13
|
+
Store.get_data('mdoc').should == @data
|
|
14
|
+
lap_timer('get_data duration',start)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "should process single attribute update 1000-record doc" do
|
|
18
|
+
@data = get_test_data(1000)
|
|
19
|
+
@data1 = get_test_data(1000)
|
|
20
|
+
@data1['950']['Phone1'] = 'This is changed'
|
|
21
|
+
expected = {'950' => {'Phone1' => 'This is changed'}}
|
|
22
|
+
Store.put_data('mdoc',@data).should == true
|
|
23
|
+
Store.put_data('cdoc',@data1).should == true
|
|
24
|
+
start = start_timer
|
|
25
|
+
Store.get_diff_data('mdoc','cdoc').should == [expected,1]
|
|
26
|
+
lap_timer('get_diff_data duration', start)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
require File.join(File.dirname(__FILE__),'..','spec_helper')
|
|
2
|
+
|
|
3
|
+
describe "Ping Blackberry" do
|
|
4
|
+
it_should_behave_like "SpecBootstrapHelper"
|
|
5
|
+
it_should_behave_like "SourceAdapterHelper"
|
|
6
|
+
|
|
7
|
+
before do
|
|
8
|
+
@params = {"user_id" => @u.id, "api_token" => @api_token,
|
|
9
|
+
"sources" => [@s.name], "message" => 'hello world',
|
|
10
|
+
"vibrate" => '5', "badge" => '5', "sound" => 'hello.mp3',
|
|
11
|
+
"device_pin" => @c.device_pin, "device_port" => @c.device_port}
|
|
12
|
+
post = mock('post')
|
|
13
|
+
post.stub!(:new).and_return(post)
|
|
14
|
+
post.stub!(:body=)
|
|
15
|
+
Net::HTTP::Post.stub!(:new).and_return(post)
|
|
16
|
+
|
|
17
|
+
@http = mock('http')
|
|
18
|
+
@http.stub!(:request)
|
|
19
|
+
@http.stub!(:start).and_yield(@http)
|
|
20
|
+
Net::HTTP.stub!(:new).and_return(@http)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it "should ping blackberry" do
|
|
24
|
+
Blackberry.ping(@params)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it "should ping blackberry with connection error" do
|
|
28
|
+
error = 'Connection refused'
|
|
29
|
+
@http.stub!(:request).and_return { raise SocketError.new(error) }
|
|
30
|
+
Blackberry.should_receive(:log).once.with("Error while sending ping: #{error}")
|
|
31
|
+
lambda { Blackberry.ping(@params) }.should raise_error(SocketError,error)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "should compute pap_message" do
|
|
35
|
+
expected = <<PAP
|
|
36
|
+
--asdlfkjiurwghasf
|
|
37
|
+
Content-Type: application/xml; charset=UTF-8
|
|
38
|
+
|
|
39
|
+
<?xml version="1.0"?>
|
|
40
|
+
<!DOCTYPE pap PUBLIC "-//WAPFORUM//DTD PAP 2.0//EN"
|
|
41
|
+
"http://www.wapforum.org/DTD/pap_2.0.dtd"
|
|
42
|
+
[<?wap-pap-ver supported-versions="2.0"?>]>
|
|
43
|
+
<pap>
|
|
44
|
+
<push-message push-id="pushID:RAND_ID" ppg-notify-requested-to="http://localhost:7778">
|
|
45
|
+
|
|
46
|
+
<address address-value="WAPPUSH=0%3A100/TYPE=USER@rim.net"/>
|
|
47
|
+
<quality-of-service delivery-method="preferconfirmed"/>
|
|
48
|
+
</push-message>
|
|
49
|
+
</pap>
|
|
50
|
+
--asdlfkjiurwghasf
|
|
51
|
+
Content-Type: text/plain
|
|
52
|
+
|
|
53
|
+
do_sync=SampleAdapter
|
|
54
|
+
show_popup=hello world
|
|
55
|
+
vibrate=5
|
|
56
|
+
|
|
57
|
+
--asdlfkjiurwghasf--
|
|
58
|
+
PAP
|
|
59
|
+
actual = Blackberry.pap_message(@params).gsub!(/pushID\:\d+/,'pushID:RAND_ID')
|
|
60
|
+
actual.gsub!(/\r|\n|\s/,"").should == expected.gsub!(/\r|\n|\s/,"")
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
require File.join(File.dirname(__FILE__),'..','spec_helper')
|
|
2
|
+
|
|
3
|
+
describe "Ping Iphone" do
|
|
4
|
+
it_should_behave_like "SpecBootstrapHelper"
|
|
5
|
+
it_should_behave_like "SourceAdapterHelper"
|
|
6
|
+
|
|
7
|
+
before do
|
|
8
|
+
@params = {"user_id" => @u.id, "api_token" => @api_token,
|
|
9
|
+
"sources" => [@s.name], "message" => 'hello world',
|
|
10
|
+
"vibrate" => '5', "badge" => '5', "sound" => 'hello.mp3',
|
|
11
|
+
"device_pin" => @c.device_pin, "device_port" => @c.device_port}
|
|
12
|
+
ssl_ctx = mock("ssl_ctx")
|
|
13
|
+
ssl_ctx.stub!(:key=).and_return('key')
|
|
14
|
+
ssl_ctx.stub!(:cert=).and_return('cert')
|
|
15
|
+
OpenSSL::SSL::SSLContext.stub!(:new).and_return(ssl_ctx)
|
|
16
|
+
OpenSSL::PKey::RSA.stub!(:new)
|
|
17
|
+
OpenSSL::X509::Certificate.stub!(:new)
|
|
18
|
+
|
|
19
|
+
tcp_socket = mock("tcp_socket")
|
|
20
|
+
tcp_socket.stub!(:close)
|
|
21
|
+
TCPSocket.stub!(:new).and_return(tcp_socket)
|
|
22
|
+
|
|
23
|
+
@ssl_socket = mock("ssl_socket")
|
|
24
|
+
@ssl_socket.stub!(:sync=)
|
|
25
|
+
@ssl_socket.stub!(:connect)
|
|
26
|
+
@ssl_socket.stub!(:write)
|
|
27
|
+
@ssl_socket.stub!(:close)
|
|
28
|
+
OpenSSL::SSL::SSLSocket.stub!(:new).and_return(@ssl_socket)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# TODO: This should really test SSLSocket.write
|
|
32
|
+
it "should ping iphone" do
|
|
33
|
+
Iphone.ping(@params)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "should compute apn_message" do
|
|
37
|
+
expected = <<-eos
|
|
38
|
+
\000\000 \253\315\000g{"aps":{"vibrate":"5","badge":5,"sound":"hello.mp3","alert":"hello world"},"do_sync":["SampleAdapter"]}
|
|
39
|
+
eos
|
|
40
|
+
Iphone.apn_message(@params).should == expected.strip!
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it "should raise SocketError if socket fails" do
|
|
44
|
+
error = 'socket error'
|
|
45
|
+
@ssl_socket.stub!(:write).and_return { raise SocketError.new(error) }
|
|
46
|
+
Iphone.should_receive(:log).once.with("Error while sending ping: #{error}")
|
|
47
|
+
lambda { Iphone.ping(@params) }.should raise_error(SocketError,error)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
require File.join(File.dirname(__FILE__),'spec_helper')
|
|
2
|
+
|
|
3
|
+
describe "ReadState" do
|
|
4
|
+
it_should_behave_like "SpecBootstrapHelper"
|
|
5
|
+
it_should_behave_like "SourceAdapterHelper"
|
|
6
|
+
|
|
7
|
+
it "should create refresh with correct id" do
|
|
8
|
+
@r.id.should == "#{@a_fields[:name]}:#{@u_fields[:login]}:#{@s_fields[:name]}"
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
it "should create refresh with default fields" do
|
|
12
|
+
@r.refresh_time.should <= Time.now.to_i
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it "should load refresh with params" do
|
|
16
|
+
@r1 = ReadState.load(:app_id => @a_fields[:name],
|
|
17
|
+
:user_id => @u_fields[:login],:source_name => @s_fields[:name])
|
|
18
|
+
@r1.refresh_time.should <= Time.now.to_i
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it "should delete read_state from db" do
|
|
22
|
+
ReadState.delete(@a_fields[:name])
|
|
23
|
+
Store.db.keys("read_state*").should == []
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
require File.join(File.dirname(__FILE__),'spec_helper')
|
|
2
|
+
|
|
3
|
+
describe "Rhosync" do
|
|
4
|
+
it_should_behave_like "RhosyncHelper"
|
|
5
|
+
it_should_behave_like "TestappHelper"
|
|
6
|
+
|
|
7
|
+
it "should bootstrap Rhosync with block" do
|
|
8
|
+
Rhosync.bootstrap(get_testapp_path) do |rhosync|
|
|
9
|
+
rhosync.vendor_directory = 'foo'
|
|
10
|
+
end
|
|
11
|
+
path = get_testapp_path
|
|
12
|
+
File.expand_path(Rhosync.base_directory).should == path
|
|
13
|
+
File.expand_path(Rhosync.app_directory).should == path
|
|
14
|
+
File.expand_path(Rhosync.data_directory).should == File.join(path,'data')
|
|
15
|
+
Rhosync.vendor_directory.should == 'foo'
|
|
16
|
+
Rhosync.blackberry_bulk_sync.should == false
|
|
17
|
+
Rhosync.environment.should == :development
|
|
18
|
+
App.is_exist?(@test_app_name).should be_true
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it "should bootstrap Rhosync with RHO_ENV provided" do
|
|
22
|
+
ENV['RHO_ENV'] = 'production'
|
|
23
|
+
Rhosync.bootstrap(get_testapp_path)
|
|
24
|
+
Rhosync.environment.should == :production
|
|
25
|
+
ENV.delete('RHO_ENV')
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it "should bootstrap with existing app" do
|
|
29
|
+
app = App.create(:name => @test_app_name)
|
|
30
|
+
App.should_receive(:load).once.with(@test_app_name).and_return(app)
|
|
31
|
+
Rhosync.bootstrap(get_testapp_path)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "should bootstrap app with no sources" do
|
|
35
|
+
app = App.create(:name => @test_app_name)
|
|
36
|
+
Rhosync.stub!(:get_config).and_return(
|
|
37
|
+
{ Rhosync.environment.to_sym => { :licensefile => 'settings/license.key' } }
|
|
38
|
+
)
|
|
39
|
+
App.should_receive(:load).twice.with(@test_app_name).and_return(app)
|
|
40
|
+
Rhosync.bootstrap(get_testapp_path)
|
|
41
|
+
App.load(@test_app_name).sources.members.should == []
|
|
42
|
+
end
|
|
43
|
+
end
|