growthforecast-client 0.0.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.
@@ -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