rhosync 2.0.9 → 2.1.0.beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +9 -0
- data/Rakefile +1 -1
- data/bench/benchapp/sources/mock_adapter.rb +2 -2
- data/bench/benchapp/tmp/restart.txt +0 -0
- data/bench/spec/mock_adapter_spec.rb +1 -1
- data/lib/rhosync/api/stats.rb +21 -0
- data/lib/rhosync/bulk_data/bulk_data.rb +1 -1
- data/lib/rhosync/client.rb +10 -0
- data/lib/rhosync/console/app/public/home.css +9 -4
- data/lib/rhosync/console/app/public/images/foot_logo_rhosync.png +0 -0
- data/lib/rhosync/console/app/public/images/landing_header.jpg +0 -0
- data/lib/rhosync/console/app/public/jqplot/excanvas.min.js +35 -0
- data/lib/rhosync/console/app/public/jqplot/jqplot.barRenderer.min.js +34 -0
- data/lib/rhosync/console/app/public/jqplot/jqplot.canvasAxisLabelRenderer.js +187 -0
- data/lib/rhosync/console/app/public/jqplot/jqplot.canvasAxisTickRenderer.js +226 -0
- data/lib/rhosync/console/app/public/jqplot/jqplot.canvasTextRenderer.js +408 -0
- data/lib/rhosync/console/app/public/jqplot/jqplot.categoryAxisRenderer.min.js +34 -0
- data/lib/rhosync/console/app/public/jqplot/jqplot.cursor.js +952 -0
- data/lib/rhosync/console/app/public/jqplot/jqplot.dateAxisRenderer.js +313 -0
- data/lib/rhosync/console/app/public/jqplot/jqplot.dateAxisRenderer.min.js +34 -0
- data/lib/rhosync/console/app/public/jqplot/jqplot.pointLabels.min.js +34 -0
- data/lib/rhosync/console/app/public/jqplot/jquery-1.4.2.min.js +154 -0
- data/lib/rhosync/console/app/public/jqplot/jquery.jqplot.min.css +1 -0
- data/lib/rhosync/console/app/public/jqplot/jquery.jqplot.min.js +34 -0
- data/lib/rhosync/console/app/routes/timing.rb +223 -7
- data/lib/rhosync/console/app/views/content.erb +1 -1
- data/lib/rhosync/console/app/views/headermenu.erb +4 -4
- data/lib/rhosync/console/app/views/jqplot.erb +52 -0
- data/lib/rhosync/console/app/views/layout.erb +86 -11
- data/lib/rhosync/console/rhosync_api.rb +19 -0
- data/lib/rhosync/jobs/bulk_data_job.rb +2 -2
- data/lib/rhosync/stats/middleware.rb +4 -6
- data/lib/rhosync/stats/record.rb +51 -26
- data/lib/rhosync/store.rb +12 -1
- data/lib/rhosync/tasks.rb +4 -2
- data/lib/rhosync/user.rb +11 -1
- data/lib/rhosync/version.rb +2 -2
- data/lib/rhosync.rb +3 -3
- data/spec/api/rhosync_api_spec.rb +26 -0
- data/spec/api/stats_spec.rb +66 -0
- data/spec/client_spec.rb +40 -0
- data/spec/client_sync_spec.rb +14 -0
- data/spec/stats/middleware_spec.rb +11 -5
- data/spec/stats/record_spec.rb +30 -11
- data/spec/store_spec.rb +15 -1
- data/spec/user_spec.rb +44 -0
- metadata +32 -14
- data/doc/protocol.html +0 -2291
- data/doc/public/css/print.css +0 -29
- data/doc/public/css/screen.css +0 -257
- data/doc/public/css/style.css +0 -20
- data/lib/rhosync/console/app/public/images/header_halo copy.jpg +0 -0
@@ -9,7 +9,24 @@
|
|
9
9
|
<link rel="stylesheet" href="<%=url('home.css')%>" type="text/css" media="screen" />
|
10
10
|
<link rel="stylesheet" href="<%=url('style.css')%>" type="text/css" media="screen" />
|
11
11
|
<link rel="stylesheet" href="<%=url('ThickBox.css')%>" type="text/css" media="screen" />
|
12
|
+
|
13
|
+
<!--[if IE]><script language="javascript" type="text/javascript" src="<%=url('jqplot/excanvas.js')%>"></script><![endif]-->
|
14
|
+
<script language="javascript" type="text/javascript" src="<%=url('jqplot/jquery-1.4.2.min.js')%>"></script>
|
15
|
+
<script language="javascript" type="text/javascript" src="<%=url('jqplot/jquery.jqplot.min.js')%>"></script>
|
16
|
+
<script language="javascript" type="text/javascript" src="<%=url('jqplot/jqplot.categoryAxisRenderer.min.js')%>"></script>
|
17
|
+
<script language="javascript" type="text/javascript" src="<%=url('jqplot/jqplot.dateAxisRenderer.js')%>"></script>
|
18
|
+
<script language="javascript" type="text/javascript" src="<%=url('jqplot/jqplot.canvasTextRenderer.js')%>"></script>
|
19
|
+
<script language="javascript" type="text/javascript" src="<%=url('jqplot/jqplot.canvasAxisLabelRenderer.js')%>"></script>
|
20
|
+
<script language="javascript" type="text/javascript" src="<%=url('jqplot/jqplot.canvasAxisTickRenderer.js')%>"></script>
|
21
|
+
<script language="javascript" type="text/javascript" src="<%=url('jqplot/jqplot.cursor.js')%>"></script>
|
22
|
+
<!--<script language="javascript" type="text/javascript" src="<%=url('jqplot/jqplot.barRenderer.min.js')%>"></script>-->
|
23
|
+
<!--<script language="javascript" type="text/javascript" src="<%=url('jqplot/jqplot.pointLabels.min.js')%>"></script>-->
|
24
|
+
|
25
|
+
<link rel="stylesheet" type="text/css" href="<%=url('jqplot/jquery.jqplot.min.css')%>" />
|
26
|
+
|
12
27
|
<script type="text/javascript">
|
28
|
+
$.jqplot.config.enablePlugins = true;
|
29
|
+
|
13
30
|
|
14
31
|
function loadXMLDoc(url,id)
|
15
32
|
{
|
@@ -30,6 +47,7 @@
|
|
30
47
|
if (element != null)
|
31
48
|
{
|
32
49
|
element.innerHTML=xmlhttp.responseText;
|
50
|
+
parseScript(xmlhttp.responseText);
|
33
51
|
}
|
34
52
|
}
|
35
53
|
}
|
@@ -46,10 +64,41 @@
|
|
46
64
|
if(document.getElementById('link7') != null)document.getElementById('link7').className = "no_class";
|
47
65
|
document.getElementById(elem).className = "selected";
|
48
66
|
}
|
49
|
-
|
67
|
+
|
68
|
+
function parseScript(_source) {
|
69
|
+
var source = _source;
|
70
|
+
var scripts = new Array();
|
71
|
+
|
72
|
+
// Strip out tags
|
73
|
+
while(source.indexOf("<script") > -1 || source.indexOf("</script") > -1) {
|
74
|
+
var s = source.indexOf("<script");
|
75
|
+
var s_e = source.indexOf(">", s);
|
76
|
+
var e = source.indexOf("</script", s);
|
77
|
+
var e_e = source.indexOf(">", e);
|
78
|
+
|
79
|
+
// Add to scripts array
|
80
|
+
scripts.push(source.substring(s_e+1, e));
|
81
|
+
// Strip from source
|
82
|
+
source = source.substring(0, s) + source.substring(e_e+1);
|
83
|
+
}
|
84
|
+
|
85
|
+
// Loop through every script collected and eval it
|
86
|
+
for(var i=0; i<scripts.length; i++) {
|
87
|
+
try {
|
88
|
+
eval(scripts[i]);
|
89
|
+
}
|
90
|
+
catch(ex) {
|
91
|
+
// do what you want here when a script fails
|
92
|
+
}
|
93
|
+
}
|
94
|
+
|
95
|
+
// Return the cleaned source
|
96
|
+
return source;
|
97
|
+
}
|
50
98
|
|
51
99
|
</script>
|
52
100
|
|
101
|
+
|
53
102
|
</head>
|
54
103
|
<body>
|
55
104
|
<div class="container">
|
@@ -69,19 +118,45 @@
|
|
69
118
|
<div class="land_separator"></div>
|
70
119
|
</div><!--END header_landing -->
|
71
120
|
<div style="float:left">
|
72
|
-
|
73
|
-
|
74
|
-
handle_api_error("Can't get license information") do
|
75
|
-
license = RhosyncApi::get_license_info(session[:server],session[:token])
|
76
|
-
end
|
77
|
-
%>
|
78
|
-
<%="Licensed to #{license['licensee']}: #{license['available']}/#{license['seats']} devices available"%>
|
79
|
-
<%end%>
|
80
|
-
<br/>Rhosync v<%=Rhosync::VERSION%><br/>
|
121
|
+
|
122
|
+
<br/>
|
81
123
|
</div>
|
82
124
|
</div><!--END header -->
|
83
125
|
</div><!--END wrapper -->
|
84
126
|
</div><!-- END container -->
|
85
|
-
|
127
|
+
<div id="footer">
|
128
|
+
<div class="footer_content">
|
129
|
+
<div id="foot_lefts" class="foot_left">
|
130
|
+
<img src="/console/images/foot_logo_rhosync.png"></a>
|
131
|
+
<p>© 2010 <a href="http://www.rhomobile.com/">Rhomobile</a> All rights reserved.</p>
|
132
|
+
</div>
|
133
|
+
<div class="foot_right">
|
134
|
+
<ul class="ul_footer">
|
135
|
+
<%unless login_required %>
|
136
|
+
<% license = {}
|
137
|
+
handle_api_error("Can't get license information") do
|
138
|
+
license = RhosyncApi::get_license_info(session[:server],session[:token])
|
139
|
+
end
|
140
|
+
%>
|
141
|
+
<%="<li>Licensed to #{license['licensee']}</li><li>|</li><li> #{license['available']}/#{license['seats']} devices available</li>"%>
|
142
|
+
<%end%>
|
143
|
+
<li>|</li>
|
144
|
+
<li>Rhosync v<%=Rhosync::VERSION%></li>
|
145
|
+
<!-- <li><a href="http://app.rhohub.com">Home</a></li>
|
146
|
+
<li>|</li>
|
147
|
+
<li><a href="http://app.rhohub.com/how_to_use">How to Use</a></li>
|
148
|
+
<li>|</li>
|
149
|
+
<li><a href="http://app.rhohub.com/pricing">Pricing</a></li>
|
150
|
+
<li>|</li>
|
151
|
+
<li><a class="largea3" target="_blank" href="http://wiki.rhomobile.com/index.php/RhoHub">Docs</a></li>
|
152
|
+
<li>|</li>
|
153
|
+
<li><a href="http://app.rhohub.com/terms">Terms of Service</a></li>
|
154
|
+
<li>|</li>
|
155
|
+
<li><a href="http://www.twitter.com/rhohub">Status</a></li>
|
156
|
+
--> </ul>
|
157
|
+
</div>
|
158
|
+
<br class="clear">
|
159
|
+
</div>
|
160
|
+
</div>
|
86
161
|
</body>
|
87
162
|
</html>
|
@@ -34,6 +34,16 @@ module RhosyncApi
|
|
34
34
|
:content_type => :json)
|
35
35
|
end
|
36
36
|
end
|
37
|
+
|
38
|
+
def update_user(server,token,attributes)
|
39
|
+
if directcall?(server) and verify_token(token)
|
40
|
+
Server.update_user({:attributes => attributes},api_user(token))
|
41
|
+
else
|
42
|
+
RestClient.post("#{server}/api/update_user",
|
43
|
+
{:api_token => token,:attributes => attributes}.to_json,
|
44
|
+
:content_type => :json)
|
45
|
+
end
|
46
|
+
end
|
37
47
|
|
38
48
|
def delete_user(server,token,user_id)
|
39
49
|
if directcall?(server) and verify_token(token)
|
@@ -172,6 +182,15 @@ module RhosyncApi
|
|
172
182
|
end
|
173
183
|
end
|
174
184
|
|
185
|
+
def stats(server,token,params)
|
186
|
+
if directcall?(server) and verify_token(token)
|
187
|
+
Server.stats(params,api_user(token))
|
188
|
+
else
|
189
|
+
RestClient.post("#{server}/api/stats",
|
190
|
+
{:api_token => token}.merge!(params).to_json, :content_type => :json).body
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
175
194
|
private
|
176
195
|
|
177
196
|
# TODO: Kill this code when rest-client properly
|
@@ -16,7 +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 "
|
19
|
+
log "bulk_data.dbfile: #{bulk_data.dbfile}"
|
20
20
|
create_hsql_data_file(bulk_data,ts) if Rhosync.blackberry_bulk_sync
|
21
21
|
lap_timer('create_hsql_data_file',timer)
|
22
22
|
log "finished bulk data process"
|
@@ -177,7 +177,7 @@ module Rhosync
|
|
177
177
|
|
178
178
|
def self.compress(archive,file)
|
179
179
|
Zip::ZipFile.open(archive, 'w') do |zipfile|
|
180
|
-
zipfile.add(File.basename(file),file)
|
180
|
+
zipfile.add(URI.escape(File.basename(file)),file)
|
181
181
|
end
|
182
182
|
end
|
183
183
|
end
|
@@ -9,12 +9,10 @@ module Rhosync
|
|
9
9
|
start = Time.now.to_f
|
10
10
|
status, headers, body = @app.call(env)
|
11
11
|
finish = Time.now.to_f
|
12
|
-
metric = "http:#{env['REQUEST_METHOD']}:#{env['
|
13
|
-
|
14
|
-
metric << ":#{
|
15
|
-
Record.
|
16
|
-
Record.save_average(counter,aggregate)
|
17
|
-
end
|
12
|
+
metric = "http:#{env['REQUEST_METHOD']}:#{env['PATH_INFO']}"
|
13
|
+
source_name = env['rack.request.query_hash']["source_name"] if env['rack.request.query_hash']
|
14
|
+
metric << ":#{source_name}" if source_name
|
15
|
+
Record.save_average(metric,finish - start)
|
18
16
|
[status, headers, body]
|
19
17
|
end
|
20
18
|
end
|
data/lib/rhosync/stats/record.rb
CHANGED
@@ -6,33 +6,41 @@ module Rhosync
|
|
6
6
|
# Add a value to a metric. If zset already has a member,
|
7
7
|
# update the existing member with an incremented value by default.
|
8
8
|
# Also supports updating the value with a block (useful for averages)
|
9
|
-
def
|
10
|
-
start = Time.now.to_i
|
9
|
+
def set(metric, value = 0)
|
10
|
+
start = (Time.now.to_i / resolution(metric)) * resolution(metric)
|
11
11
|
current, current_score = 0, start
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
12
|
+
Store.lock(key(metric)) do
|
13
|
+
range = Store.db.zrevrange(key(metric), 0, 0)
|
14
|
+
if !range.empty?
|
15
|
+
member = range[0]
|
16
|
+
m_current = member.split(':')[0]
|
17
|
+
m_current_score = Store.db.zscore(key(metric), member).to_i
|
18
|
+
if m_current_score > (start - resolution(metric))
|
19
|
+
Store.db.zrem(key(metric), member)
|
20
|
+
current, current_score = m_current, m_current_score
|
21
|
+
end
|
20
22
|
end
|
23
|
+
value = block_given? ? yield(current, value) : value
|
24
|
+
Store.db.zadd(key(metric), current_score, "#{value}:#{start}")
|
25
|
+
Store.db.zremrangebyscore(key(metric), 0, start - record_size(metric))
|
21
26
|
end
|
22
|
-
|
23
|
-
|
24
|
-
|
27
|
+
end
|
28
|
+
|
29
|
+
def add(metric, value = 1)
|
30
|
+
set(metric,value) { |current,value| current.to_i + value }
|
25
31
|
end
|
26
32
|
|
27
33
|
# Saves the accumulated average for a resolution in a metric
|
28
|
-
def save_average(
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
34
|
+
def save_average(metric, value)
|
35
|
+
set(metric,value) do |current,value|
|
36
|
+
sum = value
|
37
|
+
if current.is_a?(String)
|
38
|
+
current,sum = current.split(',')
|
39
|
+
current = current.to_f
|
40
|
+
sum = sum.to_f+value
|
41
|
+
end
|
42
|
+
"#{current + 1},#{sum}"
|
43
|
+
end
|
36
44
|
end
|
37
45
|
|
38
46
|
def update(metric)
|
@@ -41,14 +49,16 @@ module Rhosync
|
|
41
49
|
# perform the operations
|
42
50
|
yield
|
43
51
|
finish = Time.now.to_f
|
44
|
-
|
45
|
-
save_average(counter, aggregate)
|
46
|
-
end
|
52
|
+
save_average(metric, finish - start)
|
47
53
|
else
|
48
54
|
yield
|
49
55
|
end
|
50
56
|
end
|
51
57
|
|
58
|
+
def keys(glob='*')
|
59
|
+
Store.db.keys(key(glob)).collect {|c| c[5..-1]}
|
60
|
+
end
|
61
|
+
|
52
62
|
def reset(metric)
|
53
63
|
Store.db.del(key(metric))
|
54
64
|
end
|
@@ -56,6 +66,16 @@ module Rhosync
|
|
56
66
|
def reset_all
|
57
67
|
Store.flash_data('stat:*')
|
58
68
|
end
|
69
|
+
|
70
|
+
# Returns simple string metric
|
71
|
+
def get_value(metric)
|
72
|
+
Store.get_value(key(metric))
|
73
|
+
end
|
74
|
+
|
75
|
+
# Sets a string metric
|
76
|
+
def set_value(metric, value)
|
77
|
+
Store.set_value(key(metric), value)
|
78
|
+
end
|
59
79
|
|
60
80
|
# Returns the metric data, uses array indexing
|
61
81
|
def range(metric, start, finish = -1)
|
@@ -64,16 +84,21 @@ module Rhosync
|
|
64
84
|
|
65
85
|
# Returns the resolution for a given metric, default 60 seconds
|
66
86
|
def resolution(metric)
|
67
|
-
resolution =
|
87
|
+
resolution = STATS_RECORD_RESOLUTION rescue nil
|
68
88
|
resolution || 60 #=> 1 minute aggregate
|
69
89
|
end
|
70
90
|
|
71
91
|
# Returns the # of records to save for a given metric
|
72
92
|
def record_size(metric)
|
73
|
-
size =
|
93
|
+
size = STATS_RECORD_SIZE rescue nil
|
74
94
|
size || 60 * 24 * 31 #=> 44640 minutes
|
75
95
|
end
|
76
96
|
|
97
|
+
# Returns redis object type for a record
|
98
|
+
def rtype(metric)
|
99
|
+
Store.db.type(key(metric))
|
100
|
+
end
|
101
|
+
|
77
102
|
def key(metric)
|
78
103
|
"stat:#{metric}"
|
79
104
|
end
|
data/lib/rhosync/store.rb
CHANGED
@@ -56,6 +56,14 @@ module Rhosync
|
|
56
56
|
def get_value(dockey)
|
57
57
|
@@db.get(dockey) if dockey
|
58
58
|
end
|
59
|
+
|
60
|
+
def incr(dockey)
|
61
|
+
@@db.incr(dockey)
|
62
|
+
end
|
63
|
+
|
64
|
+
def decr(dockey)
|
65
|
+
@@db.decr(dockey)
|
66
|
+
end
|
59
67
|
|
60
68
|
# Retrieves set for given dockey,source,user
|
61
69
|
def get_data(dockey,type=Hash)
|
@@ -179,6 +187,9 @@ module Rhosync
|
|
179
187
|
@@db.rename(srckey,dstkey) if @@db.exists(srckey)
|
180
188
|
end
|
181
189
|
|
190
|
+
alias_method :set_value, :put_value
|
191
|
+
alias_method :set_data, :put_data
|
192
|
+
|
182
193
|
private
|
183
194
|
def _get_redis(server=nil)
|
184
195
|
if ENV[REDIS_URL]
|
@@ -195,7 +206,7 @@ module Rhosync
|
|
195
206
|
end
|
196
207
|
|
197
208
|
def _lock_key(dockey)
|
198
|
-
"
|
209
|
+
"lock:#{dockey}"
|
199
210
|
end
|
200
211
|
|
201
212
|
def _is_reserved?(attrib,value) #:nodoc:
|
data/lib/rhosync/tasks.rb
CHANGED
@@ -159,12 +159,14 @@ namespace :rhosync do
|
|
159
159
|
system "stty echo"
|
160
160
|
exit
|
161
161
|
end
|
162
|
-
if new_pass ==
|
162
|
+
if new_pass == ''
|
163
|
+
puts "\nNew password can't be empty."
|
164
|
+
elsif new_pass == new_pass_confirm
|
163
165
|
puts ""
|
164
166
|
post("/api/update_user", {:app_name => $appname, :api_token => $token,
|
165
167
|
:attributes => {:new_password => new_pass}})
|
166
168
|
else
|
167
|
-
puts "\nNew password and
|
169
|
+
puts "\nNew password and confirmation must match."
|
168
170
|
end
|
169
171
|
end
|
170
172
|
|
data/lib/rhosync/user.rb
CHANGED
@@ -11,10 +11,15 @@ module Rhosync
|
|
11
11
|
set :clients, :string
|
12
12
|
field :admin, :int
|
13
13
|
field :token_id, :string
|
14
|
-
|
14
|
+
|
15
15
|
class << self
|
16
16
|
def create(fields={})
|
17
17
|
fields[:id] = fields[:login]
|
18
|
+
if Rhosync.stats
|
19
|
+
Rhosync::Stats::Record.set('users') { Store.incr('user:count') }
|
20
|
+
else
|
21
|
+
Store.incr('user:count')
|
22
|
+
end
|
18
23
|
super(fields)
|
19
24
|
end
|
20
25
|
|
@@ -41,6 +46,11 @@ module Rhosync
|
|
41
46
|
Client.load(client_id,{:source_name => '*'}).delete
|
42
47
|
end
|
43
48
|
self.token.delete if self.token
|
49
|
+
if Rhosync.stats
|
50
|
+
Rhosync::Stats::Record.set('users') { Store.decr('user:count') }
|
51
|
+
else
|
52
|
+
Store.decr('user:count')
|
53
|
+
end
|
44
54
|
super
|
45
55
|
end
|
46
56
|
|
data/lib/rhosync/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
1
|
module Rhosync
|
2
|
-
VERSION = '2.0.
|
3
|
-
end
|
2
|
+
VERSION = '2.1.0.beta.1'
|
3
|
+
end
|
data/lib/rhosync.rb
CHANGED
@@ -9,10 +9,12 @@ require 'rhosync/document'
|
|
9
9
|
require 'rhosync/lock_ops'
|
10
10
|
require 'rhosync/model'
|
11
11
|
require 'rhosync/source'
|
12
|
+
require 'rhosync/store'
|
13
|
+
require 'rhosync/stats/record'
|
14
|
+
require 'rhosync/stats/middleware'
|
12
15
|
require 'rhosync/user'
|
13
16
|
require 'rhosync/api_token'
|
14
17
|
require 'rhosync/app'
|
15
|
-
require 'rhosync/store'
|
16
18
|
require 'rhosync/client'
|
17
19
|
require 'rhosync/read_state'
|
18
20
|
require 'rhosync/client_sync'
|
@@ -21,8 +23,6 @@ require 'rhosync/source_sync'
|
|
21
23
|
require 'rhosync/rho_indifferent_access'
|
22
24
|
require 'rhosync/jobs/source_job'
|
23
25
|
require 'rhosync/jobs/ping_job'
|
24
|
-
require 'rhosync/stats/record'
|
25
|
-
require 'rhosync/stats/middleware'
|
26
26
|
require 'rhosync/bulk_data'
|
27
27
|
|
28
28
|
REDIS_URL = 'REDIS' unless defined? REDIS_URL
|
@@ -47,6 +47,17 @@ describe "RhosyncApi" do
|
|
47
47
|
RhosyncApi::create_user('some_url',@api_token,'testuser1','testpass1').should == "User created"
|
48
48
|
end
|
49
49
|
|
50
|
+
it "should update user using direct api call" do
|
51
|
+
RhosyncApi::update_user('',@api_token, {:new_password => '123'})
|
52
|
+
User.authenticate('rhoadmin','123').login.should == 'rhoadmin'
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should update user using rest call" do
|
56
|
+
RestClient.stub(:post)
|
57
|
+
RestClient.should_receive(:post).once
|
58
|
+
RhosyncApi::update_user('some_url',@api_token, {:new_password => '123'})
|
59
|
+
end
|
60
|
+
|
50
61
|
it "should delete user direct api call" do
|
51
62
|
RhosyncApi::create_user('',@api_token,'testuser1','testpass1').should == "User created"
|
52
63
|
User.is_exist?('testuser1').should == true
|
@@ -302,5 +313,20 @@ describe "RhosyncApi" do
|
|
302
313
|
RestClient.should_receive(:post).once
|
303
314
|
RhosyncApi::get_license_info('some_url',@api_token)
|
304
315
|
end
|
316
|
+
|
317
|
+
it "should get stats using direct api call" do
|
318
|
+
Rhosync.stats = true
|
319
|
+
Store.set_value('stat:foo','bar')
|
320
|
+
RhosyncApi::stats('',@api_token,:metric => 'foo').should == 'bar'
|
321
|
+
Rhosync.stats = false
|
322
|
+
end
|
323
|
+
|
324
|
+
it "should get stats using rest call" do
|
325
|
+
res = mock('HttpResponse')
|
326
|
+
res.stub!(:body).and_return('bar')
|
327
|
+
RestClient.stub(:post).and_return(res)
|
328
|
+
RestClient.should_receive(:post).once.and_return(res)
|
329
|
+
RhosyncApi::stats('some_url',@api_token,:metric => 'foo')
|
330
|
+
end
|
305
331
|
|
306
332
|
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__),'api_helper')
|
2
|
+
|
3
|
+
describe "RhosyncApiStats" do
|
4
|
+
it_should_behave_like "ApiHelper"
|
5
|
+
|
6
|
+
before(:each) do
|
7
|
+
Rhosync.stats = true
|
8
|
+
end
|
9
|
+
|
10
|
+
after(:each) do
|
11
|
+
Rhosync.stats = false
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should retrieve metric names" do
|
15
|
+
Store.set_value('stat:foo', '1')
|
16
|
+
Store.set_value('stat:bar', '2')
|
17
|
+
post "/api/stats", {
|
18
|
+
:api_token => @api_token,
|
19
|
+
:names => '*'
|
20
|
+
}
|
21
|
+
last_response.should be_ok
|
22
|
+
JSON.parse(last_response.body).sort.should == ['bar', 'foo']
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should retrieve range metric" do
|
26
|
+
Store.db.zadd('stat:foo', 2, "1:2")
|
27
|
+
Store.db.zadd('stat:foo', 3, "1:3")
|
28
|
+
post "/api/stats", {
|
29
|
+
:api_token => @api_token,
|
30
|
+
:metric => 'foo',
|
31
|
+
:start => 0,
|
32
|
+
:finish => -1
|
33
|
+
}
|
34
|
+
last_response.should be_ok
|
35
|
+
JSON.parse(last_response.body).should == ["1:2", "1:3"]
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should retrieve string metric" do
|
39
|
+
Store.db.set('stat:foo', 'bar')
|
40
|
+
post "/api/stats", {
|
41
|
+
:api_token => @api_token,
|
42
|
+
:metric => 'foo'
|
43
|
+
}
|
44
|
+
last_response.should be_ok
|
45
|
+
last_response.body.should == 'bar'
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should raise error on unknown metric" do
|
49
|
+
post "/api/stats", {
|
50
|
+
:api_token => @api_token,
|
51
|
+
:metric => 'foo'
|
52
|
+
}
|
53
|
+
last_response.status.should == 404
|
54
|
+
last_response.body.should == 'Unknown metric'
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should raise error if stats not enabled" do
|
58
|
+
Rhosync.stats = false
|
59
|
+
post "/api/stats", {
|
60
|
+
:api_token => @api_token,
|
61
|
+
:metric => 'foo'
|
62
|
+
}
|
63
|
+
last_response.status.should == 500
|
64
|
+
last_response.body.should == 'Stats not enabled'
|
65
|
+
end
|
66
|
+
end
|
data/spec/client_spec.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__),'spec_helper')
|
2
2
|
|
3
|
+
STATS_RECORD_RESOLUTION = 2 unless defined? STATS_RECORD_RESOLUTION
|
4
|
+
STATS_RECORD_SIZE = 8 unless defined? STATS_RECORD_SIZE
|
5
|
+
|
3
6
|
describe "Client" do
|
4
7
|
it_should_behave_like "SpecBootstrapHelper"
|
5
8
|
it_should_behave_like "SourceAdapterHelper"
|
@@ -16,6 +19,7 @@ describe "Client" do
|
|
16
19
|
end
|
17
20
|
|
18
21
|
it "should create client with user_id" do
|
22
|
+
Store.get_value('client:count').should == "1"
|
19
23
|
@c.id.length.should == 32
|
20
24
|
@c.user_id.should == @c_fields[:user_id]
|
21
25
|
@u.clients.members.should == [@c.id]
|
@@ -38,6 +42,7 @@ describe "Client" do
|
|
38
42
|
it "should free seat when client is deleted" do
|
39
43
|
current = Store.get_value(License::CLIENT_DOCKEY).to_i
|
40
44
|
@c.delete
|
45
|
+
Store.get_value('client:count').should == '0'
|
41
46
|
Store.get_value(License::CLIENT_DOCKEY).to_i.should == current - 1
|
42
47
|
end
|
43
48
|
|
@@ -55,4 +60,39 @@ describe "Client" do
|
|
55
60
|
verify_result(@c.docname(:cd) => @data,
|
56
61
|
@s.docname(:md_copy) => @data)
|
57
62
|
end
|
63
|
+
|
64
|
+
describe "Client Stats" do
|
65
|
+
|
66
|
+
before(:each) do
|
67
|
+
Rhosync::Stats::Record.reset('clients')
|
68
|
+
end
|
69
|
+
|
70
|
+
after(:each) do
|
71
|
+
Rhosync::Stats::Record.reset('clients')
|
72
|
+
end
|
73
|
+
|
74
|
+
after(:all) do
|
75
|
+
Store.flash_data('stat:clients*')
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should increment clients stats on create" do
|
79
|
+
Time.stub!(:now).and_return(10)
|
80
|
+
Rhosync.stats = true
|
81
|
+
Client.create(@c_fields,{:source_name => @s_fields[:name]})
|
82
|
+
Rhosync::Stats::Record.range('clients',0,-1).should == ["2:10"]
|
83
|
+
Store.get_value('client:count').should == "2"
|
84
|
+
Rhosync.stats = false
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should decrement clients stats on delete" do
|
88
|
+
Time.stub!(:now).and_return(10)
|
89
|
+
Rhosync.stats = true
|
90
|
+
c = Client.create(@c_fields,{:source_name => @s_fields[:name]})
|
91
|
+
Rhosync::Stats::Record.range('clients',0,-1).should == ["2:10"]
|
92
|
+
c.delete
|
93
|
+
Rhosync::Stats::Record.range('clients',0,-1).should == ["1:10"]
|
94
|
+
Store.get_value('client:count').should == "1"
|
95
|
+
Rhosync.stats = false
|
96
|
+
end
|
97
|
+
end
|
58
98
|
end
|
data/spec/client_sync_spec.rb
CHANGED
@@ -444,6 +444,20 @@ describe "ClientSync" do
|
|
444
444
|
"source:#{@a_fields[:name]}:#{@u_fields[:login]}:#{@s_fields[:name]}:md_copy" => @data)
|
445
445
|
end
|
446
446
|
|
447
|
+
it "should escape bulk data url" do
|
448
|
+
name = 'a b'
|
449
|
+
data = BulkData.create(:name => bulk_data_docname(@a.id,name),
|
450
|
+
:state => :inprogress,
|
451
|
+
:app_id => @a.id,
|
452
|
+
:user_id => name,
|
453
|
+
:sources => [@s_fields[:name]])
|
454
|
+
puts "data: #{data.inspect}"
|
455
|
+
BulkDataJob.perform("data_name" => bulk_data_docname(@a.id,name))
|
456
|
+
data = BulkData.load(bulk_data_docname(@a.id,name))
|
457
|
+
data.url.should match /a%20b/
|
458
|
+
data.delete
|
459
|
+
end
|
460
|
+
|
447
461
|
it "should return bulk data url for completed bulk data app partition" do
|
448
462
|
set_state('test_db_storage' => @data)
|
449
463
|
@s.partition = :app
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'rhosync'
|
2
|
-
|
3
|
-
|
2
|
+
STATS_RECORD_RESOLUTION = 2 unless defined? STATS_RECORD_RESOLUTION
|
3
|
+
STATS_RECORD_SIZE = 8 unless defined? STATS_RECORD_SIZE
|
4
4
|
|
5
5
|
include Rhosync
|
6
6
|
include Rhosync::Stats
|
@@ -13,20 +13,26 @@ describe "Middleware" do
|
|
13
13
|
app = mock('app')
|
14
14
|
app.stub!(:call)
|
15
15
|
@middleware = Middleware.new(app)
|
16
|
+
Store.stub!(:lock).and_yield
|
16
17
|
end
|
17
18
|
|
18
19
|
it "should compute http average" do
|
19
20
|
Time.stub!(:now).and_return { @now += 0.3; @now }
|
20
21
|
env = {
|
21
22
|
'rack.request.query_hash' => {
|
22
|
-
'
|
23
|
+
'source_name' => 'SampleAdapter'
|
23
24
|
},
|
24
25
|
'REQUEST_METHOD' => 'GET',
|
25
|
-
'
|
26
|
+
'PATH_INFO' => '/application'
|
26
27
|
}
|
27
28
|
10.times { @middleware.call(env) }
|
28
29
|
metric = 'http:GET:/application:SampleAdapter'
|
29
30
|
Record.key(metric).should == "stat:#{metric}"
|
30
|
-
Record.range(metric, 0, -1).should == [
|
31
|
+
Record.range(metric, 0, -1).should == [
|
32
|
+
"2.0,0.600000000000002:12",
|
33
|
+
"2.0,0.600000000000002:14",
|
34
|
+
"2.0,0.600000000000002:16",
|
35
|
+
"2.0,0.600000000000002:18"
|
36
|
+
]
|
31
37
|
end
|
32
38
|
end
|