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/README.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
Rhosync
|
|
2
|
+
-------------------------------------------------------------
|
|
3
|
+
|
|
4
|
+
Redis-powered rhosync with built-in sinatra application.
|
|
5
|
+
|
|
6
|
+
INSTALL
|
|
7
|
+
-------------------------------------------------------------
|
|
8
|
+
1. Make sure you have the following gems installed:
|
|
9
|
+
|
|
10
|
+
* rspec rcov json sqlite3-ruby faker redis redis-namespace sinatra rack-test rubyzip uuidtools resque
|
|
11
|
+
|
|
12
|
+
2. Install and start a redis server (v1.2 or greater is required) (see <http://code.google.com/p/redis/>)
|
|
13
|
+
|
|
14
|
+
3. Install hsqldata.jar to vendor/ directory. See <http://github.com/rhomobile/hsqldata> for instructions on how to build hsqldata.
|
|
15
|
+
|
|
16
|
+
4. "rake" to run all specs
|
|
17
|
+
|
|
18
|
+
Windows Notes: when run any spec task error message box (ruby.exe - Unable to locate component) will appear. Just press 'OK'. This is problem with rcov.
|
|
19
|
+
|
|
20
|
+
DOCS
|
|
21
|
+
-------------------------------------------------------------
|
|
22
|
+
* Intro to Rhodes & Rhosync: <http://wiki.rhomobile.com/index.php/Rhomobile> -> Read this first!
|
|
23
|
+
* Tutorial: <http://wiki.rhomobile.com/index.php/Tutorial>
|
|
24
|
+
* Architecture: <http://wiki.rhomobile.com/index.php/RhoSync_2.0>
|
|
25
|
+
* Rdoc (still rough): <http://rdoc.info/projects/rhomobile/rhosync>
|
|
26
|
+
* Client/Server Protocol: See doc/protocol.html
|
data/Rakefile
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
require 'yaml'
|
|
2
|
+
|
|
3
|
+
$:.unshift File.join(File.dirname(__FILE__),'lib')
|
|
4
|
+
require 'rhosync'
|
|
5
|
+
|
|
6
|
+
task :default => 'spec:all'
|
|
7
|
+
task :spec => 'spec:spec'
|
|
8
|
+
|
|
9
|
+
begin
|
|
10
|
+
require 'spec/rake/spectask'
|
|
11
|
+
require 'rcov/rcovtask'
|
|
12
|
+
|
|
13
|
+
SPEC_OPTS = ['-fn', '--color', '-b']
|
|
14
|
+
|
|
15
|
+
TYPES = {
|
|
16
|
+
:spec => 'spec/*_spec.rb',
|
|
17
|
+
:perf => 'spec/perf/*_spec.rb',
|
|
18
|
+
:server => 'spec/server/*_spec.rb',
|
|
19
|
+
:api => 'spec/api/*_spec.rb',
|
|
20
|
+
:bulk => 'spec/bulk_data/*_spec.rb',
|
|
21
|
+
:jobs => 'spec/jobs/*_spec.rb',
|
|
22
|
+
:ping => 'spec/ping/*_spec.rb',
|
|
23
|
+
:doc => 'spec/doc/*_spec.rb',
|
|
24
|
+
:generator => 'spec/generator/*_spec.rb',
|
|
25
|
+
:bench => 'bench/spec/*_spec.rb'
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
TYPES.each do |type,files|
|
|
29
|
+
desc "Run specs in #{files}"
|
|
30
|
+
Spec::Rake::SpecTask.new("spec:#{type}") do |t|
|
|
31
|
+
t.spec_files = FileList[TYPES[type]]
|
|
32
|
+
t.spec_opts = SPEC_OPTS
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
desc "Run specs in spec/**/*_spec.rb "
|
|
37
|
+
Spec::Rake::SpecTask.new('spec:all') do |t|
|
|
38
|
+
t.spec_files = FileList[TYPES.values]
|
|
39
|
+
t.spec_opts = SPEC_OPTS
|
|
40
|
+
t.rcov = true
|
|
41
|
+
t.rcov_opts = ['--exclude', 'spec/*,gems/*,apps/*,bench/spec/*']
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
rescue LoadError => e
|
|
45
|
+
puts "rspec / rcov not available. Install with: "
|
|
46
|
+
puts "gem install rspec rcov\n\n"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
desc "Build rhosync gem"
|
|
50
|
+
task :gem => [ 'spec:all', 'clobber_spec:all', :gemspec, :build ]
|
|
51
|
+
|
|
52
|
+
begin
|
|
53
|
+
require 'jeweler'
|
|
54
|
+
|
|
55
|
+
Jeweler::Tasks.new do |gemspec|
|
|
56
|
+
gemspec.name = "rhosync"
|
|
57
|
+
gemspec.summary = %q{Rhosync Server}
|
|
58
|
+
gemspec.description = %q{Rhosync Server and related command-line utilities for using Rhosync}
|
|
59
|
+
gemspec.homepage = %q{http://rhomobile.com/products/rhosync}
|
|
60
|
+
gemspec.authors = ["Rhomobile"]
|
|
61
|
+
gemspec.version = Rhosync::VERSION
|
|
62
|
+
gemspec.files = FileList["[A-Z]*", "{bench,bin,doc,generators,lib,spec,tasks}/**/*"]
|
|
63
|
+
|
|
64
|
+
gemspec.add_dependency "json", ">=1.2.3"
|
|
65
|
+
gemspec.add_dependency "log4r", ">=1.1.7"
|
|
66
|
+
gemspec.add_dependency "sqlite3-ruby", ">=1.2.5"
|
|
67
|
+
gemspec.add_dependency "rubyzip", ">=0.9.4"
|
|
68
|
+
gemspec.add_dependency "uuidtools", ">=2.1.1"
|
|
69
|
+
gemspec.add_dependency "redis", ">=0.2.0"
|
|
70
|
+
gemspec.add_dependency "resque", ">=1.8.0"
|
|
71
|
+
gemspec.add_dependency "rest-client", ">=1.4.2"
|
|
72
|
+
gemspec.add_dependency "sinatra", ">=0.9.2"
|
|
73
|
+
gemspec.add_dependency "templater", ">=1.0.0"
|
|
74
|
+
gemspec.add_development_dependency "jeweler", ">=1.4.0"
|
|
75
|
+
gemspec.add_development_dependency "rspec", ">=1.3.0"
|
|
76
|
+
gemspec.add_development_dependency "rcov", ">=0.9.8"
|
|
77
|
+
gemspec.add_development_dependency "faker", ">=0.3.1"
|
|
78
|
+
gemspec.add_development_dependency "rack-test", ">=0.5.3"
|
|
79
|
+
gemspec.add_development_dependency "mechanize", ">=1.0.0"
|
|
80
|
+
end
|
|
81
|
+
rescue LoadError
|
|
82
|
+
puts "Jeweler not available. Install it with: "
|
|
83
|
+
puts "gem install jeweler\n\n"
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
desc "Load console environment"
|
|
87
|
+
task :console do
|
|
88
|
+
sh "irb -rubygems -r #{File.join(File.dirname(__FILE__),'lib','rhosync','server.rb')}"
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
desc "Run benchmark scripts"
|
|
92
|
+
task :bench do
|
|
93
|
+
login = ask "login: "
|
|
94
|
+
password = ask "password: "
|
|
95
|
+
prefix = 'bench/scripts/'
|
|
96
|
+
suffix = '_script.rb'
|
|
97
|
+
list = ask "scripts(default is '*'): "
|
|
98
|
+
file_list = list.empty? ? FileList[prefix+'*'+suffix] : FileList[prefix+list+suffix]
|
|
99
|
+
file_list.each do |script|
|
|
100
|
+
sh "bench/bench start #{script} #{login} #{password}"
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def ask(msg)
|
|
105
|
+
print msg
|
|
106
|
+
STDIN.gets.chomp
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
load 'tasks/redis.rake'
|
data/bench/bench
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__),'..','..','lib')
|
|
2
|
+
require 'rhosync/tasks'
|
|
3
|
+
|
|
4
|
+
begin
|
|
5
|
+
require 'resque/tasks'
|
|
6
|
+
|
|
7
|
+
task "resque:setup" do
|
|
8
|
+
require 'rhosync'
|
|
9
|
+
require 'application'
|
|
10
|
+
end
|
|
11
|
+
rescue LoadError
|
|
12
|
+
puts "Resque not available. Install it with: "
|
|
13
|
+
puts "gem install resque\n\n"
|
|
14
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
# Try to load vendor-ed rhosync, otherwise load the gem
|
|
4
|
+
begin
|
|
5
|
+
require 'vendor/rhosync/lib/rhosync'
|
|
6
|
+
rescue LoadError
|
|
7
|
+
require 'rhosync/server'
|
|
8
|
+
require 'rhosync/console/server'
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# By default, turn on the resque web console
|
|
12
|
+
require 'resque/server'
|
|
13
|
+
|
|
14
|
+
ROOT_PATH = File.expand_path(File.dirname(__FILE__))
|
|
15
|
+
|
|
16
|
+
# Rhosync server flags
|
|
17
|
+
Rhosync::Server.disable :run
|
|
18
|
+
Rhosync::Server.disable :clean_trace
|
|
19
|
+
Rhosync::Server.enable :raise_errors
|
|
20
|
+
Rhosync::Server.set :environment, :development
|
|
21
|
+
Rhosync::Server.set :secret, '<changeme>'
|
|
22
|
+
Rhosync::Server.set :root, ROOT_PATH
|
|
23
|
+
Rhosync::Server.use Rack::Static, :urls => ["/data"], :root => Rhosync::Server.root
|
|
24
|
+
|
|
25
|
+
# Load our rhosync application
|
|
26
|
+
require 'application'
|
|
27
|
+
|
|
28
|
+
# Setup the url map
|
|
29
|
+
run Rack::URLMap.new \
|
|
30
|
+
"/" => Rhosync::Server.new,
|
|
31
|
+
"/resque" => Resque::Server.new, # If you don't want resque frontend, disable it here
|
|
32
|
+
"/console" => RhosyncConsole::Server.new # If you don't want rhosync frontend, disable it here
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
858fc60fadfde40273d0ac505906969318aa4931d1a2c4aeb24d98393c74379f60e226651601969874257f7f1fbda9b099ecd551a641519aa46819947fda0191
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
:sources:
|
|
2
|
+
MockAdapter:
|
|
3
|
+
poll_interval: 300
|
|
4
|
+
QueueMockAdapter:
|
|
5
|
+
queue: abc
|
|
6
|
+
|
|
7
|
+
:development:
|
|
8
|
+
:licensefile: settings/license.key
|
|
9
|
+
:redis: localhost:6379
|
|
10
|
+
:syncserver: http://localhost:9292/application/
|
|
11
|
+
:test:
|
|
12
|
+
:licensefile: settings/license.key
|
|
13
|
+
:redis: localhost:6379
|
|
14
|
+
:syncserver: http://localhost:9292/application/
|
|
15
|
+
:production:
|
|
16
|
+
:licensefile: settings/license.key
|
|
17
|
+
:redis: localhost:6379
|
|
18
|
+
:syncserver: http://localhost:9292/application/
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
class MockAdapter < SourceAdapter
|
|
2
|
+
def initialize(source,credential)
|
|
3
|
+
super(source,credential)
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
def login
|
|
7
|
+
true
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def query(params=nil)
|
|
11
|
+
Store.lock(lock_name,1) do
|
|
12
|
+
@result = Store.get_data(db_name)
|
|
13
|
+
end
|
|
14
|
+
@result
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def create(name_value_list,blob=nil)
|
|
18
|
+
id = name_value_list['mock_id']
|
|
19
|
+
Store.lock(lock_name,1) do
|
|
20
|
+
Store.put_data(db_name,{id=>name_value_list},true) if id
|
|
21
|
+
end
|
|
22
|
+
id
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def update(name_value_list)
|
|
26
|
+
id = name_value_list.delete('id')
|
|
27
|
+
return unless id
|
|
28
|
+
Store.lock(lock_name,1) do
|
|
29
|
+
data = Store.get_data(db_name)
|
|
30
|
+
return unless data and data[id]
|
|
31
|
+
name_value_list.each do |attrib,value|
|
|
32
|
+
data[id][attrib] = value
|
|
33
|
+
end
|
|
34
|
+
Store.put_data(db_name,data)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def delete(name_value_list)
|
|
39
|
+
id = name_value_list.delete('id')
|
|
40
|
+
Store.lock(lock_name,1) do
|
|
41
|
+
Store.delete_data(db_name,{id=>name_value_list}) if id
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def db_name
|
|
46
|
+
"test_db_storage:#{@source.app_id}:#{@source.user_id}"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def lock_name()
|
|
50
|
+
"#{db_name}:lock"
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
private
|
|
54
|
+
|
|
55
|
+
end
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
|
|
2
|
+
# We're "vendoring" the rhosync/lib directory here so we can use the working copy of
|
|
3
|
+
# rhosync. Normally, you would require rhosync as a gem or vendor it here.
|
|
4
|
+
path = File.join(File.dirname(__FILE__),'..','..','..','..','..','lib')
|
|
5
|
+
$:.unshift path
|
|
6
|
+
require File.join(path,'rhosync','server')
|
|
7
|
+
require File.join(path,'rhosync','console','server')
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
require 'thor'
|
|
2
|
+
|
|
3
|
+
module Bench
|
|
4
|
+
class Cli < Thor
|
|
5
|
+
include Logging
|
|
6
|
+
desc "start path/to/bench/script", "Start performance test"
|
|
7
|
+
def start(script,login,password='')
|
|
8
|
+
Bench.admin_login = login
|
|
9
|
+
Bench.admin_password = password
|
|
10
|
+
load(script)
|
|
11
|
+
Statistics.new(Bench.concurrency,Bench.iterations,
|
|
12
|
+
Bench.total_time,Bench.sessions).process.print_stats
|
|
13
|
+
logger.info "Bench completed..."
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module Bench
|
|
2
|
+
module Logging
|
|
3
|
+
def logger
|
|
4
|
+
init_logger if Log4r::Logger['main'].nil?
|
|
5
|
+
Log4r::Logger['main']
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def log_prefix
|
|
9
|
+
"[T:%03d|I:%03d]" % [@thread_id,@iteration]
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
protected
|
|
13
|
+
def init_logger
|
|
14
|
+
logger = Log4r::Logger.new('main')
|
|
15
|
+
logger.outputters = Log4r::Outputter.stdout
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
require 'redis'
|
|
2
|
+
$:.unshift File.join(File.dirname(__FILE__),'..','..','..','lib')
|
|
3
|
+
require 'rhosync'
|
|
4
|
+
include Rhosync
|
|
5
|
+
|
|
6
|
+
module Bench
|
|
7
|
+
class MockClient
|
|
8
|
+
include Logging
|
|
9
|
+
|
|
10
|
+
def initialize(thread_id,iteration,client_id)
|
|
11
|
+
@thread_id,@iteration,@client_id = thread_id,iteration,client_id
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def parse(message)
|
|
15
|
+
msg = JSON.parse(message)
|
|
16
|
+
raise Exception.new("#{log_prefix} Wrong message format. Message: #{message.inspect}") if msg.size < 6
|
|
17
|
+
raise Exception.new("#{log_prefix} Wrong protocol version. Message: #{message.inspect}") if msg[0]['version'] != 3
|
|
18
|
+
msg.each do |p|
|
|
19
|
+
insert(p['insert']) if p['insert']
|
|
20
|
+
delete(p['delete']) if p['delete']
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def insert(objects)
|
|
25
|
+
Store.put_data(doc_type,objects,true)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def delete(objects)
|
|
29
|
+
Store.delete_data(doc_type,objects)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def verify(objects)
|
|
33
|
+
Store.get_data(doc_type) == objects
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def doc_type
|
|
37
|
+
"#{@client_id.to_s}:mock:cd"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
require 'set'
|
|
2
|
+
|
|
3
|
+
module Bench
|
|
4
|
+
class Result
|
|
5
|
+
attr_accessor :last_response,:time,:marker,:url,:verb,:error,:verification_error
|
|
6
|
+
include Logging
|
|
7
|
+
include Utils
|
|
8
|
+
|
|
9
|
+
def initialize(marker,verb,url,thread_id,iteration)
|
|
10
|
+
@marker,@verb,@url,@thread_id,@iteration = marker,verb,url,thread_id,iteration
|
|
11
|
+
@verification_error = 0
|
|
12
|
+
@time = 0
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def code
|
|
16
|
+
@last_response.code
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def body
|
|
20
|
+
@last_response.to_s
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def cookies
|
|
24
|
+
@last_response.cookies
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def headers
|
|
28
|
+
@last_response.headers
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def verify_body(expected)
|
|
32
|
+
expected,actual = JSON.parse(expected),JSON.parse(@last_response.to_s)
|
|
33
|
+
@verification_error += compare_and_log(expected,actual,caller(1)[0].to_s)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def verify_code(expected)
|
|
37
|
+
if expected != @last_response.code
|
|
38
|
+
logger.error "#{log_prefix} Verify error at: " + caller(1)[0].to_s
|
|
39
|
+
logger.error "#{log_prefix} Code diff: "
|
|
40
|
+
logger.error "#{log_prefix} expected: #{expected.inspect}"
|
|
41
|
+
logger.error "#{log_prefix} but got: #{@last_response.code}"
|
|
42
|
+
@verification_error += 1
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def verify_headers
|
|
47
|
+
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
module Bench
|
|
2
|
+
class Runner
|
|
3
|
+
include Logging
|
|
4
|
+
include Timer
|
|
5
|
+
attr_reader :threads
|
|
6
|
+
|
|
7
|
+
def initialize
|
|
8
|
+
@threads = []
|
|
9
|
+
@sessions = []
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def test(concurrency,iterations,&block)
|
|
13
|
+
thread_id = 0
|
|
14
|
+
total_time = time do
|
|
15
|
+
concurrency.times do
|
|
16
|
+
sleep rand(2)
|
|
17
|
+
thread = Thread.new(block) do |t|
|
|
18
|
+
tid, iteration = thread_id,0
|
|
19
|
+
iterations.times do
|
|
20
|
+
s = Session.new(tid,iteration)
|
|
21
|
+
@sessions << s
|
|
22
|
+
begin
|
|
23
|
+
yield Bench,s
|
|
24
|
+
rescue Exception => e
|
|
25
|
+
puts "error running script: #{e.inspect}"
|
|
26
|
+
end
|
|
27
|
+
iteration += 1
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
thread_id += 1
|
|
31
|
+
threads << thread
|
|
32
|
+
end
|
|
33
|
+
begin
|
|
34
|
+
threads.each { |t| t.join }
|
|
35
|
+
rescue RestClient::RequestTimeout => e
|
|
36
|
+
logger.info "Request timed out #{e}"
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
Bench.sessions = @sessions
|
|
40
|
+
Bench.total_time = total_time
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
module Bench
|
|
2
|
+
class Session
|
|
3
|
+
include Logging
|
|
4
|
+
include Timer
|
|
5
|
+
attr_accessor :cookies, :last_result, :results, :thread_id, :iteration, :client_id
|
|
6
|
+
|
|
7
|
+
def initialize(thread_id,iteration)
|
|
8
|
+
@cookies = {}
|
|
9
|
+
@results = {}
|
|
10
|
+
@thread_id,@iteration = thread_id,iteration
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def post(marker,url,headers={})
|
|
14
|
+
@body = yield
|
|
15
|
+
_request(marker,:_post,url,headers)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def get(marker,url,headers={})
|
|
19
|
+
params = yield if block_given?
|
|
20
|
+
url_params = url.clone
|
|
21
|
+
url_params << "?" + _url_params(params) if params
|
|
22
|
+
_request(marker,:_get,url_params,headers)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
protected
|
|
26
|
+
def _request(marker,verb,url,headers)
|
|
27
|
+
result = Result.new(marker,verb,url,@thread_id,@iteration)
|
|
28
|
+
@results[result.marker] ||= []
|
|
29
|
+
@results[result.marker] << result
|
|
30
|
+
begin
|
|
31
|
+
result.time = time do
|
|
32
|
+
headers.merge!(:cookies => @cookies)
|
|
33
|
+
result.last_response = send(verb,url,headers)
|
|
34
|
+
@last_result = result
|
|
35
|
+
end
|
|
36
|
+
logger.info "#{log_prefix} #{verb.to_s.upcase.gsub(/_/,'')} #{url} #{@last_result.code} #{result.time}"
|
|
37
|
+
rescue RestClient::Exception => e
|
|
38
|
+
result.error = e
|
|
39
|
+
logger.info "#{log_prefix} #{verb.to_s.upcase.gsub(/_/,'')} #{url}"
|
|
40
|
+
logger.error "#{log_prefix} #{e.http_code.to_s} #{e.message}\n"
|
|
41
|
+
raise e
|
|
42
|
+
end
|
|
43
|
+
@cookies = @cookies.merge(@last_result.cookies)
|
|
44
|
+
@last_result
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def _get(url,headers)
|
|
48
|
+
#logger.info "GET #{url}"
|
|
49
|
+
RestClient.get(url, headers)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def _post(url,headers)
|
|
53
|
+
#logger.info "POST #{url}"
|
|
54
|
+
RestClient.post(url, @body, headers)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def _url_params(params)
|
|
58
|
+
elements = []
|
|
59
|
+
params.each do |key,value|
|
|
60
|
+
elements << "#{key}=#{value}"
|
|
61
|
+
end
|
|
62
|
+
elements.join('&')
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
module Bench
|
|
2
|
+
class Statistics
|
|
3
|
+
include Logging
|
|
4
|
+
|
|
5
|
+
def initialize(concurrency,iterations,total_time,sessions)
|
|
6
|
+
@sessions = sessions
|
|
7
|
+
@rows = {} # row key is result.marker;
|
|
8
|
+
@total_count = 0
|
|
9
|
+
@total_time = total_time
|
|
10
|
+
@concurrency,@iterations = concurrency,iterations
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def process
|
|
14
|
+
@sessions.each do |session|
|
|
15
|
+
session.results.each do |marker,results|
|
|
16
|
+
results.each do |result|
|
|
17
|
+
@rows[result.marker] ||= {}
|
|
18
|
+
row = @rows[result.marker]
|
|
19
|
+
row[:min] ||= 0.0
|
|
20
|
+
row[:max] ||= 0.0
|
|
21
|
+
row[:count] ||= 0
|
|
22
|
+
row[:total_time] ||= 0.0
|
|
23
|
+
row[:errors] ||= 0
|
|
24
|
+
row[:verification_errors] ||= 0
|
|
25
|
+
row[:min] = result.time if result.time < row[:min] || row[:min] == 0
|
|
26
|
+
row[:max] = result.time if result.time > row[:max]
|
|
27
|
+
row[:count] += 1.0
|
|
28
|
+
row[:total_time] += result.time
|
|
29
|
+
row[:errors] += 1 if result.error
|
|
30
|
+
row[:verification_errors] += result.verification_error
|
|
31
|
+
@total_count += 1
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
self
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def average(row)
|
|
39
|
+
row[:total_time] / row[:count]
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def print_stats
|
|
43
|
+
logger.info "Statistics:"
|
|
44
|
+
@rows.each do |marker,row|
|
|
45
|
+
logger.info "Request %-15s: min: %0.4f, max: %0.4f, avg: %0.4f, err: %d, verification err: %d" % [marker, row[:min], row[:max], average(row), row[:errors], row[:verification_errors]]
|
|
46
|
+
end
|
|
47
|
+
logger.info "Verify Error : #{Bench.verify_error}"
|
|
48
|
+
logger.info "Concurrency : #{@concurrency}"
|
|
49
|
+
logger.info "Iterations : #{@iterations}"
|
|
50
|
+
logger.info "Total Count : #{@total_count}"
|
|
51
|
+
logger.info "Total Time : #{@total_time}"
|
|
52
|
+
logger.info "Throughput(req/s) : #{@total_count / @total_time}"
|
|
53
|
+
logger.info "Throughput(req/min): #{(@total_count / @total_time) * 60.0}"
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
require 'faker'
|
|
2
|
+
require 'uuidtools'
|
|
3
|
+
|
|
4
|
+
module Bench
|
|
5
|
+
module TestData
|
|
6
|
+
def get_test_data(num=1000,generate=false)
|
|
7
|
+
file = File.join(File.dirname(__FILE__),'..',"testdata","#{num}-data.txt")
|
|
8
|
+
data = nil
|
|
9
|
+
if File.exists?(file) and not generate
|
|
10
|
+
data = open(file, 'r') {|f| Marshal.load(f)}
|
|
11
|
+
else
|
|
12
|
+
data = generate_fake_data(num)
|
|
13
|
+
f = File.new(file, 'w')
|
|
14
|
+
f.write Marshal.dump(data)
|
|
15
|
+
f.close
|
|
16
|
+
end
|
|
17
|
+
data
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
PREFIX = ["Account", "Administrative", "Advertising", "Assistant", "Banking", "Business Systems",
|
|
23
|
+
"Computer", "Distribution", "IT", "Electronics", "Environmental", "Financial", "General", "Head",
|
|
24
|
+
"Laboratory", "Maintenance", "Medical", "Production", "Quality Assurance", "Software", "Technical",
|
|
25
|
+
"Chief", "Senior"] unless defined? PREFIX
|
|
26
|
+
SUFFIX = ["Clerk", "Analyst", "Manager", "Supervisor", "Plant Manager", "Mechanic", "Technician", "Engineer",
|
|
27
|
+
"Director", "Superintendent", "Specialist", "Technologist", "Estimator", "Scientist", "Foreman", "Nurse",
|
|
28
|
+
"Worker", "Helper", "Intern", "Sales", "Mechanic", "Planner", "Recruiter", "Officer", "Superintendent",
|
|
29
|
+
"Vice President", "Buyer", "Production Supervisor", "Chef", "Accountant", "Executive"] unless defined? SUFFIX
|
|
30
|
+
|
|
31
|
+
def title
|
|
32
|
+
prefix = PREFIX[rand(PREFIX.length)]
|
|
33
|
+
suffix = SUFFIX[rand(SUFFIX.length)]
|
|
34
|
+
|
|
35
|
+
"#{prefix} #{suffix}"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def generate_fake_data(num=1000)
|
|
39
|
+
res = {}
|
|
40
|
+
num.times do |n|
|
|
41
|
+
mock_id = UUIDTools::UUID.random_create.to_s.gsub(/\-/,'')
|
|
42
|
+
res[mock_id] = {
|
|
43
|
+
"mock_id" => mock_id,
|
|
44
|
+
"FirstName" => Faker::Name.first_name,
|
|
45
|
+
"LastName" => Faker::Name.last_name,
|
|
46
|
+
"Email" => Faker::Internet.free_email,
|
|
47
|
+
"Company" => Faker::Company.name,
|
|
48
|
+
"JobTitle" => title,
|
|
49
|
+
"Phone1" => Faker::PhoneNumber.phone_number
|
|
50
|
+
}
|
|
51
|
+
end
|
|
52
|
+
res
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|