vault-invoice-builder-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.
@@ -0,0 +1,6 @@
1
+ .bundle/
2
+ .rvmrc
3
+ .yardoc/
4
+ doc/
5
+ vendor/
6
+ test/.test*
@@ -0,0 +1 @@
1
+ -m markdown
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source :rubygems
2
+
3
+ gemspec
4
+
5
+ group :development do
6
+ gem 'rake'
7
+ end
8
+
9
+ group :test do
10
+ gem 'rr'
11
+ gem 'vault-test-tools', '~> 0.2.2', :git => 'https://github.com/heroku/vault-test-tools.git'
12
+ end
@@ -0,0 +1,56 @@
1
+ GIT
2
+ remote: https://github.com/heroku/vault-test-tools.git
3
+ revision: 5eabd67610f279b81cadb803cee8ef704093a05d
4
+ specs:
5
+ vault-test-tools (0.2.2)
6
+ minitest
7
+ nokogiri
8
+ rack-perftools_profiler
9
+ rack-test
10
+ rdoc
11
+ redcarpet
12
+ turn
13
+ yard
14
+
15
+ PATH
16
+ remote: .
17
+ specs:
18
+ vault-invoice-builder-client (0.0.2)
19
+ excon
20
+ yajl-ruby
21
+
22
+ GEM
23
+ remote: http://rubygems.org/
24
+ specs:
25
+ ansi (1.4.3)
26
+ excon (0.16.10)
27
+ json (1.7.7)
28
+ minitest (4.6.0)
29
+ nokogiri (1.5.6)
30
+ open4 (1.3.0)
31
+ perftools.rb (2.0.0)
32
+ rack (1.5.2)
33
+ rack-perftools_profiler (0.6.0)
34
+ open4 (~> 1.0)
35
+ perftools.rb (~> 2.0.0)
36
+ rack (~> 1.0)
37
+ rack-test (0.6.2)
38
+ rack (>= 1.0)
39
+ rake (10.0.3)
40
+ rdoc (3.12.1)
41
+ json (~> 1.4)
42
+ redcarpet (2.2.2)
43
+ rr (1.0.4)
44
+ turn (0.9.6)
45
+ ansi
46
+ yajl-ruby (1.1.0)
47
+ yard (0.8.4.1)
48
+
49
+ PLATFORMS
50
+ ruby
51
+
52
+ DEPENDENCIES
53
+ rake
54
+ rr
55
+ vault-invoice-builder-client!
56
+ vault-test-tools (~> 0.2.2)!
@@ -0,0 +1,67 @@
1
+ # Vault::InvoiceBuilder::Client
2
+
3
+ A Ruby client for the `Vault::InvoiceBuilder` HTTP API.
4
+
5
+ ## Setting up a development environment
6
+
7
+ Install dependencies and run the test suite:
8
+
9
+ bundle install --binstubs vendor/bin
10
+ rbenv rehash
11
+ rake
12
+
13
+ Run tests:
14
+
15
+ rake test
16
+
17
+ See tasks:
18
+
19
+ rake -T
20
+
21
+ Generate API documentation:
22
+
23
+ rake yard
24
+
25
+ ## Using the client
26
+
27
+ The `Vault::InvoiceBuilder` API may only be accessed anonymously:
28
+
29
+ ```ruby
30
+ require 'vault-invoice-builder-client'
31
+
32
+ client = Vault::InvoiceBuilder::Client.new(
33
+ 'https://vault-invoice-builder.herokuapp.com')
34
+ ```
35
+
36
+ For endpoints that require authentication, HTTP Basic credentials must
37
+ be supplied in the URL:
38
+
39
+ ```ruby
40
+ client = Vault::InvoiceBuilder::Client.new(
41
+ 'https://username:password@vault-invoice-builder.herokuapp.com')
42
+ ```
43
+
44
+ ### Rendering an invoice.
45
+
46
+ An invoice contains customer contact and tax details, a list of apps
47
+ and the charges they've incurred by consuming dyno hours and using
48
+ addons, a list of charges for products the customer used directly,
49
+ such as a support contract, and credits that have been applied to
50
+ cover some or all of the charges on the invoice. An invoice is
51
+ rendered from a receipt, a JSON representation of app and user charges
52
+ and credits.
53
+
54
+ ```ruby
55
+ receipt = {user: 'user123@heroku.com', start_time: …, …}
56
+ html_content = client.render_html(receipt)
57
+ ```
58
+
59
+ ### Storing an invoice
60
+ The `store` method can be used to render an invoice and then store it
61
+ to S3. The same receipt JSON object is passed and an empty 200 OK
62
+ response is returned if the request was successful.
63
+
64
+ ```ruby
65
+ receipt = {user: 'user123@heroku.com', start_time: …, …}
66
+ response = client.store(receipt)
67
+ ```
@@ -0,0 +1,11 @@
1
+ require "bundler/gem_tasks"
2
+ require 'yard'
3
+
4
+ desc "Test the things"
5
+ require 'vault-test-tools/rake_task'
6
+
7
+ desc "Doc the things"
8
+ YARD::Rake::YardocTask.new
9
+
10
+ desc "Run the test suite"
11
+ task :default => [:test]
@@ -0,0 +1,17 @@
1
+ require 'bundler'
2
+ Bundler.require :default, ENV['RACK_ENV'].to_sym
3
+
4
+ require 'excon'
5
+ require 'yajl/json_gem'
6
+
7
+ module Vault
8
+ module InvoiceBuilder
9
+ # Client provides a Ruby API to access the `Vault::InvoiceBuilder` HTTP
10
+ # API.
11
+ class Client
12
+ end
13
+ end
14
+ end
15
+
16
+ require 'vault-invoice-builder-client/client'
17
+ require 'vault-invoice-builder-client/version'
@@ -0,0 +1,67 @@
1
+ module Vault::InvoiceBuilder
2
+ # Client for the `Vault::InvoiceBuilder` HTTP API.
3
+ class Client
4
+ # The `Vault::InvoiceBuilder` HTTP API URL.
5
+ attr_reader :url
6
+
7
+ # Instantiate a client.
8
+ #
9
+ # @param url [String] The URL to connect to. Include the username and
10
+ # password to use when connecting. Defaults to the URL defined in the
11
+ # `VAULT_INVOICE_BUILDER_URL` environment variable if one isn't
12
+ # explicitly provided.
13
+ def initialize(url = nil)
14
+ @url = url || ENV['VAULT_INVOICE_BUILDER_URL']
15
+ end
16
+
17
+ # Render a statement into an HTML invoice.
18
+ #
19
+ # @param statement [Hash] An object matching the statement format described in
20
+ # the `Vault::InvoiceBuilder` README.
21
+ # @raise [Excon::Errors::HTTPStatusError] Raised if the server returns an
22
+ # unsuccessful HTTP status code.
23
+ # @return [String] The rendered HTML invoice.
24
+ def render_html(statement)
25
+ connection = Excon.new(@url)
26
+ response = connection.post(
27
+ path: "/invoice.html",
28
+ headers: {'Content-Type' => 'application/json'},
29
+ body: JSON.generate(statement),
30
+ expects: [200])
31
+ response.body
32
+ end
33
+
34
+ # POST a statement to to the proxy-able /statement/:id endpoint
35
+ #
36
+ # @param statement [Hash] An object matching the statement format described in
37
+ # the `Vault::InvoiceBuilder` README.
38
+ # @raise [Excon::Errors::HTTPStatusError] Raised if the server returns an
39
+ # unsuccessful HTTP status code.
40
+ # @return [Excon::Response] The response object.
41
+ def post(statement)
42
+ connection = Excon.new(@url)
43
+ id = statement[:id] || statement['id']
44
+ response = connection.post(
45
+ path: "/statement/#{id}",
46
+ headers: {'Content-Type' => 'application/json'},
47
+ body: JSON.generate(statement),
48
+ expects: [200])
49
+ end
50
+
51
+ # @deprecated
52
+ #
53
+ # @param statement [Hash] An object matching the statement format described in
54
+ # the `Vault::InvoiceBuilder` README.
55
+ # @raise [Excon::Errors::HTTPStatusError] Raised if the server returns an
56
+ # unsuccessful HTTP status code.
57
+ # @return [Excon::Response] The response object.
58
+ def store(statement)
59
+ connection = Excon.new(@url)
60
+ response = connection.post(
61
+ path: '/store',
62
+ headers: {'Content-Type' => 'application/json'},
63
+ body: JSON.generate(statement),
64
+ expects: [200])
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,8 @@
1
+ module Vault
2
+ module InvoiceBuilder
3
+ class Client
4
+ # The `Vault::InvoiceBuilder::Client` gem version.
5
+ VERSION = '0.0.2'
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,132 @@
1
+ require 'helper'
2
+
3
+ class ClientTest < Vault::TestCase
4
+ include Vault::Test::EnvironmentHelpers
5
+
6
+ def setup
7
+ super
8
+ Excon.stubs.clear
9
+ Excon.defaults[:mock] = true
10
+ @client = Vault::InvoiceBuilder::Client.new(
11
+ 'https://vault-invoice-builder.herokuapp.com')
12
+ @statement = {user: 'user123@heroku.com',
13
+ start_time: Time.utc(2012, 1),
14
+ stop_time: Time.utc(2012, 2)}
15
+ end
16
+
17
+ def teardown
18
+ # FIXME This is a bit ugly, but Excon doesn't provide a builtin way to
19
+ # ensure that a request was invoked, so we have to do it ourselves.
20
+ # Without this, and the Excon.stubs.pop calls in the tests below, tests
21
+ # will pass if request logic is completely removed from application
22
+ # code. -jkakar
23
+ assert(Excon.stubs.empty?, 'Expected HTTP requests were not made.')
24
+ super
25
+ end
26
+
27
+ # Client.new looks for VAULT_INVOICE_BUILDER_URL if none is passed to the
28
+ # constructor.
29
+ def test_uses_url_from_environment_by_default
30
+ url = 'http://example.com'
31
+ set_env 'VAULT_INVOICE_BUILDER_URL', url
32
+ @client = Vault::InvoiceBuilder::Client.new
33
+ assert_equal(url, @client.url)
34
+ end
35
+
36
+ # Client.render_html makes a PUT request to the Vault::InvoiceBuilder HTTP
37
+ # API, passing the supplied credentials using HTTP basic auth, to report
38
+ # that usage of a product began at a particular time.
39
+ def test_render_html
40
+ content = '<html><body><p>Hello, world!</p></body></html>'
41
+ Excon.stub(method: :post) do |request|
42
+ assert_equal('vault-invoice-builder.herokuapp.com:443',
43
+ request[:host_port])
44
+ assert_equal("/invoice.html", request[:path])
45
+ Excon.stubs.pop
46
+ {status: 200, body: content}
47
+ end
48
+ assert_equal(content, @client.render_html(@statement))
49
+ end
50
+
51
+ # Client.render_html raises the appropriate Excon::Errors::HTTPStatusError
52
+ # if an unsuccessful HTTP status code is returned by the server.
53
+ def test_render_html_with_unsuccessful_response
54
+ Excon.stub(method: :post) do |request|
55
+ Excon.stubs.pop
56
+ {status: 400, body: 'Bad inputs provided.'}
57
+ end
58
+ assert_raises Excon::Errors::BadRequest do
59
+ @client.render_html(@statement)
60
+ end
61
+ end
62
+
63
+ # Client.store makes a POST request to the Vault::InvoiceBuilder HTTP API,
64
+ # passing the supplied credentials using HTTP Basic Auth, to which triggers
65
+ # Vault::InvoiceBuilder to generate the invoice and store it to S3.
66
+ def test_store
67
+ Excon.stub(method: :post) do |request|
68
+ assert_equal('vault-invoice-builder.herokuapp.com:443',
69
+ request[:host_port])
70
+ assert_equal('/store', request[:path])
71
+ assert_equal('application/json', request[:headers]['Content-Type'])
72
+ Excon.stubs.pop
73
+ {status: 200}
74
+ end
75
+ response = @client.store(@statement)
76
+ assert_equal(200, response.status)
77
+ end
78
+
79
+ # Client.store raises the appropriate Excon::Errors::HTTPStatusError if an
80
+ # unsuccessful HTTP status code is returned by the server.
81
+ def test_store_with_unsuccessful_response
82
+ Excon.stub(method: :post) do |request|
83
+ Excon.stubs.pop
84
+ {status: 400, body: 'Bad inputs provided.'}
85
+ end
86
+ assert_raises Excon::Errors::BadRequest do
87
+ @client.store(@statement)
88
+ end
89
+ end
90
+
91
+ # Client.post makes a POST request to the canonical statement drain API
92
+ def test_post_with_symbol_id_key
93
+ @statement[:id] = 1
94
+ Excon.stub(method: :post) do |request|
95
+ assert_equal('vault-invoice-builder.herokuapp.com:443',
96
+ request[:host_port])
97
+ assert_equal('/statement/1', request[:path])
98
+ assert_equal('application/json', request[:headers]['Content-Type'])
99
+ Excon.stubs.pop
100
+ {status: 200}
101
+ end
102
+ response = @client.post(@statement)
103
+ assert_equal(200, response.status)
104
+ end
105
+
106
+ # Client.post makes a POST request to the canonical statement drain API
107
+ def test_post_with_string_id_key
108
+ @statement['id'] = 1
109
+ Excon.stub(method: :post) do |request|
110
+ assert_equal('vault-invoice-builder.herokuapp.com:443',
111
+ request[:host_port])
112
+ assert_equal('/statement/1', request[:path])
113
+ assert_equal('application/json', request[:headers]['Content-Type'])
114
+ Excon.stubs.pop
115
+ {status: 200}
116
+ end
117
+ response = @client.post(@statement)
118
+ assert_equal(200, response.status)
119
+ end
120
+
121
+ # Client.store raises the appropriate Excon::Errors::HTTPStatusError if an
122
+ # unsuccessful HTTP status code is returned by the server.
123
+ def test_post_with_unsuccessful_response
124
+ Excon.stub(method: :post) do |request|
125
+ Excon.stubs.pop
126
+ {status: 400, body: 'Bad inputs provided.'}
127
+ end
128
+ assert_raises Excon::Errors::BadRequest do
129
+ @client.post(@statement)
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,4 @@
1
+ ENV['RACK_ENV'] = 'test'
2
+
3
+ require 'vault-invoice-builder-client'
4
+ require 'vault-test-tools'
@@ -0,0 +1,9 @@
1
+ require 'helper'
2
+
3
+ class VersionTest < Vault::TestCase
4
+ # Vault::InvoiceBuilder::Client::VERSION is a string matching the
5
+ # `major.minor.patch` format.
6
+ def test_version
7
+ assert_match(/\d+\.\d+\.\d+/, Vault::InvoiceBuilder::Client::VERSION)
8
+ end
9
+ end
@@ -0,0 +1,21 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'vault-invoice-builder-client/version'
4
+
5
+ Gem::Specification.new do |gem|
6
+ gem.name = "vault-invoice-builder-client"
7
+ gem.version = Vault::InvoiceBuilder::Client::VERSION
8
+ gem.authors = ["Chris Continanza", "Jamu Kakar", "Matthew Manning"]
9
+ gem.email = ["csquared@heroku.com", "jkakar@heroku.com",
10
+ "matthew@heroku.com"]
11
+ gem.description = "Client for Vault::InvoiceBuilder"
12
+ gem.summary = "A simple wrapper for the Vault::InvoiceBuilder HTTP API"
13
+ gem.homepage = "https://github.com/heroku/vault-invoice-builder-client"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.test_files = gem.files.grep('^(test|spec|features)/')
17
+ gem.require_paths = ["lib"]
18
+
19
+ gem.add_dependency 'excon'
20
+ gem.add_dependency 'yajl-ruby'
21
+ end
metadata ADDED
@@ -0,0 +1,101 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vault-invoice-builder-client
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Chris Continanza
9
+ - Jamu Kakar
10
+ - Matthew Manning
11
+ autorequire:
12
+ bindir: bin
13
+ cert_chain: []
14
+ date: 2013-05-09 00:00:00.000000000 Z
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: excon
18
+ requirement: !ruby/object:Gem::Requirement
19
+ none: false
20
+ requirements:
21
+ - - ! '>='
22
+ - !ruby/object:Gem::Version
23
+ version: '0'
24
+ type: :runtime
25
+ prerelease: false
26
+ version_requirements: !ruby/object:Gem::Requirement
27
+ none: false
28
+ requirements:
29
+ - - ! '>='
30
+ - !ruby/object:Gem::Version
31
+ version: '0'
32
+ - !ruby/object:Gem::Dependency
33
+ name: yajl-ruby
34
+ requirement: !ruby/object:Gem::Requirement
35
+ none: false
36
+ requirements:
37
+ - - ! '>='
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ none: false
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ description: Client for Vault::InvoiceBuilder
49
+ email:
50
+ - csquared@heroku.com
51
+ - jkakar@heroku.com
52
+ - matthew@heroku.com
53
+ executables: []
54
+ extensions: []
55
+ extra_rdoc_files: []
56
+ files:
57
+ - .gitignore
58
+ - .yardopts
59
+ - Gemfile
60
+ - Gemfile.lock
61
+ - README.md
62
+ - Rakefile
63
+ - lib/vault-invoice-builder-client.rb
64
+ - lib/vault-invoice-builder-client/client.rb
65
+ - lib/vault-invoice-builder-client/version.rb
66
+ - test/client_test.rb
67
+ - test/helper.rb
68
+ - test/version_test.rb
69
+ - vault-invoice-builder-client.gemspec
70
+ homepage: https://github.com/heroku/vault-invoice-builder-client
71
+ licenses: []
72
+ post_install_message:
73
+ rdoc_options: []
74
+ require_paths:
75
+ - lib
76
+ required_ruby_version: !ruby/object:Gem::Requirement
77
+ none: false
78
+ requirements:
79
+ - - ! '>='
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ segments:
83
+ - 0
84
+ hash: -3070326704752709441
85
+ required_rubygems_version: !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
88
+ - - ! '>='
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ segments:
92
+ - 0
93
+ hash: -3070326704752709441
94
+ requirements: []
95
+ rubyforge_project:
96
+ rubygems_version: 1.8.23
97
+ signing_key:
98
+ specification_version: 3
99
+ summary: A simple wrapper for the Vault::InvoiceBuilder HTTP API
100
+ test_files: []
101
+ has_rdoc: