rhosync 2.0.8 → 2.0.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. data/CHANGELOG +9 -0
  2. data/Rakefile +1 -5
  3. data/doc/protocol.html +397 -156
  4. data/lib/rhosync/console/app/public/ThickBox.css +649 -0
  5. data/lib/rhosync/console/app/public/home.css +433 -0
  6. data/lib/rhosync/console/app/public/images/header_halo copy.jpg +0 -0
  7. data/lib/rhosync/console/app/public/images/header_halo.jpg +0 -0
  8. data/lib/rhosync/console/app/public/images/land_separator.gif +0 -0
  9. data/lib/rhosync/console/app/public/images/landing_header.jpg +0 -0
  10. data/lib/rhosync/console/app/public/images/logo_rhosync.png +0 -0
  11. data/lib/rhosync/console/app/public/images/rhomobile_rhohub_logo.png +0 -0
  12. data/lib/rhosync/console/app/public/images/tabs_separator.png +0 -0
  13. data/lib/rhosync/console/app/public/reset.css +76 -0
  14. data/lib/rhosync/console/app/public/style.css +2201 -0
  15. data/lib/rhosync/console/app/routes/auth.rb +1 -1
  16. data/lib/rhosync/console/app/routes/client.rb +1 -1
  17. data/lib/rhosync/console/app/routes/docs.rb +98 -55
  18. data/lib/rhosync/console/app/routes/home.rb +47 -8
  19. data/lib/rhosync/console/app/routes/timing.rb +26 -0
  20. data/lib/rhosync/console/app/routes/user.rb +58 -21
  21. data/lib/rhosync/console/app/views/client.erb +2 -2
  22. data/lib/rhosync/console/app/views/content.erb +14 -0
  23. data/lib/rhosync/console/app/views/docdata.erb +1 -1
  24. data/lib/rhosync/console/app/views/docs.erb +2 -2
  25. data/lib/rhosync/console/app/views/headermenu.erb +41 -0
  26. data/lib/rhosync/console/app/views/home.erb +22 -0
  27. data/lib/rhosync/console/app/views/index.erb +1 -1
  28. data/lib/rhosync/console/app/views/layout.erb +82 -7
  29. data/lib/rhosync/console/app/views/login.erb +26 -0
  30. data/lib/rhosync/console/app/views/newuser.erb +1 -1
  31. data/lib/rhosync/console/app/views/result.erb +1 -1
  32. data/lib/rhosync/console/app/views/rightboxlinks.erb +15 -0
  33. data/lib/rhosync/console/app/views/select_doc.erb +1 -3
  34. data/lib/rhosync/console/app/views/user.erb +3 -6
  35. data/lib/rhosync/console/app/views/users.erb +2 -4
  36. data/lib/rhosync/console/server.rb +6 -0
  37. data/lib/rhosync/jobs/bulk_data_job.rb +17 -4
  38. data/lib/rhosync/ping/android.rb +38 -0
  39. data/lib/rhosync/ping.rb +2 -1
  40. data/lib/rhosync/server/views/index.erb +3 -0
  41. data/lib/rhosync/server.rb +25 -6
  42. data/lib/rhosync/source_sync.rb +14 -6
  43. data/lib/rhosync/stats/middleware.rb +22 -0
  44. data/lib/rhosync/stats/record.rb +83 -0
  45. data/lib/rhosync/version.rb +1 -1
  46. data/lib/rhosync.rb +4 -2
  47. data/spec/ping/android_spec.rb +45 -0
  48. data/spec/rhosync_spec.rb +1 -0
  49. data/spec/server/server_spec.rb +8 -0
  50. data/spec/spec.opts +3 -0
  51. data/spec/spec_helper.rb +4 -3
  52. data/spec/stats/middleware_spec.rb +32 -0
  53. data/spec/stats/record_spec.rb +71 -0
  54. metadata +31 -7
  55. data/lib/rhosync/monitoring/record.rb +0 -28
  56. data/spec/monitoring/record_spec.rb +0 -21
@@ -7,5 +7,5 @@
7
7
  <%end%>
8
8
  </div>
9
9
  <div class='panel'>
10
- <a href='<%= @back_href%>' class='nav_button'>Back</a>
10
+ <a href='javascript:void(0);' onclick="loadXMLDoc('<%= @back_href%>','main_box');" class='nav_button'>Back</a>
11
11
  </div>
@@ -0,0 +1,15 @@
1
+ <!-- div, links[]{ :url, :title, :selected }> -->
2
+
3
+ <div id="right-box_links">
4
+ <ul class="right-box_links">
5
+ <% i=1 %>
6
+ <% links.each do |link| %>
7
+ <li><a id="link<%=i%>"
8
+ <%= 'class="selected"' if link[:selected] %>
9
+ onclick="javascript:loadXMLDoc('<%=link[:url]%>','<%= div %>');switch_tab(this.id); this.blur();"
10
+ href="javascript:void(0);"><%=link[:title]%></a>
11
+ </li>
12
+ <% i = i + 1 %>
13
+ <% end %>
14
+ </ul>
15
+ </div>
@@ -1,8 +1,6 @@
1
1
  <h1>Document <%= @dbkey%></h1>
2
2
  <%=show_errors%>
3
- <div class='panel'>
4
- <a href='<%= url('/')%>' class='nav_button'>Back</a>
5
- </div>
3
+
6
4
  <form action=<%= url('doc/select')%> method='GET'>
7
5
  <table>
8
6
  <tr>
@@ -1,8 +1,5 @@
1
1
  <h1>User: <%=params[:user_id]%></h1>
2
2
  <%=show_errors%>
3
- <div class="panel">
4
- <a href="<%=url('users')%>" class='nav_button'>Back</a>
5
- </div>
6
3
  <div class="panel">
7
4
  <a href='<%=url("user/delete?user_id=#{CGI.escape(params[:user_id])}")%>' class='nav_button'>Delete user</a>
8
5
  </div>
@@ -13,18 +10,18 @@
13
10
 
14
11
  [
15
12
  <%@sources.each_index do |i|%>
16
- <a href="<%=url("docs?source_id=#{@sources[i]}&user_id=#{CGI.escape(params[:user_id])}")%>"><%=i==0?'':','%>"<%=@sources[i]%>"</a>
13
+ <a href='javascript:void(0);' onclick="loadXMLDoc('<%=url("docs?source_id=#{@sources[i]}&user_id=#{CGI.escape(params[:user_id])}")%>','main_box');"><%=i==0?'':','%>"<%=@sources[i]%>"</a>
17
14
  <%end%>
18
15
  ]
19
16
 
20
17
  <h2>Registered Devices</h2>
21
18
 
22
- <a href="<%=url("device/create?user_id=#{CGI.escape(params[:user_id])}")%>" class='nav_button'>Create Device</a>
19
+ <a href="javascript:void(0);" onclick="loadXMLDoc('<%=url("device/create?user_id=#{CGI.escape(params[:user_id])}")%>','');loadXMLDoc('<%=url("user?user_id=#{CGI.escape(params[:user_id])}")%>','main_box');" class='nav_button'>Create Device</a>
23
20
 
24
21
  <div class="panel">
25
22
  [
26
23
  <%@devices.each_index do |i|%>
27
- <a href="<%=url("device?user_id=#{CGI.escape(params[:user_id])}&device_id=#{CGI.escape(@devices[i])}")%>">
24
+ <a href="javascript:void(0);" onclick="loadXMLDoc('<%=url("device?user_id=#{CGI.escape(params[:user_id])}&device_id=#{CGI.escape(@devices[i])}")%>','main_box');">
28
25
  <%=i==0?'':','%>"<%=@devices[i]%>"
29
26
  </a>
30
27
  <%end%>
@@ -1,6 +1,4 @@
1
- <h1>Users</h1>
2
- <a href="<%=url('/')%>" class='nav_button'>Back</a>
3
- <a href="<%=url('user/new')%>" class='nav_button'>Create User</a>
1
+ <a href="javascript:void(0);" onclick="loadXMLDoc('<%=url('user/new')%>','main_box');" class='nav_button'>Create User</a>
4
2
 
5
3
  <h2>Registered users</h2>
6
4
  <%if is_errors?%>
@@ -8,7 +6,7 @@
8
6
  <%else%>
9
7
  [
10
8
  <%@users.each_index do |i|%>
11
- <a href="<%=url("user?user_id=#{CGI.escape(@users[i])}")%>"><%=i==0?'':','%>"<%=@users[i]%>"</a>
9
+ <a href="javascript:void(0);" onclick="loadXMLDoc('<%=url("user?user_id=#{CGI.escape(@users[i])}")%>','main_box');"><%=i==0?'':','%>"<%=@users[i]%>"</a>
12
10
  <%end%>
13
11
  ]
14
12
  <%end%>
@@ -19,6 +19,12 @@ module RhosyncConsole
19
19
  set :public, RhosyncConsole::root_path("app","public")
20
20
  set :static, true
21
21
  use Rack::Session::Cookie
22
+ before do
23
+ headers['Expires'] = 'Sun, 19 Nov 1978 05:00:00 GMT'
24
+ headers['Cache-Control'] = 'no-store, no-cache, must-revalidate'
25
+ headers['Pramga'] = 'no-cache'
26
+ end
27
+
22
28
  end
23
29
  end
24
30
 
@@ -16,6 +16,7 @@ module Rhosync
16
16
  ts = Time.now.to_i.to_s
17
17
  create_sqlite_data_file(bulk_data,ts)
18
18
  timer = lap_timer('create_sqlite_data_file',timer)
19
+ log " bulk_data.dbfile : #{bulk_data.dbfile}"
19
20
  create_hsql_data_file(bulk_data,ts) if Rhosync.blackberry_bulk_sync
20
21
  lap_timer('create_hsql_data_file',timer)
21
22
  log "finished bulk data process"
@@ -54,13 +55,13 @@ module Rhosync
54
55
  data = source.get_data(:md)
55
56
  counter = {}
56
57
  columns,qm = [],[]
57
- create_table = ['object varchar']
58
+ create_table = ["\"object\" varchar"]
58
59
  schema = JSON.parse(source.schema)
59
60
 
60
61
  db.transaction do |database|
61
62
  # Create a table with columns specified by 'property' array in settings
62
63
  schema['property'].each do |key,value|
63
- create_table << "#{key} varchar default NULL"
64
+ create_table << "\"#{key}\" varchar default NULL"
64
65
  columns << key
65
66
  qm << '?'
66
67
  end
@@ -81,12 +82,24 @@ module Rhosync
81
82
 
82
83
  # Create indexes for specified columns in settings 'index'
83
84
  schema['index'].each do |key,value|
84
- database.execute("CREATE INDEX #{key} on #{source.name} (#{value});")
85
+ val2 = ""
86
+ value.split(',').each do |col|
87
+ val2 += ',' if val2.length() > 0
88
+ val2 += "\"#{col}\""
89
+ end
90
+
91
+ database.execute("CREATE INDEX #{key} on #{source.name} (#{val2});")
85
92
  end if schema['index']
86
93
 
87
94
  # Create unique indexes for specified columns in settings 'unique_index'
88
95
  schema['unique_index'].each do |key,value|
89
- database.execute("CREATE UNIQUE INDEX #{key} on #{source.name} (#{value});")
96
+ val2 = ""
97
+ value.split(',').each do |col|
98
+ val2 += ',' if val2.length() > 0
99
+ val2 += "\"#{col}\""
100
+ end
101
+
102
+ database.execute("CREATE UNIQUE INDEX #{key} on #{source.name} (#{val2});")
90
103
  end if schema['unique_index']
91
104
  end
92
105
 
@@ -0,0 +1,38 @@
1
+ require 'net/https'
2
+ require 'uri'
3
+ module Rhosync
4
+ class Android
5
+ def self.ping(params)
6
+ begin
7
+ settings = get_config(Rhosync.base_directory)[Rhosync.environment]
8
+ authtoken = settings[:authtoken]
9
+
10
+ url = URI.parse('https://android.apis.google.com/c2dm/send')
11
+
12
+ req = Net::HTTP::Post.new url.path, 'Authorization' => "GoogleLogin auth=#{authtoken}"
13
+ req.set_form_data c2d_message(params)
14
+
15
+ http = Net::HTTP.new(url.host, url.port)
16
+ http.use_ssl = true
17
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
18
+ res = http.request(req)
19
+
20
+ rescue Exception => error
21
+ log "Error while sending ping: #{error}"
22
+ raise error
23
+ end
24
+ end
25
+
26
+ def self.c2d_message(params)
27
+ data = {}
28
+ data['registration_id'] = params['device_pin']
29
+ data['collapse_key'] = (rand * 100000000).to_i.to_s
30
+ data['data.do_sync'] = params['sources'] ? params['sources'].join(',') : ''
31
+ data['data.alert'] = params['message'] if params['message']
32
+ data['data.vibrate'] = params['vibrate'] if params['vibrate']
33
+ data['data.sound'] = params['sound'] if params['sound']
34
+
35
+ data
36
+ end
37
+ end
38
+ end
data/lib/rhosync/ping.rb CHANGED
@@ -1,2 +1,3 @@
1
+ require 'rhosync/ping/android'
1
2
  require 'rhosync/ping/apple'
2
- require 'rhosync/ping/blackberry'
3
+ require 'rhosync/ping/blackberry'
@@ -1,5 +1,8 @@
1
1
  <html>
2
2
  <head>
3
+ <script type="text/javascript">
4
+ window.location="/console/";
5
+ </script>
3
6
  <title>Rhosync Server</title>
4
7
  </head>
5
8
  <body>
@@ -21,12 +21,12 @@ module Rhosync
21
21
  set :public, "#{libdir}/server/public"
22
22
  set :static, true
23
23
 
24
- set :secret, '<changeme>' unless defined? Server.secret
24
+ # default secret
25
+ @@secret = '<changeme>'
25
26
 
26
- use Rack::Session::Cookie, :key => 'rhosync_session',
27
- :expire_after => 31536000,
28
- :secret => Server.secret
29
-
27
+ # stats middleware disabled by default
28
+ @@stats = false
29
+
30
30
  # Setup route and mimetype for bulk data downloads
31
31
  # TODO: Figure out why "mime :data, 'application/octet-stream'" doesn't work
32
32
  Rack::Mime::MIME_TYPES['.data'] = 'application/octet-stream'
@@ -126,10 +126,29 @@ module Rhosync
126
126
  end
127
127
  end
128
128
  end
129
+
130
+ # hook into new so we can enable middleware
131
+ def self.new
132
+ if @@stats == true
133
+ use Rhosync::Stats::Middleware
134
+ Rhosync.stats = true
135
+ end
136
+ use Rack::Session::Cookie,
137
+ :key => 'rhosync_session',
138
+ :expire_after => 31536000,
139
+ :secret => @@secret
140
+ super
141
+ end
142
+
143
+ def self.set(option, value=self, &block)
144
+ @@stats = value if option == :stats and (value.is_a?(TrueClass) or value.is_a?(FalseClass))
145
+ @@secret = value if option == :secret and value.is_a?(String)
146
+ super
147
+ end
129
148
 
130
149
  def initialize
131
150
  # Whine about default session secret
132
- check_default_secret!(Server.secret)
151
+ check_default_secret!(@@secret)
133
152
  super
134
153
  end
135
154
 
@@ -11,15 +11,15 @@ module Rhosync
11
11
 
12
12
  # CUD Operations
13
13
  def create(client_id)
14
- _process_cud('create',client_id)
14
+ _measure_and_process_cud('create',client_id)
15
15
  end
16
16
 
17
17
  def update(client_id)
18
- _process_cud('update',client_id)
18
+ _measure_and_process_cud('update',client_id)
19
19
  end
20
20
 
21
21
  def delete(client_id)
22
- _process_cud('delete',client_id)
22
+ _measure_and_process_cud('delete',client_id)
23
23
  end
24
24
 
25
25
  # Read Operation; params are query arguments
@@ -60,9 +60,11 @@ module Rhosync
60
60
 
61
61
  def do_query(params=nil)
62
62
  @source.if_need_refresh do
63
- return if _auth_op('login') == false
64
- self.read(nil,params)
65
- _auth_op('logoff')
63
+ Stats::Record.update("source:query:#{@source.name}") do
64
+ return if _auth_op('login') == false
65
+ self.read(nil,params)
66
+ _auth_op('logoff')
67
+ end
66
68
  end
67
69
  end
68
70
 
@@ -143,6 +145,12 @@ module Rhosync
143
145
  dels[key] = value
144
146
  end
145
147
 
148
+ def _measure_and_process_cud(operation,client_id)
149
+ Stats::Record.update("source:#{operation}:#{@source.name}") do
150
+ _process_cud(operation,client_id)
151
+ end
152
+ end
153
+
146
154
  def _process_cud(operation,client_id)
147
155
  errors,links,deletes,creates,dels = {},{},{},{},{}
148
156
  client = Client.load(client_id,{:source_name => @source.name})
@@ -0,0 +1,22 @@
1
+ module Rhosync
2
+ module Stats
3
+ class Middleware
4
+ def initialize(app)
5
+ @app = app
6
+ end
7
+
8
+ def call(env)
9
+ start = Time.now.to_f
10
+ status, headers, body = @app.call(env)
11
+ finish = Time.now.to_f
12
+ metric = "http:#{env['REQUEST_METHOD']}:#{env['REQUEST_PATH']}"
13
+ source_id = env['rack.request.query_hash']["source_id"] if env['rack.request.query_hash']
14
+ metric << ":#{source_id}" if source_id
15
+ Record.add(metric,finish - start) do |counter,aggregate|
16
+ Record.save_average(counter,aggregate)
17
+ end
18
+ [status, headers, body]
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,83 @@
1
+ module Rhosync
2
+ module Stats
3
+ class Record
4
+ class << self
5
+
6
+ # Add a value to a metric. If zset already has a member,
7
+ # update the existing member with an incremented value by default.
8
+ # Also supports updating the value with a block (useful for averages)
9
+ def add(metric, value = 1)
10
+ start = Time.now.to_i
11
+ current, current_score = 0, start
12
+ range = Store.db.zrevrange(key(metric), 0, 0)
13
+ if !range.empty?
14
+ member = range[0]
15
+ m_current = member.split(':')[0]
16
+ m_current_score = Store.db.zscore(key(metric), member).to_i
17
+ if m_current_score > (start - resolution(metric))
18
+ Store.db.zrem(key(metric), member)
19
+ current, current_score = m_current, m_current_score
20
+ end
21
+ end
22
+ value = block_given? ? yield(current, value) : (current.to_i + value)
23
+ Store.db.zadd(key(metric), current_score, "#{value}:#{start}")
24
+ Store.db.zremrangebyscore(key(metric), 0, start - record_size(metric))
25
+ end
26
+
27
+ # Saves the accumulated average for a resolution in a metric
28
+ def save_average(current, value)
29
+ sum = value
30
+ if current.is_a?(String)
31
+ current,sum = current.split(',')
32
+ current = current.to_f
33
+ sum = sum.to_f+value
34
+ end
35
+ "#{current + 1},#{sum}"
36
+ end
37
+
38
+ def update(metric)
39
+ if Rhosync.stats
40
+ start = Time.now.to_f
41
+ # perform the operations
42
+ yield
43
+ finish = Time.now.to_f
44
+ add(metric, finish - start) do |counter, aggregate|
45
+ save_average(counter, aggregate)
46
+ end
47
+ else
48
+ yield
49
+ end
50
+ end
51
+
52
+ def reset(metric)
53
+ Store.db.del(key(metric))
54
+ end
55
+
56
+ def reset_all
57
+ Store.flash_data('stat:*')
58
+ end
59
+
60
+ # Returns the metric data, uses array indexing
61
+ def range(metric, start, finish = -1)
62
+ Store.db.zrange(key(metric), start, finish)
63
+ end
64
+
65
+ # Returns the resolution for a given metric, default 60 seconds
66
+ def resolution(metric)
67
+ resolution = Object.const_get("#{metric.upcase}_RECORD_RESOLUTION") rescue nil
68
+ resolution || 60 #=> 1 minute aggregate
69
+ end
70
+
71
+ # Returns the # of records to save for a given metric
72
+ def record_size(metric)
73
+ size = Object.const_get("#{metric.upcase}_RECORD_SIZE") rescue nil
74
+ size || 60 * 24 * 31 #=> 44640 minutes
75
+ end
76
+
77
+ def key(metric)
78
+ "stat:#{metric}"
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -1,3 +1,3 @@
1
1
  module Rhosync
2
- VERSION = '2.0.8'
2
+ VERSION = '2.0.9'
3
3
  end
data/lib/rhosync.rb CHANGED
@@ -21,7 +21,8 @@ require 'rhosync/source_sync'
21
21
  require 'rhosync/rho_indifferent_access'
22
22
  require 'rhosync/jobs/source_job'
23
23
  require 'rhosync/jobs/ping_job'
24
- require 'rhosync/monitoring/record'
24
+ require 'rhosync/stats/record'
25
+ require 'rhosync/stats/middleware'
25
26
  require 'rhosync/bulk_data'
26
27
 
27
28
  REDIS_URL = 'REDIS' unless defined? REDIS_URL
@@ -41,7 +42,7 @@ module Rhosync
41
42
  class << self
42
43
  attr_accessor :base_directory, :app_directory, :data_directory,
43
44
  :vendor_directory, :blackberry_bulk_sync, :redis, :environment,
44
- :log_disabled, :license, :bulk_sync_poll_interval
45
+ :log_disabled, :license, :bulk_sync_poll_interval, :stats
45
46
  end
46
47
 
47
48
  ### Begin Rhosync setup methods
@@ -70,6 +71,7 @@ module Rhosync
70
71
  Rhosync.blackberry_bulk_sync ||= false
71
72
  Rhosync.bulk_sync_poll_interval ||= 3600
72
73
  Rhosync.log_disabled ||= false
74
+ Rhosync.stats ||= false
73
75
  Rhosync.license = License.new
74
76
 
75
77
  check_and_add(File.join(Rhosync.app_directory,'sources'))
@@ -0,0 +1,45 @@
1
+ require File.join(File.dirname(__FILE__),'..','spec_helper')
2
+
3
+ describe "Ping Android" do
4
+ it_should_behave_like "SpecBootstrapHelper"
5
+ it_should_behave_like "SourceAdapterHelper"
6
+
7
+ before do
8
+ @params = {"device_pin" => @c.device_pin,
9
+ "sources" => [@s.name], "message" => 'hello world',
10
+ "vibrate" => '5', "badge" => '5', "sound" => 'hello.mp3'}
11
+ post = mock('post')
12
+ post.stub!(:new).and_return(post)
13
+ post.stub!(:set_form_data)
14
+ Net::HTTP::Post.stub!(:new).and_return(post)
15
+
16
+ @http = mock('http')
17
+ @http.stub!(:request)
18
+ @http.stub!(:use_ssl=)
19
+ @http.stub!(:verify_mode=)
20
+ @http.stub!(:start).and_yield(@http)
21
+ Net::HTTP.stub!(:new).and_return(@http)
22
+ end
23
+
24
+ it "should ping android" do
25
+ Android.ping(@params)
26
+ end
27
+
28
+ it "should ping android with connection error" do
29
+ error = 'Connection refused'
30
+ @http.stub!(:request).and_return { raise SocketError.new(error) }
31
+ Android.should_receive(:log).once.with("Error while sending ping: #{error}")
32
+ lambda { Android.ping(@params) }.should raise_error(SocketError,error)
33
+ end
34
+
35
+ it "should compute c2d_message" do
36
+ expected = {'registration_id' => @c.device_pin, 'collapse_key' => "RAND_KEY",
37
+ 'data.do_sync' => @s.name,
38
+ 'data.alert' => "hello world",
39
+ 'data.vibrate' => '5',
40
+ 'data.sound' => "hello.mp3"}
41
+ actual = Android.c2d_message(@params)
42
+ actual['collapse_key'] = "RAND_KEY" unless actual['collapse_key'].nil?
43
+ actual.should == expected
44
+ end
45
+ end
data/spec/rhosync_spec.rb CHANGED
@@ -16,6 +16,7 @@ describe "Rhosync" do
16
16
  Rhosync.blackberry_bulk_sync.should == false
17
17
  Rhosync.bulk_sync_poll_interval.should == 3600
18
18
  Rhosync.environment.should == :development
19
+ Rhosync.stats.should == false
19
20
  App.is_exist?(@test_app_name).should be_true
20
21
  end
21
22
 
@@ -57,6 +57,14 @@ describe "Server" do
57
57
  Rhosync::Server.secret.should == "secure!"
58
58
  end
59
59
 
60
+ it "should use Stats::Middleware if stats enabled" do
61
+ Rhosync::Server.enable :stats
62
+ Rhosync::Server.new
63
+ Rhosync.stats.should == true
64
+ Rhosync.stats = nil
65
+ Rhosync::Server.disable :stats
66
+ end
67
+
60
68
  it "should update session secret to default" do
61
69
  Rhosync::Server.set :secret, "<changeme>"
62
70
  Rhosync::Server.secret.should == "<changeme>"
data/spec/spec.opts ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ -fn
3
+ -b
data/spec/spec_helper.rb CHANGED
@@ -117,9 +117,9 @@ module TestHelpers
117
117
  db.execute("select source_id,name,sync_priority,partition,
118
118
  sync_type,source_attribs,metadata,blob_attribs,associations
119
119
  from sources where name='#{s.name}'").each do |row|
120
- return false if row[0] != s.source_id.to_s
120
+ return false if row[0].to_s != s.source_id.to_s
121
121
  return false if row[1] != s.name
122
- return false if row[2] != s.priority.to_s
122
+ return false if row[2].to_s != s.priority.to_s
123
123
  return false if row[3] != s.partition_type.to_s
124
124
  return false if row[4] != s.sync_type.to_s
125
125
  return false if row[5] != (s.schema ? "" : get_attrib_counter(data))
@@ -127,6 +127,7 @@ module TestHelpers
127
127
  return false if row[7] != s.blob_attribs
128
128
  return false if row[8] != s.has_many
129
129
  end
130
+
130
131
  data = json_clone(data)
131
132
  if s.schema
132
133
  schema = JSON.parse(s.schema)
@@ -145,7 +146,7 @@ module TestHelpers
145
146
  else
146
147
  db.execute("select * from object_values where source_id=#{s.source_id}").each do |row|
147
148
  object = data[row[2]]
148
- return false if object.nil? or object[row[1]] != row[3] or row[0] != s.source_id.to_s
149
+ return false if object.nil? or object[row[1]] != row[3] or row[0].to_s != s.source_id.to_s
149
150
  object.delete(row[1])
150
151
  data.delete(row[2]) if object.empty?
151
152
  end
@@ -0,0 +1,32 @@
1
+ require 'rhosync'
2
+ FOO_RECORD_RESOLUTION = 2
3
+ FOO_RECORD_SIZE = 8
4
+
5
+ include Rhosync
6
+ include Rhosync::Stats
7
+
8
+ describe "Middleware" do
9
+
10
+ before(:each) do
11
+ @now = 10.0
12
+ Store.db.flushdb
13
+ app = mock('app')
14
+ app.stub!(:call)
15
+ @middleware = Middleware.new(app)
16
+ end
17
+
18
+ it "should compute http average" do
19
+ Time.stub!(:now).and_return { @now += 0.3; @now }
20
+ env = {
21
+ 'rack.request.query_hash' => {
22
+ 'source_id' => 'SampleAdapter'
23
+ },
24
+ 'REQUEST_METHOD' => 'GET',
25
+ 'REQUEST_PATH' => '/application'
26
+ }
27
+ 10.times { @middleware.call(env) }
28
+ metric = 'http:GET:/application:SampleAdapter'
29
+ Record.key(metric).should == "stat:#{metric}"
30
+ Record.range(metric, 0, -1).should == ["10.0,3.0:19"]
31
+ end
32
+ end
@@ -0,0 +1,71 @@
1
+ require 'rhosync'
2
+ FOO_RECORD_RESOLUTION = 2
3
+ FOO_RECORD_SIZE = 8
4
+
5
+ include Rhosync
6
+ include Rhosync::Stats
7
+
8
+ describe "Record" do
9
+
10
+ before(:each) do
11
+ @now = 9
12
+ Store.db.flushdb
13
+ end
14
+
15
+ it "should add metric to the record and trim record size" do
16
+ Time.stub!(:now).and_return { @now += 1; @now }
17
+ 10.times { Record.add('foo') }
18
+ Store.db.zrange('stat:foo', 0, -1).should == ["2:13", "2:15", "2:17", "2:19"]
19
+ end
20
+
21
+ it "should add single record" do
22
+ Time.stub!(:now).and_return { @now += 1; @now }
23
+ Record.add('foo')
24
+ Store.db.zrange('stat:foo', 0, -1).should == ["1:10"]
25
+ end
26
+
27
+ it "should add absolute metric value" do
28
+ Time.stub!(:now).and_return { @now += 1; @now }
29
+ time = 0
30
+ 4.times do
31
+ Record.add('foo',time) do |current,value|
32
+ Record.save_average(current, value)
33
+ end
34
+ time += 1
35
+ end
36
+ Store.db.zrange('stat:foo', 0, -1).should == ["2.0,1.0:11", "2.0,5.0:13"]
37
+ end
38
+
39
+ it "should update metric" do
40
+ Rhosync.stats = true
41
+ Time.stub!(:now).and_return { @now += 1; @now }
42
+ 4.times do
43
+ Record.update('foo') do
44
+ # something interesting
45
+ end
46
+ end
47
+ Store.db.zrange('stat:foo', 0, -1).should == ["1,1.0:15", "1,1.0:18", "1,1.0:21"]
48
+ Rhosync.stats = nil
49
+ end
50
+
51
+ it "should get range of metric values" do
52
+ Time.stub!(:now).and_return { @now += 1; @now }
53
+ 10.times { Record.add('foo') }
54
+ Record.range('foo', 0, 1).should == ["2:13", "2:15"]
55
+ end
56
+
57
+ it "should reset metric" do
58
+ Time.stub!(:now).and_return { @now += 1; @now }
59
+ 10.times { Record.add('foo') }
60
+ Store.db.zrange('stat:foo', 0, -1).should == ["2:13", "2:15", "2:17", "2:19"]
61
+ Record.reset('foo')
62
+ Store.db.zrange('stat:foo', 0, -1).should == []
63
+ end
64
+
65
+ it "should reset all metrics" do
66
+ Record.add('foo')
67
+ Record.add('bar')
68
+ Record.reset_all
69
+ Store.db.keys('stat:*').should == []
70
+ end
71
+ end