addons-client 0.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.
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .*.sw?
data/.travis.yml ADDED
@@ -0,0 +1,8 @@
1
+ rvm:
2
+ - 1.8.7
3
+ - 1.9.2
4
+ - 1.9.3
5
+ notifications:
6
+ email:
7
+ - csquared@heroku.com
8
+ - glenn@heroku.com
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in addons-client.gemspec
4
+ gemspec
5
+ gem "rake"
6
+
7
+ group :test do
8
+ gem 'rr'
9
+ gem 'webmock'
10
+ gem 'ruby-debug19', :platforms => [:mri_19]
11
+ end
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Chris Continanza
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.
data/README.md ADDED
@@ -0,0 +1,133 @@
1
+ # Addons::Client
2
+
3
+ [![Build Status](https://secure.travis-ci.org/heroku/addons-client.png?branch=master)](http://travis-ci.org/heroku/addons-client)
4
+
5
+ ## codename: Kaikei
6
+
7
+ The addons client is a Ruby library that creates the RESTful requests that are used to interact with the Add-on Platform API.
8
+
9
+ The Platform API provides 3 main functions for Add-ons: provisioning, deprovisioning, and plan change.
10
+ Historically, the heroku module "core" was responsible for sending the appropriate messages to
11
+ add-on providers and reacting correctly according to those responses. Core will still have to react
12
+ to api errors, but will no longer send messages to providers.
13
+
14
+ The Addons Client represents the first attempt at having a well-defined interface between a Platform and these
15
+ add-on related API interactions. It is an implementation of the following API: https://gist.github.com/079c98529d399bb08c7a
16
+
17
+ Also, we have provided a command line client (the real first consumer of the API) so we could issue API requests
18
+ to the add-ons app without having to fire up a console session.
19
+
20
+ ## Installation
21
+
22
+ ### make a test directory
23
+
24
+ mkdir client-test
25
+ cd client-test
26
+
27
+ ### make a Gemfile with the gem on github
28
+
29
+ echo "source :rubygems" > Gemfile
30
+ echo "gem 'addons-client', :git => 'git@github.com:heroku/addons-client.git'" >> Gemfile
31
+
32
+ ### use bundler to install the Gem from github
33
+
34
+ bundle install
35
+
36
+ ### set up ENV
37
+
38
+ export ADDONS_API_URL=https://heroku:password@localhost:3000
39
+
40
+ ### it works
41
+
42
+ bundle exec addons-client
43
+ Command must be one of: provision, deprovision, planchange
44
+
45
+ Remember to use bundle exec to run the command line commands!
46
+
47
+ ## Ruby Usage
48
+
49
+ ```ruby
50
+ client = Addons::Client.new
51
+ # Addons::UserError: ADDONS_API_URL must be set
52
+
53
+ ENV['ADDONS_API_URL']='http://heroku:password@localhost:3000'
54
+
55
+ client = Addons::Client.new
56
+ ```
57
+
58
+ ### API Methods
59
+ ```ruby
60
+ client.provision! 'memcache:5mb'
61
+
62
+ client.provision! 'foo:bar', :consumer_id => 'app123@heroku.com',
63
+ :options => { :foo => 'bar', 'baz' => 'test' }
64
+
65
+ # => {:resource_id=>"DEADBEEF",
66
+ # :config=>{"FOO_URL"=>"http://foo.com"},
67
+ # :message=>"great success",
68
+ # :provider_id=>"ABC123"}
69
+
70
+ client.plan_change! 'ABC123', 'new_plan'
71
+
72
+ client.deprovision! 'ABC123'
73
+ ```
74
+
75
+ ## Command Line Usage
76
+ export ADDONS_API_URL=http://heroku:password@localhost:3000
77
+
78
+ addons-client provision memcache:5mb --consumer-id=app123@heroku.com --options.foo=bar --options.baz=true
79
+
80
+ #### Provisioning:
81
+
82
+ addons-client provision glenntest:test
83
+ {"resource_id":"3bdb228d-a94e-4135-b19f-7a17a9f4f481","config":null,"message":null,"provider_id":null}
84
+
85
+ ### use the resource id to interact with the add-on
86
+
87
+ addons-client plan_change 0dedb8f4-2921-42b8-81b9-a7df4c551140 test
88
+
89
+ addons-client deprovision 0dedb8f4-2921-42b8-81b9-a7df4c551140
90
+ Deprovisioned 0dedb8f4-2921-42b8-81b9-a7df4c551140
91
+
92
+ ### fun with options
93
+
94
+ addons-client provision foo-bar:test --consumer_id=resource123@heroku.com --options.message='Good job'
95
+
96
+
97
+ ## enabling api requests
98
+ Notice the provider_id is null.
99
+ This is because we won't send live requests until we've enabled the switch.
100
+ And also because in a later story we will want to have this toggleable on a per-request basis.
101
+
102
+ heroku config:add PROVIDER_API_ENABLED=true --app addons-staging
103
+
104
+ ### it should now create a resource with a provider_id
105
+
106
+ addons-client provision foo-bar:test
107
+ Provisioned foo-bar:test
108
+ {"resource_id":"0dedb8f4-2921-42b8-81b9-a7df4c551140","config":{"MYADDON_URL":"http://user.yourapp.com"},"message":null,"provider_id":2}
109
+
110
+ ## Test Usage
111
+
112
+ The client supports a mocked mode that sends no requests and returns canned responses.
113
+
114
+ ```ruby
115
+ Addons::Client.mock!
116
+ Addons::Client.new.provision! 'foo:bar'
117
+ # => {:resource_id=>"DEADBEEF",
118
+ # :config=>{"FOO_URL"=>"http://foo.com"},
119
+ # :message=>"great success",
120
+ # :provider_id=>"ABC123"}
121
+
122
+ Addons::Client.unmock!
123
+ Addons::Client.new.provision! 'foo:bar'
124
+ # Addons::UserError: ADDONS_API_URL must be set
125
+ ```
126
+
127
+ ## Contributing
128
+
129
+ 1. Fork it
130
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
131
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
132
+ 4. Push to the branch (`git push origin my-new-feature`)
133
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+ require "rake/testtask"
4
+
5
+ Rake::TestTask.new do |t|
6
+ t.libs << "test"
7
+ t.test_files = FileList['test/*_test.rb']
8
+ t.verbose = true
9
+ end
10
+
11
+ task :default => :test
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $LOAD_PATH.unshift File.dirname(File.expand_path('.', __FILE__)) + '/lib'
3
+ require "addons-client/version"
4
+
5
+ Gem::Specification.new do |gem|
6
+ gem.authors = ["Chris Continanza"]
7
+ gem.email = ["csquared@gmail.com"]
8
+ gem.description = %q{Addons Platform API client}
9
+ gem.summary = %q{Allows platfomrs to provision, deprovision, and change plans for add-on resources.}
10
+ gem.homepage = ""
11
+
12
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
13
+ gem.files = `git ls-files`.split("\n")
14
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
15
+ gem.name = "addons-client"
16
+ gem.require_paths = ["lib"]
17
+ gem.version = Addons::Client::VERSION
18
+
19
+ gem.add_dependency 'rest-client'
20
+ gem.add_dependency 'configliere'
21
+ gem.add_dependency 'json'
22
+ end
data/bin/addons-client ADDED
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require_relative '../lib/addons-client'
5
+
6
+ begin
7
+ Addons::CLI.run!
8
+ rescue Addons::UserError => e
9
+ STDERR.puts e.message and exit 1
10
+ rescue RestClient::ServiceUnavailable => e
11
+ if ! e.response.body.strip.empty?
12
+ STDERR.puts JSON.parse(e.response.body)['message']
13
+ else
14
+ STDERR.puts "Add-on is not available"
15
+ end
16
+ exit 1
17
+ end
18
+
@@ -0,0 +1,56 @@
1
+ module Addons::CLI
2
+ extend self
3
+
4
+ def run!
5
+ load_settings!
6
+ run_command!
7
+ end
8
+
9
+ def run_command!
10
+ command = Settings.rest.first
11
+ case command
12
+ when /deprovision/i
13
+ resource_id = Settings.rest[1]
14
+ raise Addons::UserError, "Must supply resource id" unless resource_id
15
+ response = client.deprovision!(resource_id)
16
+ puts "Deprovisioned #{resource_id}"
17
+ puts response
18
+ when /provision/i
19
+ slug = Settings.rest[1]
20
+ raise Addons::UserError, "Must supply add-on:plan" unless slug
21
+ response = client.provision!(slug, :options => Settings[:options],
22
+ :consumer_id => Settings[:consumer_id])
23
+ puts "Provisioned #{slug}"
24
+ puts response
25
+ when /plan-change/i
26
+ resource_id = Settings.rest[1]
27
+ raise Addons::UserError, "Must supply resource id" unless resource_id
28
+ plan = Settings.rest[2]
29
+ raise Addons::UserError, "Must supply plan after resource id" unless plan
30
+ response = client.plan_change!(resource_id, plan)
31
+ puts "Plan Changed to #{plan}"
32
+ puts response
33
+ else
34
+ if command
35
+ puts "#{command} is not a valid command"
36
+ else
37
+ puts "Command must be one of: provision, deprovision, plan-change"
38
+ end
39
+ end
40
+ end
41
+
42
+ def client
43
+ @client ||= Addons::Client
44
+ end
45
+
46
+ def puts(string)
47
+ STDOUT.puts(string)
48
+ end
49
+
50
+ def load_settings!
51
+ Settings.use :commandline
52
+ Settings.resolve!
53
+ rescue RuntimeError => e
54
+ raise Addons::UserError.new(e)
55
+ end
56
+ end
@@ -0,0 +1,89 @@
1
+ module Addons
2
+ class Client
3
+ extend Mock::Methods
4
+ extend Mock::Responses
5
+ DEFAULT_CONSUMER_ID = "api-client@localhost"
6
+
7
+ def self.api_url
8
+ @api_url = validate_api_url!
9
+ end
10
+
11
+ def self.provision!(slug, opts = {})
12
+ wrap_request do
13
+ addon_name, plan = slug.split(':')
14
+ raise UserError, "No add-on name given" unless addon_name
15
+ raise UserError, "No plan name given" unless plan
16
+
17
+ if mocked?
18
+ mocked_provision(addon_name)
19
+ else
20
+ payload = {
21
+ :addon => addon_name,
22
+ :plan => plan,
23
+ :consumer_id => opts[:consumer_id] || DEFAULT_CONSUMER_ID
24
+ }
25
+ payload.merge! :options => opts[:options] if opts[:options]
26
+ payload.merge! :rate => opts[:rate] if opts[:rate]
27
+ payload.merge! :addons_id => opts[:addons_id] if opts[:addons_id]
28
+ if start_at = opts[:start_at]
29
+ start_at.utc
30
+ payload.merge! :start_at => start_at.to_s
31
+ end
32
+ if end_at = opts[:end_at]
33
+ end_at.utc
34
+ payload.merge! :end_at => end_at.to_s
35
+ end
36
+ resource.post payload, :accept => :json
37
+ end
38
+ end
39
+ end
40
+
41
+ def self.deprovision!(resource_id)
42
+ wrap_request do
43
+ if mocked?
44
+ mocked_deprovision(resource_id)
45
+ else
46
+ resource["/#{resource_id}"].delete :accept => :json
47
+ end
48
+ end
49
+ end
50
+
51
+ def self.plan_change!(resource_id, plan)
52
+ wrap_request do
53
+ if mocked?
54
+ mocked_plan_change(resource_id, plan)
55
+ else
56
+ payload = {
57
+ :plan => plan,
58
+ }
59
+ resource["/#{resource_id}"].put payload, :accept => :json
60
+ end
61
+ end
62
+ end
63
+
64
+ def self.resource
65
+ RestClient::Resource.new(api_url.to_s)
66
+ end
67
+
68
+ protected
69
+ def self.wrap_request
70
+ response = yield
71
+ Addons::Client::Response.new(response)
72
+ rescue RestClient::ResourceNotFound
73
+ raise UserError, "Add-on not found: check addon spelling and plan name"
74
+ end
75
+
76
+ def self.validate_api_url!
77
+ api_url = nil
78
+ raise UserError, "ADDONS_API_URL must be set" unless ENV['ADDONS_API_URL']
79
+ begin
80
+ api_url = URI.join(ENV['ADDONS_API_URL'], '/api/1/resources')
81
+ rescue URI::InvalidURIError
82
+ raise UserError, "ADDONS_API_URL is an invalid url"
83
+ end
84
+ raise UserError, "No username given" unless api_url.user
85
+ raise UserError, "No password given" unless api_url.password
86
+ api_url
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,44 @@
1
+ module Addons
2
+ class Client
3
+ module Mock
4
+ module Methods
5
+ def mock!
6
+ @mock = true
7
+ end
8
+
9
+ def unmock!
10
+ @mock = false
11
+ end
12
+
13
+ def mocked?
14
+ @mock
15
+ end
16
+ end
17
+
18
+ module Responses
19
+ private
20
+ def mocked_provision(name)
21
+ {
22
+ 'resource_id' => "DEADBEEF",
23
+ 'config' => {"#{name.upcase}_URL" => 'http://foo.com'},
24
+ 'message' => "great success",
25
+ 'provider_id' => 'ABC123'
26
+ }
27
+ end
28
+
29
+ def mocked_deprovision(resource_id)
30
+ {}
31
+ end
32
+
33
+ def mocked_plan_change(resource_id, plan)
34
+ {
35
+ 'resource_id' => resource_id,
36
+ 'config' => {"#{plan.upcase}_URL" => 'http://foo.com'},
37
+ 'message' => "great success",
38
+ 'provider_id' => 'ABC123'
39
+ }
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,29 @@
1
+ module Addons
2
+ class Client
3
+ class Response
4
+ def initialize(response)
5
+ @data = case response
6
+ when String
7
+ response.strip.empty? ? {} : JSON.parse(response)
8
+ when Hash
9
+ response
10
+ end
11
+ @data
12
+ end
13
+
14
+ def to_s
15
+ @data.to_s
16
+ end
17
+
18
+ def method_missing(name, *args, &blk)
19
+ if @data.keys.include? name
20
+ @data[name]
21
+ elsif @data.keys.include? name.to_s
22
+ @data[name.to_s]
23
+ else
24
+ super
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
File without changes
@@ -0,0 +1,5 @@
1
+ module Addons
2
+ class Client
3
+ VERSION = "0.0.2"
4
+ end
5
+ end
@@ -0,0 +1,17 @@
1
+ $LOAD_PATH.unshift File.dirname(File.expand_path('..', __FILE__)) + '/lib'
2
+
3
+ require "addons-client/version"
4
+ require 'rest-client'
5
+ require 'digest'
6
+ require 'configliere'
7
+ require 'json'
8
+
9
+ module Addons
10
+ Exception = Class.new(Exception)
11
+ UserError = Class.new(RuntimeError)
12
+ end
13
+
14
+ require 'addons-client/mock'
15
+ require 'addons-client/client'
16
+ require 'addons-client/cli'
17
+ require 'addons-client/response'
@@ -0,0 +1,33 @@
1
+ require "#{File.dirname(__FILE__)}/test_helper"
2
+
3
+ class SettingsTest < Addons::Client::TestCase
4
+ def setup
5
+ stub_request(:any, /api\/1\/resources/)
6
+ ENV['ADDONS_API_URL'] = 'https://test:password@localhost:3333'
7
+ end
8
+
9
+ def test_client_uses_env_var
10
+ Addons::Client.provision! 'foo:bar'
11
+ assert_requested(:post, URI.join(ENV['ADDONS_API_URL'], '/api/1/resources').to_s)
12
+ end
13
+
14
+ def test_client_raises_error_on_bad_url
15
+ [
16
+ nil,
17
+ 'https://localhost:3333',
18
+ 'https://foo@localhost:3333',
19
+ ].each do |url|
20
+ ENV['ADDONS_API_URL'] = url
21
+ assert_raises Addons::UserError do
22
+ Addons::Client.provision! 'foo:bar'
23
+ end
24
+ end
25
+ end
26
+
27
+ def test_client_handles_404s_gracefully
28
+ stub_request(:any, /api\/1\/resources/).to_return(:status => 404)
29
+ assert_raises Addons::UserError do
30
+ Addons::Client.provision! 'foo:bar'
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,27 @@
1
+ require "#{File.dirname(__FILE__)}/test_helper"
2
+
3
+ class DeprovisionTest < Addons::Client::TestCase
4
+ def setup
5
+ ENV["ADDONS_API_URL"] = 'https://foo:bar@heroku.com'
6
+ stub_request(:any, target_url).to_return :body => " "
7
+ stub(Addons::CLI).puts
8
+ end
9
+
10
+ alias :target_url :resource_url
11
+
12
+ def test_cmd_line_requires_resource_id
13
+ assert_raises Addons::UserError, "Must supply resource id" do
14
+ addons_client! "deprovision"
15
+ end
16
+ end
17
+
18
+ def test_deprovisions_from_cmd_line
19
+ addons_client! "deprovision addons-uuid"
20
+ assert_requested(:delete, target_url)
21
+ end
22
+
23
+ def test_deprovisions_from_ruby
24
+ Addons::Client.deprovision! "addons-uuid"
25
+ assert_requested(:delete, target_url)
26
+ end
27
+ end
@@ -0,0 +1,53 @@
1
+ require "#{File.dirname(__FILE__)}/test_helper"
2
+
3
+ class PlanChangeTest < Addons::Client::TestCase
4
+ def setup
5
+ ENV["ADDONS_API_URL"] = 'https://foo:bar@heroku.com/api/1/resources'
6
+ stub_request(:any, target_url)
7
+ stub(Addons::CLI).puts
8
+ end
9
+
10
+ alias :target_url :resource_url
11
+
12
+ def test_plan_change_from_cmd_line
13
+ addons_client! "plan-change addons-uuid 5mb"
14
+ assert_requested(:put, target_url,
15
+ :body => { :plan => '5mb' })
16
+ end
17
+
18
+ def test_plan_change_from_ruby
19
+ Addons::Client.plan_change! 'addons-uuid', 'plizzan'
20
+ assert_requested(:put, target_url,
21
+ :body => { :plan => 'plizzan' })
22
+ end
23
+
24
+ def test_client_sets_plan_change_options
25
+ Addons::Client.plan_change! 'addons-uuid', 'bar'
26
+
27
+ assert_requested(:put, target_url,
28
+ :body => { :plan => 'bar' })
29
+ end
30
+
31
+ def test_cmd_line_sets_plan_change_options
32
+ addons_client! "plan-change addons-uuid bar"
33
+
34
+ assert_requested(:put, target_url,
35
+ :body => { :plan => 'bar' })
36
+ assert_received(Addons::CLI) do |cli|
37
+ cli.puts "Plan Changed to bar"
38
+ end
39
+ end
40
+
41
+ def test_cmd_line_requires_resource_id
42
+ assert_raises Addons::UserError, "Must supply resource id" do
43
+ addons_client! "provision"
44
+ end
45
+ end
46
+
47
+ def test_cmd_line_requires_plan_name
48
+ assert_raises Addons::UserError, "Must supply plan after resource id" do
49
+ addons_client! "provision ABC-123"
50
+ end
51
+ end
52
+
53
+ end
@@ -0,0 +1,69 @@
1
+ require "#{File.dirname(__FILE__)}/test_helper"
2
+
3
+ class ProvisionTest < Addons::Client::TestCase
4
+ def setup
5
+ ENV["ADDONS_API_URL"] = 'https://foo:bar@heroku.com'
6
+ stub_request(:any, target_url)
7
+ stub(Addons::CLI).puts
8
+ end
9
+
10
+ def target_url
11
+ URI.join(ENV["ADDONS_API_URL"], '/api/1/resources').to_s
12
+ end
13
+
14
+ def test_cmd_line_requires_addon_slug
15
+ assert_raises Addons::UserError, "Must supply addon:plan" do
16
+ addons_client! "provision"
17
+ end
18
+ end
19
+
20
+ def test_cmd_line_requires_plan
21
+ assert_raises Addons::UserError, "No plan name given" do
22
+ addons_client! "provision foo"
23
+ end
24
+ end
25
+
26
+ def test_provisions_from_cmd_line
27
+ addons_client! "provision memcache:5mb"
28
+ assert_requested(:post, target_url,
29
+ :body => { :addon => 'memcache', :plan => '5mb',
30
+ :consumer_id => 'api-client@localhost'})
31
+ end
32
+
33
+ def test_provisions_from_ruby
34
+ Addons::Client.provision! 'foo:plizzan'
35
+ assert_requested(:post, target_url,
36
+ :body => { :addon => 'foo', :plan => 'plizzan',
37
+ :consumer_id => 'api-client@localhost'})
38
+ end
39
+
40
+ def test_sets_consumer_id
41
+ Addons::Client.provision! 'foo:bar', :consumer_id => 'app123@heroku.com'
42
+ assert_requested(:post, target_url,
43
+ :body => { :addon => 'foo', :plan => 'bar',
44
+ :consumer_id => 'app123@heroku.com'})
45
+ end
46
+
47
+ def test_client_sets_provision_options
48
+ Addons::Client.provision! 'foo:bar',
49
+ :consumer_id => 'app123@heroku.com',
50
+ :options => { :foo => 'bar', 'baz' => 'test' }
51
+
52
+ assert_requested(:post, target_url,
53
+ :body => { :addon => 'foo', :plan => 'bar',
54
+ :consumer_id => 'app123@heroku.com',
55
+ :options => { :foo => 'bar', :baz => 'test'}})
56
+ end
57
+
58
+ def test_cmd_line_sets_provision_options
59
+ addons_client! "provision foo:bar --options.foo=bar --options.baz=test --consumer_id=app123@heroku.com"
60
+
61
+ assert_requested(:post, target_url,
62
+ :body => { :addon => 'foo', :plan => 'bar',
63
+ :consumer_id => 'app123@heroku.com',
64
+ :options => { :foo => 'bar', :baz => 'test'}})
65
+ assert_received(Addons::CLI) do |cli|
66
+ cli.puts "Provisioned foo:bar"
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,55 @@
1
+ require "#{File.dirname(__FILE__)}/test_helper"
2
+
3
+ # testing the canned responses with the mocks
4
+ # means we are both testing the mock mode and
5
+ # keeping the mocked responses in one place
6
+ class ResponseTest < Addons::Client::TestCase
7
+ def setup
8
+ super
9
+ Addons::Client.mock!
10
+ end
11
+
12
+ def teardown
13
+ super
14
+ Addons::Client.unmock!
15
+ end
16
+
17
+ def target_url
18
+ URI.join(ENV["ADDONS_API_URL"], '/api/1/resources').to_s
19
+ end
20
+
21
+ def test_response_parses_json
22
+ Addons::Client.unmock!
23
+ stub_request(:any, target_url).to_return(:body => {
24
+ 'resource_id' => '123-ABC',
25
+ 'config' => {'ADDON_URL' => 'foo'},
26
+ 'message' => 'great success',
27
+ 'provider_id' => '42'
28
+ }.to_json)
29
+
30
+ response = Addons::Client.provision! 'memcache:5mb'
31
+
32
+ assert_equal '123-ABC', response.resource_id
33
+ assert_equal 'foo', response.config['ADDON_URL']
34
+ assert_equal 'great success', response.message
35
+ assert_equal '42', response.provider_id
36
+ end
37
+
38
+ def test_response_object_wraps_provision_data
39
+ response = Addons::Client.provision! 'memcache:5mb'
40
+
41
+ assert_equal 'DEADBEEF', response.resource_id
42
+ assert_equal 'http://foo.com', response.config['MEMCACHE_URL']
43
+ assert_equal 'great success', response.message
44
+ assert_equal 'ABC123', response.provider_id
45
+ end
46
+
47
+ def test_response_object_wraps_deprovision
48
+ response = Addons::Client.deprovision! 'UUID'
49
+ end
50
+
51
+ def test_response_object_wraps_plan_change
52
+ response = Addons::Client.plan_change! 'UUID', 'plan'
53
+ end
54
+ end
55
+
@@ -0,0 +1,32 @@
1
+ require 'test/unit'
2
+ Bundler.require :test
3
+ require 'webmock/test_unit'
4
+ require "#{File.dirname(__FILE__)}/../lib/addons-client"
5
+
6
+ class Addons::Client::TestCase < Test::Unit::TestCase
7
+ include RR::Adapters::TestUnit
8
+
9
+ def setup
10
+ super
11
+ end
12
+
13
+ def resource_url
14
+ URI.join(ENV["ADDONS_API_URL"], '/api/1/resources/', 'addons-uuid').to_s
15
+ end
16
+
17
+ def teardown
18
+ super
19
+ WebMock.reset!
20
+ ::ARGV.replace []
21
+ Settings.replace Hash.new
22
+ end
23
+
24
+ def addons_client! cmd
25
+ ::ARGV.replace cmd.split
26
+ Addons::CLI.run!
27
+ end
28
+
29
+ # for ruby 1.8.7 Test::Unit compatibility
30
+ def default_test
31
+ end
32
+ end
metadata ADDED
@@ -0,0 +1,132 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: addons-client
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 2
10
+ version: 0.0.2
11
+ platform: ruby
12
+ authors:
13
+ - Chris Continanza
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2012-04-29 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ prerelease: false
22
+ type: :runtime
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 3
29
+ segments:
30
+ - 0
31
+ version: "0"
32
+ name: rest-client
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ prerelease: false
36
+ type: :runtime
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ hash: 3
43
+ segments:
44
+ - 0
45
+ version: "0"
46
+ name: configliere
47
+ version_requirements: *id002
48
+ - !ruby/object:Gem::Dependency
49
+ prerelease: false
50
+ type: :runtime
51
+ requirement: &id003 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ hash: 3
57
+ segments:
58
+ - 0
59
+ version: "0"
60
+ name: json
61
+ version_requirements: *id003
62
+ description: Addons Platform API client
63
+ email:
64
+ - csquared@gmail.com
65
+ executables:
66
+ - addons-client
67
+ extensions: []
68
+
69
+ extra_rdoc_files: []
70
+
71
+ files:
72
+ - .gitignore
73
+ - .travis.yml
74
+ - Gemfile
75
+ - LICENSE
76
+ - README.md
77
+ - Rakefile
78
+ - addons-client.gemspec
79
+ - bin/addons-client
80
+ - lib/addons-client.rb
81
+ - lib/addons-client/cli.rb
82
+ - lib/addons-client/client.rb
83
+ - lib/addons-client/mock.rb
84
+ - lib/addons-client/response.rb
85
+ - lib/addons-client/settings.rb
86
+ - lib/addons-client/version.rb
87
+ - test/client_test.rb
88
+ - test/deprovision_test.rb
89
+ - test/plan_change_test.rb
90
+ - test/provision_test.rb
91
+ - test/response_test.rb
92
+ - test/test_helper.rb
93
+ homepage: ""
94
+ licenses: []
95
+
96
+ post_install_message:
97
+ rdoc_options: []
98
+
99
+ require_paths:
100
+ - lib
101
+ required_ruby_version: !ruby/object:Gem::Requirement
102
+ none: false
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ hash: 3
107
+ segments:
108
+ - 0
109
+ version: "0"
110
+ required_rubygems_version: !ruby/object:Gem::Requirement
111
+ none: false
112
+ requirements:
113
+ - - ">="
114
+ - !ruby/object:Gem::Version
115
+ hash: 3
116
+ segments:
117
+ - 0
118
+ version: "0"
119
+ requirements: []
120
+
121
+ rubyforge_project:
122
+ rubygems_version: 1.8.15
123
+ signing_key:
124
+ specification_version: 3
125
+ summary: Allows platfomrs to provision, deprovision, and change plans for add-on resources.
126
+ test_files:
127
+ - test/client_test.rb
128
+ - test/deprovision_test.rb
129
+ - test/plan_change_test.rb
130
+ - test/provision_test.rb
131
+ - test/response_test.rb
132
+ - test/test_helper.rb