multiforecast-client 0.62.0.2

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.
@@ -0,0 +1,326 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require 'growthforecast-client'
3
+
4
+ module MultiForecast
5
+ class Error < StandardError; end
6
+ class NotFound < Error; end
7
+ class AlreadyExists < Error; end
8
+
9
+ class Client
10
+ include ::MultiForecast::ConversionRule
11
+ attr_accessor :clients
12
+ attr_accessor :debug_dev
13
+ attr_accessor :short_metrics
14
+
15
+ # @param [Hash] opts
16
+ # [Hash] mapping: Mapping rules from `path` to GrowthForecast's `base_uri`.
17
+ def initialize(opts = {})
18
+ @mapping = opts['mapping'] || { '' => 'http://localhost:5125' }
19
+ @short_metrics = opts['short_metrics'] || true
20
+
21
+ @clients = {}
22
+ @base_uris = {}
23
+ @mapping.each do |path, base_uri|
24
+ if base_uri.kind_of?(Hash)
25
+ base_uri = uri['in_uri']
26
+ out_uri = uri['out_uri']
27
+ end
28
+ @clients[path] = GrowthForecast::Client.new(base_uri)
29
+ @base_uris[path] = out_uri || base_uri
30
+ end
31
+ end
32
+
33
+ # set the `debug_dev` attribute of HTTPClient
34
+ # @param [IO] debug_dev such as STDOUT
35
+ def debug_dev=(debug_dev)
36
+ @debug_dev = debug_dev
37
+ @clients.each {|c| c.debug_dev = debug_dev }
38
+ end
39
+
40
+ def clients(base_path = nil)
41
+ base_path.nil? ? @clients.values : @clients.values_at(*ids(base_path)).compact
42
+ end
43
+
44
+ def client(path)
45
+ @last_client = @clients[id(path)]
46
+ end
47
+
48
+ def last_client
49
+ @last_client
50
+ end
51
+
52
+ def last_response
53
+ @last_client.last_response
54
+ end
55
+
56
+ # GET the JSON API
57
+ # @param [String] path
58
+ # @return [Hash] response body
59
+ def get_json(path)
60
+ client(path).get_json(path)
61
+ end
62
+
63
+ # POST the JSON API
64
+ # @param [String] path
65
+ # @param [Hash] data
66
+ # @return [Hash] response body
67
+ def post_json(path, data = {})
68
+ client(path).post_json(path, data)
69
+ end
70
+
71
+ # POST the non-JSON API
72
+ # @param [String] path
73
+ # @param [Hash] data
74
+ # @return [String] response body
75
+ def post_query(path, data = {})
76
+ client(path).post_query(path, data)
77
+ end
78
+
79
+ # Get the list of graphs, /json/list/graph
80
+ # @return [Hash] list of graphs
81
+ # @example
82
+ # [
83
+ # {"base_uri"=>"xxxxx",
84
+ # "service_name"=>"mbclient",
85
+ # "section_name"=>"mbclient",
86
+ # "graph_name"=>"test%2Fhostname%2F%3C2sec_count",
87
+ # "path"=>"test/hostname/<2sec_count",
88
+ # "id"=>4},
89
+ # {"base_uri"=>"xxxxx",
90
+ # "service_name"=>"mbclient",
91
+ # "section_name"=>"mbclient",
92
+ # "graph_name"=>"test%2Fhostname%2F%3C1sec_count",
93
+ # "path"=>"test/hostname/<1sec_count",
94
+ # "id"=>3},
95
+ # ]
96
+ def list_graph(base_path = nil)
97
+ clients(base_path).inject([]) do |ret, client|
98
+ graphs = []
99
+ client.list_graph.each do |graph|
100
+ graph['base_uri'] = client.base_uri
101
+ graph['path'] = path(graph['service_name'], graph['section_name'], graph['graph_name'])
102
+ graphs << graph if base_path.nil? or graph['path'].index(base_path) == 0
103
+ end
104
+ ret = ret + graphs
105
+ end
106
+ end
107
+
108
+ # Get the propety of a graph, GET /api/:path
109
+ # @param [String] path
110
+ # @return [Hash] the graph property
111
+ # @example
112
+ #{
113
+ # "base_uri" => "xxxxxx",
114
+ # "path" => "test/hostname/<4sec_count",
115
+ # "service_name"=>"mbclient",
116
+ # "section_name"=>"mbclient",
117
+ # "graph_name"=>"test%2Fhostname%2F%3C4sec_count",
118
+ # "number"=>1,
119
+ # "llimit"=>-1000000000,
120
+ # "mode"=>"gauge",
121
+ # "stype"=>"AREA",
122
+ # "adjustval"=>"1",
123
+ # "meta"=>"",
124
+ # "gmode"=>"gauge",
125
+ # "color"=>"#cc6633",
126
+ # "created_at"=>"2013/02/02 00:41:11",
127
+ # "ulimit"=>1000000000,
128
+ # "id"=>21,
129
+ # "description"=>"",
130
+ # "sulimit"=>100000,
131
+ # "unit"=>"",
132
+ # "sort"=>0,
133
+ # "updated_at"=>"2013/02/02 02:32:10",
134
+ # "adjust"=>"*",
135
+ # "type"=>"AREA",
136
+ # "sllimit"=>-100000,
137
+ # "md5"=>"3c59dc048e8850243be8079a5c74d079"}
138
+ def get_graph(path)
139
+ client(path).get_graph(service_name(path), section_name(path), graph_name(path)).tap do |graph|
140
+ graph['base_uri'] = client(path).base_uri
141
+ graph['path'] = path
142
+ end
143
+ end
144
+
145
+ # Post parameters to a graph, POST /api/:path
146
+ # @param [String] path
147
+ # @param [Hash] params The POST parameters. See #get_graph
148
+ def post_graph(path, params)
149
+ client(path).post_graph(service_name(path), section_name(path), graph_name(path), params)
150
+ end
151
+
152
+ # Delete a graph, POST /delete/:path
153
+ # @param [String] path
154
+ def delete_graph(path)
155
+ client(path).delete_graph(service_name(path), section_name(path), graph_name(path))
156
+ end
157
+
158
+ # Update the property of a graph, /json/edit/graph/:id
159
+ # @param [String] path
160
+ # @param [Hash] params
161
+ # All of parameters given by #get_graph are available except `number` and `mode`.
162
+ # @return [Hash] error response
163
+ # @example
164
+ # {"error"=>0} #=> Success
165
+ # {"error"=>1} #=> Error
166
+ def edit_graph(path, params)
167
+ client(path).edit_graph(service_name(path), section_name(path), graph_name(path), params)
168
+ end
169
+
170
+ # Get the list of complex graphs, /json/list/complex
171
+ # @return [Hash] list of complex graphs
172
+ # @example
173
+ # [
174
+ # {"base_uri"=>"xxxxx",
175
+ # "path"=>"test/hostname/<2sec_count",
176
+ # "service_name"=>"mbclient",
177
+ # "section_name"=>"mbclient",
178
+ # "graph_name"=>"test%2Fhostname%2F%3C2sec_count",
179
+ # "id"=>4},
180
+ # {"base_uri"=>"xxxxx",
181
+ # "path"=>"test/hostname/<1sec_count",
182
+ # "service_name"=>"mbclient",
183
+ # "section_name"=>"mbclient",
184
+ # "graph_name"=>"test%2Fhostname%2F%3C1sec_count",
185
+ # "id"=>3},
186
+ # ]
187
+ def list_complex(base_path = nil)
188
+ clients(base_path).inject([]) do |ret, client|
189
+ graphs = []
190
+ client.list_complex.each do |graph|
191
+ graph['base_uri'] = client.base_uri
192
+ graph['path'] = path(graph['service_name'], graph['section_name'], graph['graph_name'])
193
+ graphs << graph if base_path.nil? or graph['path'].index(base_path) == 0
194
+ end
195
+ ret = ret + graphs
196
+ end
197
+ end
198
+
199
+ # Create a complex graph
200
+ #
201
+ # @param [Array] from_graphs Array of graph properties whose keys are
202
+ # ["path", "gmode", "stack", "type"]
203
+ # @param [Hash] to_complex Property of Complex Graph, whose keys are like
204
+ # ["path", "description", "sort"]
205
+ def create_complex(from_graphs, to_complex)
206
+ from_graphs = from_graphs.dup
207
+ to_complex = to_complex.dup
208
+
209
+ from_graphs.each do |from_graph|
210
+ from_graph['service_name'] = service_name(from_graph['path'])
211
+ from_graph['section_name'] = section_name(from_graph['path'])
212
+ from_graph['graph_name'] = graph_name(from_graph['path'])
213
+ from_graph.delete('path')
214
+ from_graph.delete('base_uri')
215
+ end
216
+
217
+ to_complex['service_name'] = service_name(to_complex['path'])
218
+ to_complex['section_name'] = section_name(to_complex['path'])
219
+ to_complex['graph_name'] = graph_name(to_complex['path'])
220
+ path = to_complex.delete('path')
221
+
222
+ # NOTE: FROM_GRAPHS AND TO _COMPLEX MUST BE THE SAME GF SERVER
223
+ client(path).create_complex(from_graphs, to_complex)
224
+ end
225
+
226
+ # Get a complex graph
227
+ #
228
+ # @param [String] path
229
+ # @return [Hash] the graph property
230
+ # @example
231
+ # {"number"=>0,
232
+ # "complex"=>true,
233
+ # "created_at"=>"2013/05/20 15:08:28",
234
+ # "service_name"=>"app name",
235
+ # "section_name"=>"host name",
236
+ # "id"=>18,
237
+ # "graph_name"=>"complex graph test",
238
+ # "data"=>
239
+ # [{"gmode"=>"gauge", "stack"=>false, "type"=>"AREA", "graph_id"=>218},
240
+ # {"gmode"=>"gauge", "stack"=>true, "type"=>"AREA", "graph_id"=>217}],
241
+ # "sumup"=>false,
242
+ # "description"=>"complex graph test",
243
+ # "sort"=>10,
244
+ # "updated_at"=>"2013/05/20 15:08:28"}
245
+ def get_complex(path)
246
+ client(path).get_complex(service_name(path), section_name(path), graph_name(path)).tap do |graph|
247
+ graph['base_uri'] = client(path).base_uri
248
+ graph['path'] = path
249
+ end
250
+ end
251
+
252
+ # Delete a complex graph
253
+ #
254
+ # @param [String] path
255
+ # @return [Hash] error response
256
+ # @example
257
+ # {"error"=>0} #=> Success
258
+ # {"error"=>1} #=> Error
259
+ def delete_complex(path)
260
+ client(path).delete_complex(service_name(path), section_name(path), graph_name(path))
261
+ end
262
+
263
+ # Get graph image uri
264
+ #
265
+ # @param [String] path
266
+ # @param [Hash] params for the query string
267
+ # t [String] the time unit such as 'h' (an hour), '4h' (4 hours), '8h', 'n' (half day), 'd' (a day), '3d', 'w', (a week), 'm' (a month), 'y' (a year).
268
+ # Also, 'sh' 's4h' 's8h', 'sn', 'sd', 's3d' for graphs generated by short period GF worker.
269
+ # Also, this parameter is overrided with 'c' or 'sc' when `from` parameter is set.
270
+ # from [String|Time] the time period to show 'from'. String describing a time, or a Time object
271
+ # to [String|Time] the time period to show 'to'. String describing a time, or a Time Object
272
+ # width [String] the widh of image to show
273
+ # height [String] the height of image to show
274
+ # @return [Hash] error response
275
+ # @example
276
+ def get_graph_uri(path, params = {})
277
+ params = preprocess_time_params(params) if params
278
+ "#{@base_uris[id(path)]}/graph/#{CGI.escape(service_name(path))}/#{CGI.escape(section_name(path))}/#{CGI.escape(graph_name(path))}?#{query_string(params)}"
279
+ end
280
+
281
+ # Get complex graph image uri
282
+ #
283
+ # @param [String] path
284
+ # @param [Hash] params for the query string
285
+ # t [String] the time unit such as 'h' (an hour), '4h' (4 hours), '8h', 'n' (half day), 'd' (a day), '3d', 'w', (a week), 'm' (a month), 'y' (a year).
286
+ # Also, 'sh' 's4h' 's8h', 'sn', 'sd', 's3d' for graphs generated by short period GF worker.
287
+ # Also, this parameter is overrided with 'c' or 'sc' when `from` parameter is set.
288
+ # from [String|Time] the time period to show 'from'. String describing a time, or a Time object
289
+ # to [String|Time] the time period to show 'to'. String describing a time, or a Time Object
290
+ # width [String] the widh of image to show
291
+ # height [String] the height of image to show
292
+ # @return [Hash] error response
293
+ # @example
294
+ def get_complex_uri(path, params = {})
295
+ params = preprocess_time_params(params) if params
296
+ "#{@base_uris[id(path)]}/complex/graph/#{CGI.escape(service_name(path))}/#{CGI.escape(section_name(path))}/#{CGI.escape(graph_name(path))}?#{query_string(params)}"
297
+ end
298
+
299
+ # process the time params (from and to)
300
+ def preprocess_time_params(params)
301
+ params = params.dup
302
+ params['from'] = Time.parse(params['from']) if params['from'].kind_of?(String)
303
+ params['to'] = Time.parse(params['to']) if params['to'].kind_of?(String)
304
+ if params['from'] and params['to']
305
+ # if from is more future than 3 days ago, use 'sc' (short period time worker)
306
+ params['t'] = (@short_metrics && params['from'] > Time.now - 60 * 60 * 24 * 3) ? 'sc' : 'c'
307
+ params['from'] = params['from'].strftime("%F %T %z") # format is determined
308
+ params['to'] = params['to'].strftime("%F %T %z")
309
+ end
310
+ params
311
+ end
312
+
313
+ private
314
+
315
+ # build URI query string
316
+ #
317
+ # @param [Hash] param
318
+ # @return [String] query string
319
+ # @example
320
+ def query_string(params)
321
+ return '' if params.nil?
322
+ params.keys.collect{|key| "#{URI.escape(key.to_s)}=#{URI.escape(params[key].to_s)}" }.join('&')
323
+ end
324
+ end
325
+ end
326
+
@@ -0,0 +1,42 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require 'cgi'
3
+
4
+ module MultiForecast
5
+ module ConversionRule
6
+ def service_name(path)
7
+ return path.split('/')[0] if path.count('/') == 2
8
+ 'multiforecast'
9
+ end
10
+
11
+ def section_name(path)
12
+ return path.split('/')[1] if path.count('/') == 2
13
+ # + => '%20' is to avoid GF (Kossy?) bug
14
+ # . => '%2E' because a/./b is recognized as a/b as URL
15
+ CGI.escape(File.dirname(path)).gsub('+', '%20').gsub('.', '%2E')
16
+ end
17
+
18
+ def graph_name(path)
19
+ File.basename(path)
20
+ end
21
+
22
+ def path(service_name, section_name, graph_name)
23
+ return "#{service_name}/#{section_name}/#{graph_name}" unless service_name == "multiforecast"
24
+ dirname = CGI.unescape(section_name)
25
+ basename = graph_name
26
+ dirname == "." ? basename : "#{dirname}/#{basename}"
27
+ end
28
+
29
+ def id(path)
30
+ @mapping.each do |base_path, base_uri|
31
+ return base_path if path.index(base_path) == 0
32
+ end
33
+ return @mapping.keys.first
34
+ end
35
+
36
+ def ids(path)
37
+ @mapping.map do |base_path, base_uri|
38
+ base_path if path.index(base_path) == 0
39
+ end.compact
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,163 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ base_uri = 'http://localhost:5125'
4
+
5
+ shared_context "stub_list_graph" do
6
+ def list_graph_example
7
+ [
8
+ {"gfuri"=>'http://localhost:5125',
9
+ "path"=>"app name/host name/<1sec count",
10
+ "service_name"=>"multiforecast",
11
+ "section_name"=>"app%20name%2Fhost%20name",
12
+ "graph_name"=>"<1sec count",
13
+ "id"=>1},
14
+ {"gfuri"=>'http://localhost:5125',
15
+ "path"=>"app name/host name/<2sec count",
16
+ "service_name"=>"multiforecast",
17
+ "section_name"=>"app+name%2Fhost+name",
18
+ "graph_name"=>"<2sec count",
19
+ "id"=>2},
20
+ ]
21
+ end
22
+
23
+ proc = Proc.new do
24
+ # WebMock.allow_net_connect!
25
+ stub_request(:get, "#{base_uri}/json/list/graph").to_return(:status => 200, :body => list_graph_example.to_json)
26
+ end
27
+ before(:each, &proc)
28
+ end
29
+
30
+ shared_context "stub_get_graph" do
31
+ def graph_example
32
+ {
33
+ "gfuri"=>"http://localhost:5125",
34
+ "path"=>"app name/host name/<1sec count",
35
+ "number"=>0,
36
+ "llimit"=>-1000000000,
37
+ "mode"=>"gauge",
38
+ "stype"=>"AREA",
39
+ "adjustval"=>"1",
40
+ "meta"=>"",
41
+ "service_name"=>"multiforecast",
42
+ "gmode"=>"gauge",
43
+ "color"=>"#cc6633",
44
+ "created_at"=>"2013/02/02 00:41:11",
45
+ "section_name"=>"app%20name%2Fhost%20name",
46
+ "ulimit"=>1000000000,
47
+ "id"=>1,
48
+ "graph_name"=>"<1sec count",
49
+ "description"=>"",
50
+ "sulimit"=>100000,
51
+ "unit"=>"",
52
+ "sort"=>0,
53
+ "updated_at"=>"2013/02/02 02:32:10",
54
+ "adjust"=>"*",
55
+ "type"=>"AREA",
56
+ "sllimit"=>-100000,
57
+ "md5"=>"3c59dc048e8850243be8079a5c74d079"
58
+ }
59
+ end
60
+
61
+ proc = Proc.new do
62
+ stub_request(:get, "#{base_uri}/api/#{gfpath(graph['path'])}").
63
+ to_return(:status => 200, :body => graph_example.to_json)
64
+ end
65
+ before(:each, &proc)
66
+ end
67
+
68
+ shared_context "stub_post_graph" do
69
+ include_context "stub_get_graph"
70
+ proc = Proc.new do
71
+ stub_request(:post, "#{base_uri}/api/#{gfpath(graph['path'])}").
72
+ to_return(:status => 200, :body => { "error" => 0, "data" => graph_example }.to_json)
73
+ end
74
+ before(:each, &proc)
75
+ end
76
+
77
+ shared_context "stub_delete_graph" do
78
+ proc = Proc.new do
79
+ stub_request(:post, "#{base_uri}/delete/#{gfpath(graph['path'])}").
80
+ to_return(:status => 200, :body => { "error" => 0 }.to_json)
81
+ end
82
+ before(:each, &proc)
83
+ end
84
+
85
+ shared_context "stub_edit_graph" do
86
+ include_context "stub_get_graph"
87
+
88
+ proc = Proc.new do
89
+ stub_request(:post, "#{base_uri}/json/edit/graph/#{graph['id']}").
90
+ to_return(:status => 200, :body => { "error" => 0 }.to_json)
91
+ end
92
+ before(:each, &proc)
93
+ end
94
+
95
+ shared_context "stub_list_complex" do
96
+ def list_complex_example
97
+ [
98
+ {"gfuri"=>"http://localhost:5125",
99
+ "path"=>"app name/host name/complex graph test",
100
+ "service_name"=>"multiforecast",
101
+ "section_name"=>"app%20name%2Fhost%20name",
102
+ "graph_name"=>"<1sec count",
103
+ "id"=>1},
104
+ ]
105
+ end
106
+
107
+ proc = Proc.new do
108
+ stub_request(:get, "#{base_uri}/json/list/complex").
109
+ to_return(:status => 200, :body => list_complex_example.to_json)
110
+ end
111
+ before(:each, &proc)
112
+ end
113
+
114
+ shared_context "stub_get_complex" do
115
+ def complex_example
116
+ {"gfuri"=>"http://localhost:5125",
117
+ "path"=>"app name/host name/complex graph test",
118
+ "service_name"=>"multiforecast",
119
+ "section_name"=>"app%20name%2Fhost%20name",
120
+ "graph_name"=>"complex graph test",
121
+ "number"=>0,
122
+ "complex"=>true,
123
+ "created_at"=>"2013/05/20 15:08:28",
124
+ "id"=>1,
125
+ "data"=>
126
+ [{"gmode"=>"gauge", "stack"=>false, "type"=>"AREA", "graph_id"=>218},
127
+ {"gmode"=>"gauge", "stack"=>true, "type"=>"AREA", "graph_id"=>217}],
128
+ "sumup"=>false,
129
+ "description"=>"complex graph test",
130
+ "sort"=>10,
131
+ "updated_at"=>"2013/05/20 15:08:28"}
132
+ end
133
+
134
+ proc = Proc.new do
135
+ stub_request(:get, "#{base_uri}/json/complex/#{gfpath(to_complex['path'])}").
136
+ to_return(:status => 200, :body => complex_example.to_json)
137
+ end
138
+ before(:each, &proc)
139
+ end
140
+
141
+ shared_context "stub_delete_complex" do
142
+ proc = Proc.new do
143
+ stub_request(:post, "#{base_uri}/json/delete/complex/#{gfpath(to_complex['path'])}").
144
+ to_return(:status => 200, :body => { "error" => 0 }.to_json)
145
+ end
146
+ before(:each, &proc)
147
+ end
148
+
149
+ shared_context "stub_create_complex" do
150
+ include_context "stub_list_complex"
151
+
152
+ proc = Proc.new do
153
+ list_graph_example.each do |graph|
154
+ stub_request(:get, "#{base_uri}/api/#{gfpath(graph['path'])}").
155
+ to_return(:status => 200, :body => graph.to_json)
156
+ end
157
+
158
+ stub_request(:post, "#{base_uri}/json/create/complex").
159
+ to_return(:status => 200, :body => { "error" => 0 }.to_json)
160
+ end
161
+ before(:each, &proc)
162
+ end
163
+
@@ -0,0 +1,62 @@
1
+ # -*- encoding: utf-8 -*-
2
+ shared_context "let_graph" do
3
+ include_context "stub_list_graph" if ENV['MOCK'] == 'on'
4
+ let(:graphs) { multiforecast.list_graph }
5
+ let(:graph) { graphs.first }
6
+ end
7
+
8
+ shared_context "setup_graph" do
9
+ include_context "let_graph"
10
+ include_context "stub_post_graph" if ENV['MOCK'] == 'on'
11
+ include_context "stub_delete_graph" if ENV['MOCK'] == 'on'
12
+ before(:all) {
13
+ multiforecast.delete_graph("app name/host name/<1sec count") rescue nil
14
+ multiforecast.delete_graph("app name/host name/<2sec count") rescue nil
15
+ multiforecast.post_graph("app name/host name/<1sec count", { 'number' => 0 }) rescue nil
16
+ multiforecast.post_graph("app name/host name/<2sec count", { 'number' => 0 }) rescue nil
17
+ }
18
+ after(:all) {
19
+ multiforecast.delete_graph("app name/host name/<1sec count") rescue nil
20
+ multiforecast.delete_graph("app name/host name/<2sec count") rescue nil
21
+ }
22
+ end
23
+
24
+ shared_context "let_complex" do
25
+ include_context "setup_graph"
26
+ let(:from_graphs) do
27
+ [
28
+ {
29
+ "path" => graphs[0]["path"],
30
+ "gmode" => "gauge",
31
+ "stack" => false,
32
+ "type" => "AREA",
33
+ },
34
+ {
35
+ "path" => graphs[1]["path"],
36
+ "gmode" => "gauge",
37
+ "stack" => false,
38
+ "type" => "AREA"
39
+ },
40
+ ]
41
+ end
42
+ let(:to_complex) do
43
+ {
44
+ "path" => "app name/host name/complex graph test",
45
+ "description" => "complex graph test",
46
+ "sort" => 10
47
+ }
48
+ end
49
+ end
50
+
51
+ shared_context "setup_complex" do
52
+ include_context "let_complex"
53
+ include_context "stub_create_complex" if ENV['MOCK'] == 'on'
54
+ include_context "stub_delete_complex" if ENV['MOCK'] == 'on'
55
+ before do
56
+ multiforecast.delete_complex(to_complex["path"]) rescue nil
57
+ multiforecast.create_complex(from_graphs, to_complex) rescue nil
58
+ end
59
+ after do
60
+ multiforecast.delete_complex(to_complex["path"]) rescue nil
61
+ end
62
+ end
@@ -0,0 +1,22 @@
1
+ require 'multiforecast-client'
2
+ require 'multiforecast/shared_context/setup.rb'
3
+ require 'multiforecast/shared_context/mock.rb'
4
+
5
+ include MultiForecast::ConversionRule
6
+
7
+ def e(str)
8
+ CGI.escape(str).gsub('+', '%20') if str
9
+ end
10
+
11
+ def gfpath(path)
12
+ "#{e service_name(path)}/#{e section_name(path)}/#{e graph_name(path)}"
13
+ end
14
+
15
+ def base_uri
16
+ 'http://localhost:5125'
17
+ end
18
+
19
+ def multiforecast(opts = {})
20
+ opts['mapping'] ||= { '' => base_uri }
21
+ MultiForecast::Client.new(opts)
22
+ end
@@ -0,0 +1,30 @@
1
+ shared_examples_for 'graph_uri_long_metrics' do
2
+ it { subject.should match(/(\?|&)t=c(&|$)/) }
3
+ it_should_behave_like 'graph_uri_params_fromto'
4
+ it_should_behave_like 'graph_uri_params_widthheight'
5
+ end
6
+
7
+ shared_examples_for 'graph_uri_short_metrics' do
8
+ it { subject.should match(/(\?|&)t=sc(&|$)/) }
9
+ it_should_behave_like 'graph_uri_params_fromto'
10
+ it_should_behave_like 'graph_uri_params_widthheight'
11
+ end
12
+
13
+ shared_examples_for 'graph_uri_params' do
14
+ it_should_behave_like 'graph_uri_params_term'
15
+ it_should_behave_like 'graph_uri_params_widthheight'
16
+ end
17
+
18
+ shared_examples_for 'graph_uri_params_term' do
19
+ it { subject.should match(/(\?|&)t=#{params['t']}(&|$)/) }
20
+ end
21
+
22
+ shared_examples_for 'graph_uri_params_widthheight' do
23
+ it { subject.should match(/(\?|&)width=#{params['width'].to_s}(&|$)/) }
24
+ it { subject.should match(/(\?|&)height=#{params['height'].to_s}(&|$)/) }
25
+ end
26
+
27
+ shared_examples_for 'graph_uri_params_fromto' do
28
+ it { subject.should match(/(\?|&)from=#{Regexp.escape(URI.escape(params['from'].to_s))}(&|$)/) }
29
+ it { subject.should match(/(\?|&)to=#{Regexp.escape(URI.escape(params['to'].to_s))}(&|$)/) }
30
+ end
@@ -0,0 +1,2 @@
1
+ require 'multiforecast/conversion_rule'
2
+ require 'multiforecast/client'
@@ -0,0 +1,29 @@
1
+ #! /usr/bin/env gem build
2
+ # encoding: utf-8
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.name = 'multiforecast-client'
6
+ gem.version = File.read(File.expand_path('VERSION', File.dirname(__FILE__))).chomp
7
+ gem.authors = ["Naotoshi Seo"]
8
+ gem.email = ["sonots@gmail.com"]
9
+ gem.homepage = "https://github.com/sonots/multiforecast-client"
10
+ gem.summary = "Multiple GrowthForecast Client"
11
+ gem.description = gem.summary
12
+
13
+ gem.files = `git ls-files`.split($\)
14
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
15
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
16
+ gem.require_paths = ["lib"]
17
+
18
+ gem.add_runtime_dependency "growthforecast-client", "~> 0.62.0"
19
+
20
+ # for testing
21
+ gem.add_development_dependency "rake"
22
+ gem.add_development_dependency "rspec", "~> 2.11"
23
+ gem.add_development_dependency "webmock"
24
+
25
+ # for debug
26
+ gem.add_development_dependency "pry"
27
+ gem.add_development_dependency "pry-nav"
28
+ gem.add_development_dependency "tapp"
29
+ end