growthforecast-client 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,11 @@
1
+ /*.gem
2
+ ~*
3
+ #*
4
+ *~
5
+ .bundle
6
+ Gemfile.lock
7
+ .rbenv-version
8
+ vendor
9
+ doc/*
10
+ tmp/*
11
+ .yardoc
@@ -0,0 +1,4 @@
1
+ set autolist
2
+ set autoeval
3
+ set autoreload
4
+
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --colour
2
+ --format documentation
@@ -0,0 +1,7 @@
1
+ rvm:
2
+ # - 1.8.7
3
+ - 1.9.2
4
+ - 1.9.3
5
+ # - ruby-head
6
+ gemfile:
7
+ - Gemfile
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ # encoding: utf-8
2
+ source :rubygems
3
+
4
+ gemspec
5
+ gem 'growthforecast-client', path: '.'
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Naotoshi SEO
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,25 @@
1
+ # GrowthForecast Client [![Build Status](https://secure.travis-ci.org/sonots/growthforecast-client.png?branch=master)](http://travis-ci.org/sonots/growthforecast-client) [![Dependency Status](https://gemnasium.com/sonots/growthforecast-client.png)](https://gemnasium.com/sonots/growthforecast-client)
2
+
3
+ testing ruby: 1.9.3; GrowthForecast: > 0.39
4
+
5
+ ## About GrowthForecast Client
6
+
7
+ growthforecast-client is a ruby client library for GrowthForecast API where [GrowthForecast](http://kazeburo.github.com/GrowthForecast/) is a visualization graph tool.
8
+
9
+ ## USAGE
10
+
11
+ gem install growthforecast-client
12
+
13
+ See [examples](examples) directory.
14
+
15
+ ## Contributing
16
+
17
+ 1. Fork it
18
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
19
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
20
+ 4. Push to the branch (`git push origin my-new-feature`)
21
+ 5. Create new [Pull Request](../../pull/new/master)
22
+
23
+ ## Copyright
24
+
25
+ Copyright (c) 2013 Naotoshi SEO. See [LICENSE](LICENSE) for details.
@@ -0,0 +1,15 @@
1
+ # encoding: utf-8
2
+ require "bundler/gem_tasks"
3
+
4
+ require 'rspec/core'
5
+ require 'rspec/core/rake_task'
6
+ RSpec::Core::RakeTask.new(:spec) do |spec|
7
+ spec.pattern = FileList['spec/**/*_spec.rb']
8
+ end
9
+ task :default => :spec
10
+
11
+ desc 'Open an irb session preloaded with the gem library'
12
+ task :console do
13
+ sh 'irb -rubygems -I lib -r growthforecast-client.rb'
14
+ end
15
+ task :c => :console
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,37 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require 'growthforecast-client'
3
+
4
+ # Create a GrowthForecast Client, given he base URI of GrowthForecast
5
+ uri = 'http://localhost:5125'
6
+ client = GrowthForecast::Client.new(uri)
7
+
8
+ # Apply for all services/sections
9
+ sections = client.list_section
10
+ sections.each do |service_name, sections|
11
+ sections.each do |section_name|
12
+ # Make a complex graph from these graphs
13
+ from_graphs= [
14
+ {:path => "#{service_name}/#{section_name}/<1sec_count", :gmode => 'gauge', :stack => true, :type => 'AREA'},
15
+ {:path => "#{service_name}/#{section_name}/<2sec_count", :gmode => 'gauge', :stack => true, :type => 'AREA'},
16
+ {:path => "#{service_name}/#{section_name}/<3sec_count", :gmode => 'gauge', :stack => true, :type => 'AREA'},
17
+ {:path => "#{service_name}/#{section_name}/<4sec_count", :gmode => 'gauge', :stack => true, :type => 'AREA'},
18
+ {:path => "#{service_name}/#{section_name}/>=4sec_count", :gmode => 'gauge', :stack => true, :type => 'AREA'},
19
+ ]
20
+
21
+ # The propety of a complex graph to create, e.g., path
22
+ to_complex = {
23
+ :path => "#{service_name}/#{section_name}/response_count",
24
+ :description => 'response time count',
25
+ :sort => 10,
26
+ }
27
+
28
+ begin
29
+ puts "Setup #{to_complex[:path]}"
30
+ client.create_complex(from_graphs, to_complex)
31
+ rescue GrowthForecast::AlreadyExists => e
32
+ puts "\tclass:#{e.class}\t#{e.message}"
33
+ rescue GrowthForecast::NotFound => e
34
+ puts "\tclass:#{e.class}\t#{e.message}"
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,36 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require 'growthforecast-client'
3
+
4
+ # Create a GrowthForecast Client, given he base URI of GrowthForecast
5
+ uri = 'http://localhost:5125'
6
+ client = GrowthForecast::Client.new(uri)
7
+
8
+ # configure colors of graphs whose names are as belows:
9
+ graph_colors = {
10
+ '<1sec_count' => '#1111cc',
11
+ '<2sec_count' => '#11cc11',
12
+ '<3sec_count' => '#cc7711',
13
+ '<4sec_count' => '#cccc11',
14
+ '>=4sec_count' => '#cc1111',
15
+ }
16
+ # Apply for all services/sections
17
+ sections = client.list_section
18
+ sections.each do |service_name, sections|
19
+ sections.each do |section_name|
20
+ graph_colors.keys.each do |graph_name|
21
+ data = {
22
+ 'color' => graph_colors[graph_name],
23
+ 'unit' => 'count',
24
+ 'sort' => 1, # order to display, 19 is the top
25
+ 'adjust' => '/',
26
+ 'adjustval' => '1',
27
+ }
28
+ begin
29
+ puts "Setup /#{service_name}/#{section_name}/#{graph_name}"
30
+ client.edit_graph(service_name, section_name, graph_name, data)
31
+ rescue GrowthForecast::NotFound => e
32
+ puts "\tclass:#{e.class}\t#{e.message}"
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,30 @@
1
+ #! /usr/bin/env gem build
2
+ # encoding: utf-8
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.name = 'growthforecast-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/growthforecast-client"
10
+ gem.summary = "A Ruby Client Library for GrowthForecast API"
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 "httpclient"
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-debugger"
28
+ gem.add_development_dependency "rb-readline"
29
+ gem.add_development_dependency "tapp"
30
+ end
@@ -0,0 +1 @@
1
+ require 'growthforecast/client'
@@ -0,0 +1,323 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require 'httpclient'
3
+ require 'json'
4
+ require 'uri'
5
+ require 'pp'
6
+
7
+ module GrowthForecast
8
+ class Error < StandardError; end
9
+ class NotFound < Error; end
10
+ class AlreadyExists < Error; end
11
+
12
+ class Client
13
+ attr_accessor :debug
14
+ # @param [String] base_uri The base uri of GrowthForecast
15
+ def initialize(base_uri = 'http://127.0.0.1:5125')
16
+ @base_uri = base_uri
17
+ end
18
+
19
+ # GET the JSON API
20
+ # @param [String] path
21
+ # @return [Hash] response body
22
+ def get_json(path)
23
+ res = client.get("#{@base_uri}#{path}")
24
+ handle_error(res)
25
+ JSON.parse(res.body)
26
+ end
27
+
28
+ # POST the JSON API
29
+ # @param [String] path
30
+ # @param [Hash] data
31
+ # @return [Hash] response body
32
+ def post_json(path, data = {})
33
+ pp data if @debug
34
+ json = JSON.generate(data)
35
+ res = client.post("#{@base_uri}#{path}", json)
36
+ handle_error(res)
37
+ JSON.parse(res.body)
38
+ end
39
+
40
+ # POST the non-JSON API
41
+ # @param [String] path
42
+ # @param [Hash] data
43
+ # @return [String] response body
44
+ def post_query(path, data = {})
45
+ pp data if @debug
46
+ res = client.post("#{@base_uri}#{path}", data)
47
+ handle_error(res)
48
+ JSON.parse(res.body)
49
+ end
50
+
51
+ # Get the list of graphs, /json/list/graph
52
+ # @return [Hash] list of graphs
53
+ # @example
54
+ # [
55
+ # {"service_name"=>"test",
56
+ # "graph_name"=>"<2sec_count",
57
+ # "section_name"=>"hostname",
58
+ # "id"=>4},
59
+ # {"service_name"=>"test",
60
+ # "graph_name"=>"<1sec_count",
61
+ # "section_name"=>"hostname",
62
+ # "id"=>3},
63
+ # ]
64
+ def list_graph
65
+ get_json('/json/list/graph')
66
+ end
67
+
68
+ # A Helper: Get the list of section
69
+ # @return [Hash] list of sections
70
+ # @example
71
+ # {
72
+ # "service_name1" => [
73
+ # "section_name1",
74
+ # "section_name2",
75
+ # ],
76
+ # "service_name2" => [
77
+ # "section_name1",
78
+ # "section_name2",
79
+ # ],
80
+ # }
81
+ def list_section
82
+ graphs = list_graph
83
+ services = {}
84
+ graphs.each do |graph|
85
+ service_name, section_name = graph['service_name'], graph['section_name']
86
+ services[service_name] ||= {}
87
+ services[service_name][section_name] ||= true
88
+ end
89
+ Hash[services.map {|service_name, sections| [service_name, sections.keys] }]
90
+ end
91
+
92
+ # A Helper: Get the list of services
93
+ # @return [Array] list of services
94
+ # @example
95
+ # [
96
+ # "service_name1",
97
+ # "service_name2",
98
+ # ]
99
+ def list_service
100
+ graphs = list_graph
101
+ services = {}
102
+ graphs.each do |graph|
103
+ service_name = graph['service_name']
104
+ services[service_name] ||= true
105
+ end
106
+ services.keys
107
+ end
108
+
109
+ # Get the propety of a graph, GET /api/:service_name/:section_name/:graph_name
110
+ # @param [String] service_name
111
+ # @param [String] section_name
112
+ # @param [String] graph_name
113
+ # @return [Hash] the graph property
114
+ # @example
115
+ #{
116
+ # "number"=>1,
117
+ # "llimit"=>-1000000000,
118
+ # "mode"=>"gauge",
119
+ # "stype"=>"AREA",
120
+ # "adjustval"=>"1",
121
+ # "meta"=>"",
122
+ # "service_name"=>"test",
123
+ # "gmode"=>"gauge",
124
+ # "color"=>"#cc6633",
125
+ # "created_at"=>"2013/02/02 00:41:11",
126
+ # "section_name"=>"hostname",
127
+ # "ulimit"=>1000000000,
128
+ # "id"=>21,
129
+ # "graph_name"=>"<4sec_count",
130
+ # "description"=>"",
131
+ # "sulimit"=>100000,
132
+ # "unit"=>"",
133
+ # "sort"=>0,
134
+ # "updated_at"=>"2013/02/02 02:32:10",
135
+ # "adjust"=>"*",
136
+ # "type"=>"AREA",
137
+ # "sllimit"=>-100000,
138
+ # "md5"=>"3c59dc048e8850243be8079a5c74d079"}
139
+ def get_graph(service_name, section_name, graph_name)
140
+ get_json("/api/#{service_name}/#{section_name}/#{graph_name}")
141
+ end
142
+
143
+ # Get the propety of a graph, /json/graph/:id
144
+ # @param [String] id
145
+ # @return [Hash] the graph property
146
+ # @example
147
+ # {"llimit"=>-1000000000,
148
+ # "number"=>48778224,
149
+ # "stype"=>"AREA",
150
+ # "mode"=>"count",
151
+ # "complex"=>false,
152
+ # "adjustval"=>"1",
153
+ # "created_at"=>"2013/02/01 16:01:17",
154
+ # "color"=>"#cc3366",
155
+ # "service_name"=>"test",
156
+ # "gmode"=>"gauge",
157
+ # "ulimit"=>1000000000,
158
+ # "section_name"=>"all",
159
+ # "id"=>1,
160
+ # "graph_name"=>"response_time_max",
161
+ # "description"=>"",
162
+ # "sort"=>0,
163
+ # "unit"=>"",
164
+ # "sulimit"=>100000,
165
+ # "updated_at"=>"2013/02/04 18:26:49",
166
+ # "adjust"=>"*",
167
+ # "sllimit"=>-100000,
168
+ # "type"=>"AREA"}
169
+ def get_graph_by_id(id)
170
+ get_json("/json/graph/#{id}")
171
+ end
172
+
173
+ # Post parameters to a graph, POST /api/:service_name/:section_name/:graph_name
174
+ # @param [String] service_name
175
+ # @param [String] section_name
176
+ # @param [String] graph_name
177
+ # @param [Hash] params The POST parameters. See #get_graph
178
+ def post_graph(service_name, section_name, graph_name, params)
179
+ post_query("/api/#{service_name}/#{section_name}/#{graph_name}", params)
180
+ end
181
+
182
+ # Delete a graph, POST /delete/:service_name/:section_name/:graph_name
183
+ # @param [String] service_name
184
+ # @param [String] section_name
185
+ # @param [String] graph_name
186
+ def delete_graph(service_name, section_name, graph_name)
187
+ post_query("/delete/#{service_name}/#{section_name}/#{graph_name}")
188
+ end
189
+
190
+ # Update the property of a graph, /json/edit/graph/:id
191
+ # @param [String] service_name
192
+ # @param [String] section_name
193
+ # @param [String] graph_name
194
+ # @param [Hash] params
195
+ # All of parameters given by #get_graph are available except `number` and `mode`.
196
+ # @return [Hash] error response
197
+ # @example
198
+ # {"error"=>0} #=> Success
199
+ # {"error"=>1} #=> Error
200
+ def edit_graph(service_name, section_name, graph_name, params)
201
+ data = get_graph(service_name, section_name, graph_name)
202
+ id = data['id']
203
+ updates = handle_update_params(data, params)
204
+ post_json("/json/edit/graph/#{id}", updates)
205
+ end
206
+
207
+ # Get the list of complex graphs, /json/list/complex
208
+ # @return [Hash] list of complex graphs
209
+ # @example
210
+ # [
211
+ # {"service_name"=>"test",
212
+ # "graph_name"=>"<2sec_count",
213
+ # "section_name"=>"hostname",
214
+ # "id"=>4},
215
+ # {"service_name"=>"test",
216
+ # "graph_name"=>"<1sec_count",
217
+ # "section_name"=>"hostname",
218
+ # "id"=>3},
219
+ # ]
220
+ def list_complex
221
+ get_json('/json/list/complex')
222
+ end
223
+
224
+ # Create a complex graph
225
+ #
226
+ # @param [Array] from_graphs Array of graph properties whose keys are
227
+ # ["service_name", "section_name", "graph_name", "gmode", "stack", "type"]
228
+ # @param [Hash] to_complex Property of Complex Graph, whose keys are like
229
+ # ["service_name", "section_name", "graph_name", "description", "sort"]
230
+ def create_complex(from_graphs, to_complex)
231
+ graph_data = []
232
+ from_graphs.each do |from_graph|
233
+ graph = get_graph(from_graph["service_name"], from_graph["section_name"], from_graph["graph_name"])
234
+ graph_id = graph['id']
235
+
236
+ graph_data << {
237
+ :gmode => from_graph["gmode"],
238
+ :stack => from_graph["stack"],
239
+ :type => from_graph["type"],
240
+ :graph_id => graph_id
241
+ }
242
+ end
243
+
244
+ post_params = {
245
+ :service_name => to_complex["service_name"],
246
+ :section_name => to_complex["section_name"],
247
+ :graph_name => to_complex["graph_name"],
248
+ :description => to_complex["description"],
249
+ :sort => to_complex["sort"],
250
+ :data => graph_data
251
+ }
252
+
253
+ post_json('/json/create/complex', post_params)
254
+ end
255
+
256
+ # Delete a complex graph
257
+ #
258
+ # This is a helper method of GrowthForecast API to find complex graph id and call delete_complex_by_id
259
+ #
260
+ # @param [String] service_name
261
+ # @param [String] section_name
262
+ # @param [String] graph_name
263
+ # @return [Hash] error response
264
+ # @example
265
+ # {"error"=>0} #=> Success
266
+ # {"error"=>1} #=> Error
267
+ def delete_complex(service_name, section_name, graph_name)
268
+ complex_graphs = list_complex
269
+ complex = complex_graphs.select {|g| g["service_name"] == service_name and g["section_name"] == section_name and g["graph_name"] == graph_name }
270
+ raise NotFound if complex.empty?
271
+ delete_complex_by_id(complex.first["id"])
272
+ end
273
+
274
+ # Delete a complex graph, /delete_complex/:complex_id
275
+ #
276
+ # @param [String] id of a complex graph
277
+ # @return [Hash] error response
278
+ # @example
279
+ # {"error"=>0} #=> Success
280
+ # {"error"=>1} #=> Error
281
+ def delete_complex_by_id(complex_id)
282
+ post_query("/delete_complex/#{complex_id}")
283
+ end
284
+
285
+ private
286
+
287
+ def client
288
+ @client ||= HTTPClient.new
289
+ end
290
+
291
+ def handle_error(res)
292
+ case res.status
293
+ when 200
294
+ when 404
295
+ raise NotFound.new(error_message(res))
296
+ when 409
297
+ raise AlreadyExists.new(error_message(res))
298
+ else
299
+ raise Error.new(error_message(res))
300
+ end
301
+ end
302
+
303
+ def error_message(res)
304
+ "status:#{res.status}\turi:#{res.http_header.request_uri.to_s}"
305
+ end
306
+
307
+ # GrowthForecast's /json/edit/graph API requires all parameters to update, thus
308
+ # we have to merge the original graph parameters and parameters which we want to update. Sucks!
309
+ #
310
+ # @param [Hash] graph_data the current graph property data
311
+ # @param [Hash[ params the parameters which we want to update
312
+ # @return [Hash] merged parameters
313
+ def handle_update_params(graph_data, params)
314
+ updates = graph_data.merge(params)
315
+ # `meta` field is automatically added when we call get_graph.
316
+ # If we post `meta` data to update graph, `meta` is constructed circularly. Sucks!
317
+ # Thus, I remove the `meta` here.
318
+ updates['meta'] = '' if !params.has_key?('meta')
319
+ updates
320
+ end
321
+ end
322
+ end
323
+
@@ -0,0 +1,154 @@
1
+ require 'spec_helper'
2
+
3
+ describe GrowthForecast::Client do
4
+ id_keys = %w[id service_name section_name graph_name]
5
+ graph_keys = %w[number llimit mode stype adjustval gmode color created_at ulimit description
6
+ sulimit unit sort updated_at adjust type sllimit meta md5]
7
+
8
+ before(:all) { @client = GrowthForecast::Client.new('http://localhost:5125') }
9
+
10
+ include_context "stub_list_graph" if ENV['MOCK'] == 'on'
11
+ let(:graphs) { @client.list_graph }
12
+ let(:graph) { graphs.first }
13
+
14
+ include_context "stub_post_graph" if ENV['MOCK'] == 'on'
15
+ include_context "stub_delete_graph" if ENV['MOCK'] == 'on'
16
+ before(:all) {
17
+ @client.delete_graph("app_name", "hostname", "<1sec_count") rescue nil
18
+ @client.delete_graph("app_name", "hostname", "<2sec_count") rescue nil
19
+ @client.post_graph("app_name", "hostname", "<1sec_count", { 'number' => 0 }) rescue nil
20
+ @client.post_graph("app_name", "hostname", "<2sec_count", { 'number' => 0 }) rescue nil
21
+ }
22
+ after(:all) {
23
+ @client.delete_graph("app_name", "hostname", "<1sec_count") rescue nil
24
+ @client.delete_graph("app_name", "hostname", "<2sec_count") rescue nil
25
+ }
26
+
27
+ context "#list_graph" do
28
+ include_context "stub_list_graph" if ENV['MOCK'] == 'on'
29
+ subject { graphs }
30
+ its(:size) { should > 0 }
31
+ id_keys.each {|key| its(:first) { should have_key(key) } }
32
+ end
33
+
34
+ context "#list_section" do
35
+ include_context "stub_list_graph" if ENV['MOCK'] == 'on'
36
+ subject { @client.list_section }
37
+ its(:size) { should > 0 }
38
+ its(:class) { should == Hash }
39
+ it { subject.each {|service_name, sections| sections.size.should > 0 } }
40
+ end
41
+
42
+ context "#list_service" do
43
+ include_context "stub_list_graph" if ENV['MOCK'] == 'on'
44
+ subject { @client.list_service }
45
+ its(:size) { should > 0 }
46
+ its(:class) { should == Array }
47
+ end
48
+
49
+ context "#get_graph" do
50
+ include_context "stub_get_graph" if ENV['MOCK'] == 'on'
51
+ subject { @client.get_graph(graph["service_name"], graph["section_name"], graph["graph_name"]) }
52
+ id_keys.each {|key| it { subject[key].should == graph[key] } }
53
+ graph_keys.each {|key| it { subject.should have_key(key) } }
54
+ end
55
+
56
+ context "#get_graph_by_id" do
57
+ include_context "stub_get_graph_by_id" if ENV['MOCK'] == 'on'
58
+ subject { @client.get_graph_by_id(graph["id"]) }
59
+ id_keys.each {|key| it { subject[key].should == graph[key] } }
60
+ # this is the behavior of GrowthForecast API
61
+ (graph_keys - %w[meta md5]).each {|key| it { subject.should have_key(key) } }
62
+ end
63
+
64
+ context "#post_graph" do
65
+ include_context "stub_post_graph" if ENV['MOCK'] == 'on'
66
+ include_context "stub_get_graph" if ENV['MOCK'] == 'on'
67
+ params = {
68
+ 'number' => 0,
69
+ }
70
+ subject { @client.post_graph(graph["service_name"], graph["section_name"], graph["graph_name"], params) }
71
+ it { subject["error"].should == 0 }
72
+ params.keys.each {|key| it { subject["data"][key].should == params[key] } }
73
+ end
74
+
75
+ context "#delete_graph" do
76
+ include_context "stub_post_graph" if ENV['MOCK'] == 'on'
77
+ include_context "stub_delete_graph" if ENV['MOCK'] == 'on'
78
+ let(:graph) {
79
+ {
80
+ "service_name" => "app_name",
81
+ "section_name" => "hostname",
82
+ "graph_name" => "<1sec_count",
83
+ }
84
+ }
85
+ before { @client.post_graph(graph['service_name'], graph['section_name'], graph['graph_name'], { 'number' => 0 }) }
86
+ subject { @client.delete_graph(graph['service_name'], graph['section_name'], graph['graph_name']) }
87
+ it { subject["error"].should == 0 }
88
+ end
89
+
90
+ context "#edit_graph" do
91
+ context "normal" do
92
+ include_context "stub_edit_graph" if ENV['MOCK'] == 'on'
93
+ params = {
94
+ 'sort' => 19,
95
+ 'adjust' => '/',
96
+ 'adjustval' => '1000000',
97
+ 'unit' => 'sec',
98
+ 'color' => "#000000"
99
+ }
100
+ before(:all) do
101
+ @before = @client.get_graph(graph["service_name"], graph["section_name"], graph["graph_name"])
102
+ @response = @client.edit_graph(graph["service_name"], graph["section_name"], graph["graph_name"], params)
103
+ @after = @client.get_graph(graph["service_name"], graph["section_name"], graph["graph_name"])
104
+ end
105
+ it { @response["error"].should == 0 }
106
+ # @todo: how to stub @after?
107
+ unless ENV['MOCK'] == 'on'
108
+ (id_keys + graph_keys - params.keys - %w[meta md5]).each {|key| it { @after[key].should == @before[key] } }
109
+ params.keys.each {|key| it { @after[key].should == params[key] } }
110
+ end
111
+ end
112
+
113
+ # this is the behavior of GrowthForecast API
114
+ context "number and mode does not affect" do
115
+ include_context "stub_edit_graph" if ENV['MOCK'] == 'on'
116
+ params = {
117
+ 'number' => 0,
118
+ 'mode' => 'count',
119
+ }
120
+ before(:all) do
121
+ @before = @client.get_graph(graph["service_name"], graph["section_name"], graph["graph_name"])
122
+ @response = @client.edit_graph(graph["service_name"], graph["section_name"], graph["graph_name"], params)
123
+ @after = @client.get_graph(graph["service_name"], graph["section_name"], graph["graph_name"])
124
+ end
125
+ params.keys.each {|key| it { @after[key].should == @before[key] } }
126
+ end
127
+ end
128
+
129
+ context "#create_complex" do
130
+ include_context "stub_create_complex" if ENV['MOCK'] == 'on'
131
+ include_context "stub_delete_complex" if ENV['MOCK'] == 'on'
132
+ context "normal" do
133
+ let(:from_graphs) do
134
+ [
135
+ graphs[0],
136
+ graphs[1],
137
+ ]
138
+ end
139
+ let(:to_complex) do
140
+ {
141
+ "service_name" => graphs.first["service_name"],
142
+ "section_name" => graphs.first["section_name"],
143
+ "graph_name" => "complex_graph_test",
144
+ "description" => "complex graph test",
145
+ "sort" => 10
146
+ }
147
+ end
148
+ subject { @client.create_complex(from_graphs, to_complex) }
149
+ it { subject["error"].should == 0 }
150
+ after { @client.delete_complex(to_complex["service_name"], to_complex["section_name"], to_complex["graph_name"]) }
151
+ end
152
+ end
153
+ end
154
+
@@ -0,0 +1,16 @@
1
+ # encoding: utf-8
2
+ require "bundler/setup"
3
+
4
+ ENV['MOCK'] ||= 'on'
5
+ require "pry"
6
+ require 'debugger'
7
+ require 'growthforecast/client'
8
+ require 'webmock/rspec' if ENV['MOCK'] == 'on'
9
+
10
+ ROOT = File.dirname(__FILE__)
11
+ Dir[File.expand_path("support/**/*.rb", ROOT)].each {|f| require f }
12
+
13
+ RSpec.configure do |config|
14
+ config.treat_symbols_as_metadata_keys_with_true_values = true
15
+ config.run_all_when_everything_filtered = true
16
+ end
@@ -0,0 +1,150 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ base_uri = 'http://localhost:5125'
4
+
5
+ shared_context "stub_list_graph" do
6
+ let(:list_graph_example) {
7
+ [
8
+ {"service_name"=>"app_name",
9
+ "section_name"=>"hostname",
10
+ "graph_name"=>"<1sec_count",
11
+ "id"=>1},
12
+ {"service_name"=>"app_name",
13
+ "section_name"=>"hostname",
14
+ "graph_name"=>"<2sec_count",
15
+ "id"=>2},
16
+ ]
17
+ }
18
+
19
+ proc = Proc.new do
20
+ # WebMock.allow_net_connect!
21
+ stub_request(:get, "#{base_uri}/json/list/graph").to_return(:status => 200, :body => list_graph_example.to_json)
22
+ end
23
+ before(:each, &proc)
24
+ before(:all, &proc)
25
+ end
26
+
27
+ shared_context "stub_get_graph" do
28
+ let(:graph_example) {
29
+ {
30
+ "number"=>0,
31
+ "llimit"=>-1000000000,
32
+ "mode"=>"gauge",
33
+ "stype"=>"AREA",
34
+ "adjustval"=>"1",
35
+ "meta"=>"",
36
+ "service_name"=>"app_name",
37
+ "gmode"=>"gauge",
38
+ "color"=>"#cc6633",
39
+ "created_at"=>"2013/02/02 00:41:11",
40
+ "section_name"=>"hostname",
41
+ "ulimit"=>1000000000,
42
+ "id"=>1,
43
+ "graph_name"=>"<1sec_count",
44
+ "description"=>"",
45
+ "sulimit"=>100000,
46
+ "unit"=>"",
47
+ "sort"=>0,
48
+ "updated_at"=>"2013/02/02 02:32:10",
49
+ "adjust"=>"*",
50
+ "type"=>"AREA",
51
+ "sllimit"=>-100000,
52
+ "md5"=>"3c59dc048e8850243be8079a5c74d079"
53
+ }
54
+ }
55
+
56
+ proc = Proc.new do
57
+ stub_request(:get, "#{base_uri}/api/#{graph['service_name']}/#{graph['section_name']}/#{graph['graph_name']}").
58
+ to_return(:status => 200, :body => graph_example.to_json)
59
+ end
60
+ before(:each, &proc)
61
+ before(:all, &proc)
62
+ end
63
+
64
+ shared_context "stub_get_graph_by_id" do
65
+ include_context "stub_get_graph"
66
+
67
+ proc = Proc.new do
68
+ stub_request(:get, "#{base_uri}/json/graph/#{graph['id']}").
69
+ to_return(:status => 200, :body => graph_example.to_json)
70
+ end
71
+ before(:each, &proc)
72
+ before(:all, &proc)
73
+ end
74
+
75
+ shared_context "stub_post_graph" do
76
+ include_context "stub_get_graph"
77
+ proc = Proc.new do
78
+ stub_request(:post, "#{base_uri}/api/#{graph['service_name']}/#{graph['section_name']}/#{graph['graph_name']}").
79
+ to_return(:status => 200, :body => { "error" => 0, "data" => graph_example }.to_json)
80
+ end
81
+ before(:each, &proc)
82
+ before(:all, &proc)
83
+ end
84
+
85
+ shared_context "stub_delete_graph" do
86
+ proc = Proc.new do
87
+ stub_request(:post, "#{base_uri}/delete/#{graph['service_name']}/#{graph['section_name']}/#{graph['graph_name']}").
88
+ to_return(:status => 200, :body => { "error" => 0 }.to_json)
89
+ end
90
+ before(:each, &proc)
91
+ before(:all, &proc)
92
+ end
93
+
94
+ shared_context "stub_edit_graph" do
95
+ include_context "stub_get_graph"
96
+
97
+ proc = Proc.new do
98
+ stub_request(:post, "#{base_uri}/json/edit/graph/#{graph['id']}").
99
+ to_return(:status => 200, :body => { "error" => 0 }.to_json)
100
+ end
101
+ before(:each, &proc)
102
+ before(:all, &proc)
103
+ end
104
+
105
+ shared_context "stub_list_complex" do
106
+ let(:list_complex_example) {
107
+ [
108
+ {"service_name"=>"app_name",
109
+ "section_name"=>"hostname",
110
+ "graph_name"=>"complex_graph_test",
111
+ "id"=>1},
112
+ ]
113
+ }
114
+ let(:complex_example) {
115
+ list_complex_example.first
116
+ }
117
+
118
+ proc = Proc.new do
119
+ stub_request(:get, "#{base_uri}/json/list/complex").
120
+ to_return(:status => 200, :body => list_complex_example.to_json)
121
+ end
122
+ before(:each, &proc)
123
+ before(:all, &proc)
124
+ end
125
+
126
+ shared_context "stub_delete_complex" do
127
+ proc = Proc.new do
128
+ stub_request(:post, "#{base_uri}/delete_complex/#{complex_example['id']}").
129
+ to_return(:status => 200, :body => { "error" => 0 }.to_json)
130
+ end
131
+ before(:each, &proc)
132
+ before(:all, &proc)
133
+ end
134
+
135
+ shared_context "stub_create_complex" do
136
+ include_context "stub_list_complex"
137
+
138
+ proc = Proc.new do
139
+ list_graph_example.each do |graph|
140
+ stub_request(:get, "#{base_uri}/api/#{graph['service_name']}/#{graph['section_name']}/#{graph['graph_name']}").
141
+ to_return(:status => 200, :body => graph.to_json)
142
+ end
143
+
144
+ stub_request(:post, "#{base_uri}/json/create/complex").
145
+ to_return(:status => 200, :body => { "error" => 0 }.to_json)
146
+ end
147
+ before(:each, &proc)
148
+ before(:all, &proc)
149
+ end
150
+
metadata ADDED
@@ -0,0 +1,199 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: growthforecast-client
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Naotoshi Seo
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-02-20 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: httpclient
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rspec
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '2.11'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '2.11'
62
+ - !ruby/object:Gem::Dependency
63
+ name: webmock
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: pry
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: pry-debugger
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ - !ruby/object:Gem::Dependency
111
+ name: rb-readline
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ - !ruby/object:Gem::Dependency
127
+ name: tapp
128
+ requirement: !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ! '>='
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ type: :development
135
+ prerelease: false
136
+ version_requirements: !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ! '>='
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ description: A Ruby Client Library for GrowthForecast API
143
+ email:
144
+ - sonots@gmail.com
145
+ executables: []
146
+ extensions: []
147
+ extra_rdoc_files: []
148
+ files:
149
+ - .gitignore
150
+ - .rdebugrc
151
+ - .rspec
152
+ - .travis.yml
153
+ - Gemfile
154
+ - LICENSE
155
+ - README.md
156
+ - Rakefile
157
+ - VERSION
158
+ - examples/complex_graph.rb
159
+ - examples/edit_graph.rb
160
+ - growthforecast-client.gemspec
161
+ - lib/growthforecast-client.rb
162
+ - lib/growthforecast/client.rb
163
+ - spec/growthforecast/client_spec.rb
164
+ - spec/spec_helper.rb
165
+ - spec/support/mock.rb
166
+ homepage: https://github.com/sonots/growthforecast-client
167
+ licenses: []
168
+ post_install_message:
169
+ rdoc_options: []
170
+ require_paths:
171
+ - lib
172
+ required_ruby_version: !ruby/object:Gem::Requirement
173
+ none: false
174
+ requirements:
175
+ - - ! '>='
176
+ - !ruby/object:Gem::Version
177
+ version: '0'
178
+ segments:
179
+ - 0
180
+ hash: -2138731048266880490
181
+ required_rubygems_version: !ruby/object:Gem::Requirement
182
+ none: false
183
+ requirements:
184
+ - - ! '>='
185
+ - !ruby/object:Gem::Version
186
+ version: '0'
187
+ segments:
188
+ - 0
189
+ hash: -2138731048266880490
190
+ requirements: []
191
+ rubyforge_project:
192
+ rubygems_version: 1.8.23
193
+ signing_key:
194
+ specification_version: 3
195
+ summary: A Ruby Client Library for GrowthForecast API
196
+ test_files:
197
+ - spec/growthforecast/client_spec.rb
198
+ - spec/spec_helper.rb
199
+ - spec/support/mock.rb