shipping_easy 0.0.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rspec +2 -0
- data/Rakefile +3 -0
- data/lib/shipping_easy.rb +39 -2
- data/lib/shipping_easy/configuration.rb +29 -0
- data/lib/shipping_easy/http.rb +2 -0
- data/lib/shipping_easy/http/faraday_adapter.rb +30 -0
- data/lib/shipping_easy/http/request.rb +51 -0
- data/lib/shipping_easy/http/response_handler.rb +27 -0
- data/lib/shipping_easy/resources.rb +2 -0
- data/lib/shipping_easy/resources/base.rb +16 -0
- data/lib/shipping_easy/resources/cancellation.rb +7 -0
- data/lib/shipping_easy/resources/order.rb +7 -0
- data/lib/shipping_easy/signature.rb +2 -1
- data/lib/shipping_easy/version.rb +1 -1
- data/shipping_easy.gemspec +4 -1
- data/spec/authenticator_spec.rb +76 -0
- data/spec/configuration_spec.rb +31 -0
- data/spec/http/faraday_adapter_spec.rb +42 -0
- data/spec/http/request_spec.rb +81 -0
- data/spec/http/response_handler_spec.rb +33 -0
- data/spec/resources/base_spec.rb +39 -0
- data/spec/signature_spec.rb +40 -0
- data/spec/spec_helper.rb +20 -0
- metadata +79 -14
- data/lib/shipping_easy/resources/cancellations.rb +0 -0
- data/lib/shipping_easy/resources/store.rb +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b51569e520e425f916ee5b73f0fcd9086ec23aa1
|
4
|
+
data.tar.gz: 5c9bf4c89f508e002327c37b3670fd3ac3fdd0b8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0d2f8ce7d601b671c76186ab78eebe8fc2ccc886abf7af13c2adcc3a5071f10a134ea4511db8749ba97854d196dc59547d31918da9ac389711ff2832744c20fe
|
7
|
+
data.tar.gz: e7c656651793f6fc67c5883e44b09e1d33397383ce5be7e87b7edc39fb65b129662846942363efc9311128b1b8651574ea6e1824c5667966d1433ef9078e28fe
|
data/.rspec
ADDED
data/Rakefile
CHANGED
data/lib/shipping_easy.rb
CHANGED
@@ -1,10 +1,47 @@
|
|
1
|
-
|
1
|
+
|
2
|
+
require "faraday"
|
3
|
+
require "rack"
|
4
|
+
require "json"
|
5
|
+
require "shipping_easy/authenticator"
|
6
|
+
require "shipping_easy/configuration"
|
7
|
+
require "shipping_easy/signature"
|
8
|
+
require "shipping_easy/http"
|
9
|
+
require "shipping_easy/http/faraday_adapter"
|
10
|
+
require "shipping_easy/http/request"
|
11
|
+
require "shipping_easy/http/response_handler"
|
12
|
+
require "shipping_easy/resources"
|
13
|
+
require "shipping_easy/resources/base"
|
14
|
+
require "shipping_easy/resources/order"
|
15
|
+
require "shipping_easy/resources/cancellation"
|
2
16
|
require "shipping_easy/version"
|
3
17
|
|
4
18
|
module ShippingEasy
|
5
19
|
|
6
|
-
class
|
20
|
+
class << self
|
21
|
+
|
22
|
+
attr_accessor :configuration
|
23
|
+
|
24
|
+
def configure
|
25
|
+
configuration = ShippingEasy::Configuration.new
|
26
|
+
yield(configuration)
|
27
|
+
self.configuration = configuration
|
28
|
+
end
|
29
|
+
|
30
|
+
def api_secret
|
31
|
+
configuration.api_secret
|
32
|
+
end
|
7
33
|
|
34
|
+
def api_key
|
35
|
+
configuration.api_key
|
36
|
+
end
|
37
|
+
|
38
|
+
def base_url
|
39
|
+
configuration.base_url
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class Error < StandardError; end
|
44
|
+
class ResourceNotFoundError < Error; end
|
8
45
|
class RequestExpiredError < Error
|
9
46
|
def initialize(msg = "The request has expired.")
|
10
47
|
super(msg)
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# Configuration class that stores configuration options for the ShippingEasy API.
|
2
|
+
#
|
3
|
+
# ShippingEasy requires an API key and secret combination to authenticate against its API. At the very least these must be
|
4
|
+
# supplied in the configuration.
|
5
|
+
#
|
6
|
+
# Configuration options are typically set via the ShippingEasy.config method.
|
7
|
+
# @see ShippingEasy.configure
|
8
|
+
# @example
|
9
|
+
# ShippingEasy.configure do |config|
|
10
|
+
# config.api_key = "12345"
|
11
|
+
# config.api_secret = "XXXXXXXXXXXXXXXXXXXXXXXX"
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
module ShippingEasy
|
15
|
+
class Configuration
|
16
|
+
|
17
|
+
attr_accessor :api_key,
|
18
|
+
:api_secret,
|
19
|
+
:api_version,
|
20
|
+
:base_url,
|
21
|
+
:http_adapter
|
22
|
+
|
23
|
+
# Creates a configuration object, setting the default attributes.
|
24
|
+
def initialize
|
25
|
+
@http_adapter = ShippingEasy::Http::FaradayAdapter
|
26
|
+
@base_url = "https://app.shippingeasy.com"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class ShippingEasy::Http::FaradayAdapter
|
2
|
+
|
3
|
+
extend Forwardable
|
4
|
+
|
5
|
+
def_delegators :request, :body, :params, :base_url, :http_method, :uri
|
6
|
+
|
7
|
+
attr_reader :request
|
8
|
+
|
9
|
+
def initialize(request)
|
10
|
+
@request = request
|
11
|
+
end
|
12
|
+
|
13
|
+
def connect!
|
14
|
+
send(http_method)
|
15
|
+
end
|
16
|
+
|
17
|
+
def post
|
18
|
+
connection.post do |req|
|
19
|
+
req.url uri, params
|
20
|
+
req.body = request.body
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def connection
|
25
|
+
@connection ||= Faraday.new(url: base_url) do |faraday|
|
26
|
+
faraday.adapter Faraday.default_adapter
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
class ShippingEasy::Http::Request
|
2
|
+
|
3
|
+
attr_accessor :http_method, :body, :params, :relative_path
|
4
|
+
|
5
|
+
def initialize(options = {})
|
6
|
+
@http_method = options.fetch(:http_method, :get)
|
7
|
+
@params = options.fetch(:params, {})
|
8
|
+
@body = options.fetch(:payload, {}).to_json
|
9
|
+
@relative_path = options.delete(:relative_path)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.connect!(options = {})
|
13
|
+
new(options).connect!
|
14
|
+
end
|
15
|
+
|
16
|
+
def connect!
|
17
|
+
sign_request!
|
18
|
+
adapter.connect!
|
19
|
+
end
|
20
|
+
|
21
|
+
def sign_request!
|
22
|
+
params[:api_key] = api_key
|
23
|
+
params[:api_timestamp] = Time.now.to_i
|
24
|
+
params[:api_signature] = signature.to_s
|
25
|
+
end
|
26
|
+
|
27
|
+
def uri
|
28
|
+
"/api#{relative_path}"
|
29
|
+
end
|
30
|
+
|
31
|
+
def signature
|
32
|
+
ShippingEasy::Signature.new(api_secret: api_secret, method: http_method, path: uri, params: params, body: body)
|
33
|
+
end
|
34
|
+
|
35
|
+
def adapter
|
36
|
+
ShippingEasy.configuration.http_adapter.new(self)
|
37
|
+
end
|
38
|
+
|
39
|
+
def api_secret
|
40
|
+
ShippingEasy.api_secret
|
41
|
+
end
|
42
|
+
|
43
|
+
def api_key
|
44
|
+
ShippingEasy.api_key
|
45
|
+
end
|
46
|
+
|
47
|
+
def base_url
|
48
|
+
ShippingEasy.base_url
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class ShippingEasy::Http::ResponseHandler
|
2
|
+
|
3
|
+
extend Forwardable
|
4
|
+
|
5
|
+
def_delegators :response, :status, :body
|
6
|
+
|
7
|
+
attr_reader :response
|
8
|
+
|
9
|
+
def initialize(response)
|
10
|
+
@response = response
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.run(response)
|
14
|
+
new(response).run
|
15
|
+
end
|
16
|
+
|
17
|
+
def run
|
18
|
+
case status
|
19
|
+
when 401 then raise ShippingEasy::AccessDeniedError, response.body
|
20
|
+
when 404 then raise ShippingEasy::ResourceNotFoundError, response.body
|
21
|
+
when 200, 201 then JSON.parse(response.body)
|
22
|
+
else
|
23
|
+
raise ShippingEasy::Error, response.body
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class ShippingEasy::Resources::Base
|
2
|
+
|
3
|
+
def self.command(name, command_options, &block)
|
4
|
+
define_singleton_method name do |options = {}|
|
5
|
+
options[:relative_path] = command_options.fetch(:relative_path, block.call(options))
|
6
|
+
options[:http_method] = command_options.fetch(:http_method, :get)
|
7
|
+
execute_request!(options)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.execute_request!(options = {})
|
12
|
+
response = ShippingEasy::Http::Request.connect!(options)
|
13
|
+
ShippingEasy::Http::ResponseHandler.run(response)
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
@@ -64,7 +64,8 @@ module ShippingEasy
|
|
64
64
|
# Returns true if the supplied string or signature object matches the current object.
|
65
65
|
def ==(other_signature)
|
66
66
|
expected_signature, supplied_signature = self.to_s, other_signature.to_s
|
67
|
-
return false if expected_signature.
|
67
|
+
return false if expected_signature.nil? || supplied_signature.nil? || expected_signature.empty? || supplied_signature.empty?
|
68
|
+
return false if expected_signature.bytesize != supplied_signature.bytesize
|
68
69
|
l = expected_signature.unpack "C#{expected_signature.bytesize}"
|
69
70
|
res = 0
|
70
71
|
supplied_signature.each_byte { |byte| res |= byte ^ l.shift }
|
data/shipping_easy.gemspec
CHANGED
@@ -18,6 +18,9 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
+
spec.add_dependency('faraday', '>= 0.8.7')
|
22
|
+
spec.add_dependency('rack', ">= 1.4.5")
|
23
|
+
spec.add_dependency('json', "~> 1.8.0")
|
21
24
|
spec.add_development_dependency "bundler", "~> 1.3"
|
22
|
-
spec.add_development_dependency "
|
25
|
+
spec.add_development_dependency "rspec"
|
23
26
|
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ShippingEasy::Authenticator, api: true do
|
4
|
+
let(:api_secret) { "ABC12345" }
|
5
|
+
let(:method) { :post }
|
6
|
+
let(:path) { "/api/orders" }
|
7
|
+
let(:api_signature) { signature.to_s }
|
8
|
+
let(:api_timestamp) { (Time.now - (60 * 5)).to_i }
|
9
|
+
let(:params) { { test_param: "ABCDE", api_key: "123", api_timestamp: api_timestamp } }
|
10
|
+
let(:params_with_signature) { params[:api_signature] = api_signature; params }
|
11
|
+
let(:request_body) { { orders: { name: "Flip flops", cost: "10.00", shipping_cost: "2.00" } }.to_json.to_s }
|
12
|
+
let(:method) { :post }
|
13
|
+
let(:signature) { ShippingEasy::Signature.new(api_secret: api_secret, method: method, path: path, params: params, body: request_body) }
|
14
|
+
subject { ShippingEasy::Authenticator.new(api_secret: api_secret, method: method, path: path, params: params_with_signature, body: request_body) }
|
15
|
+
|
16
|
+
describe "#initialize" do
|
17
|
+
specify { subject.api_secret.should == api_secret }
|
18
|
+
specify { subject.method.should == :post }
|
19
|
+
specify { subject.path.should == path }
|
20
|
+
specify { subject.body.should == request_body }
|
21
|
+
specify { subject.params.should == params_with_signature }
|
22
|
+
specify { subject.params[:api_signature].should be_nil }
|
23
|
+
specify { subject.expected_signature.should be_a(ShippingEasy::Signature) }
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "#request_expires_at" do
|
27
|
+
specify { subject.request_expires_at.to_s.should == (Time.now - ShippingEasy::Authenticator::EXPIRATION_INTERVAL).to_s }
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "#request_expired?" do
|
31
|
+
specify { subject.request_expired?.should be_false }
|
32
|
+
|
33
|
+
context "when expired" do
|
34
|
+
let(:api_timestamp) { (Time.now - (ShippingEasy::Authenticator::EXPIRATION_INTERVAL * 2)).to_i }
|
35
|
+
specify { subject.request_expired?.should be_true }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "#signatures_match?" do
|
40
|
+
specify { subject.signatures_match?.should be_true }
|
41
|
+
|
42
|
+
context "when they don't match" do
|
43
|
+
let(:api_signature) { "XXX" }
|
44
|
+
specify { subject.signatures_match?.should be_false }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "#parsed_timestamp" do
|
49
|
+
specify { subject.parsed_timestamp.should be_a(Time) }
|
50
|
+
context "when date string is invalid" do
|
51
|
+
let(:api_timestamp) { "xxxx" }
|
52
|
+
specify { expect{ subject.parsed_timestamp }.to raise_error(ShippingEasy::TimestampFormatError) }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "#authenticate" do
|
57
|
+
context "when everything is ok" do
|
58
|
+
before do
|
59
|
+
subject.stub(:request_expired?).and_return(false)
|
60
|
+
subject.stub(:signatures_match?).and_return(true)
|
61
|
+
end
|
62
|
+
specify { subject.authenticate.should be_true }
|
63
|
+
end
|
64
|
+
|
65
|
+
context "when request has expired" do
|
66
|
+
before { subject.stub(:request_expired?).and_return(true) }
|
67
|
+
specify { expect{ subject.authenticate }.to raise_error(ShippingEasy::RequestExpiredError)}
|
68
|
+
end
|
69
|
+
|
70
|
+
context "when signatures do not match" do
|
71
|
+
before { subject.stub(:signatures_match?).and_return(false) }
|
72
|
+
specify { expect{ subject.authenticate }.to raise_error(ShippingEasy::AccessDeniedError) }
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe ShippingEasy::Configuration do
|
4
|
+
subject { ShippingEasy::Configuration.new }
|
5
|
+
|
6
|
+
specify { subject.should respond_to(:api_key) }
|
7
|
+
specify { subject.should respond_to(:api_secret) }
|
8
|
+
specify { subject.should respond_to(:base_url) }
|
9
|
+
|
10
|
+
describe "http_adapter" do
|
11
|
+
it "gets set to a default" do
|
12
|
+
subject.http_adapter.should == ShippingEasy::Http::FaradayAdapter
|
13
|
+
end
|
14
|
+
|
15
|
+
it "can be overidden" do
|
16
|
+
subject.http_adapter = String
|
17
|
+
subject.http_adapter.should == String
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "base_url" do
|
22
|
+
it "gets set to a default" do
|
23
|
+
subject.base_url.should == "https://app.shippingeasy.com"
|
24
|
+
end
|
25
|
+
|
26
|
+
it "can be overidden" do
|
27
|
+
subject.base_url = String
|
28
|
+
subject.base_url.should == String
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe ShippingEasy::Http::FaradayAdapter do
|
4
|
+
|
5
|
+
let(:http_method) { "post" }
|
6
|
+
let(:params) { { "page" => 1 } }
|
7
|
+
let(:base_url) { "https://www.test.com" }
|
8
|
+
let(:uri) { "/api/orders" }
|
9
|
+
let(:body) { { order_number: "1234" }.to_json }
|
10
|
+
|
11
|
+
let(:request) do
|
12
|
+
double("request",
|
13
|
+
http_method: http_method,
|
14
|
+
params: params,
|
15
|
+
base_url: base_url,
|
16
|
+
uri: uri,
|
17
|
+
body: body)
|
18
|
+
end
|
19
|
+
|
20
|
+
subject { ShippingEasy::Http::FaradayAdapter.new(request) }
|
21
|
+
|
22
|
+
[:http_method, :params, :base_url, :uri, :body].each do |m|
|
23
|
+
it "delegates #{m} to request" do
|
24
|
+
subject.send(m).should == request.send(m)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "#connect!" do
|
29
|
+
it "calls the correct http method as specified by the request" do
|
30
|
+
subject.stub(:post)
|
31
|
+
subject.should_receive(:post).once
|
32
|
+
subject.connect!
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "#connection" do
|
37
|
+
it "instantiates a faraday connection" do
|
38
|
+
subject.connection.should be_a(Faraday::Connection)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe ShippingEasy::Http::Request do
|
4
|
+
|
5
|
+
let(:http_method) { "post" }
|
6
|
+
let(:params) { { :page => 1 } }
|
7
|
+
let(:base_url) { "https://www.test.com" }
|
8
|
+
let(:relative_path) { "/orders" }
|
9
|
+
let(:body) { { order_number: "1234" } }
|
10
|
+
let(:api_key) { "12345678ASGHSGHJ" }
|
11
|
+
let(:api_secret) { "12345678ASGHSGHJ123213321312" }
|
12
|
+
let(:signature) { ShippingEasy::Signature.new(api_secret: api_secret, method: http_method, path: "/api#{relative_path}", params: params.dup, body: body.to_json) }
|
13
|
+
|
14
|
+
before do
|
15
|
+
ShippingEasy.configure do |config|
|
16
|
+
config.api_key = api_key
|
17
|
+
config.api_secret = api_secret
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
subject { ShippingEasy::Http::Request.new(http_method: http_method, params: params, relative_path: relative_path, payload: body) }
|
22
|
+
|
23
|
+
[:http_method, :params, :relative_path].each do |m|
|
24
|
+
it "parses and sets the option named #{m}" do
|
25
|
+
subject.send(m).should == send(m)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "#api_secret" do
|
30
|
+
it "delegates the api_secret to the config" do
|
31
|
+
subject.api_secret.should == ShippingEasy.api_secret
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "#api_key" do
|
36
|
+
it "delegates the api_key to the config" do
|
37
|
+
subject.api_key.should == ShippingEasy.api_key
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "#adpater" do
|
42
|
+
it "instantiates a new adapter" do
|
43
|
+
subject.adapter.should be_a(ShippingEasy::Http::FaradayAdapter)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "#signature" do
|
48
|
+
it "returns a calculated sigature object" do
|
49
|
+
subject.signature.to_s.should == signature.to_s
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "#sign_request!" do
|
54
|
+
before { subject.sign_request! }
|
55
|
+
|
56
|
+
it "adds the api signature parameter to the params hash" do
|
57
|
+
subject.params[:api_signature].should_not be_nil
|
58
|
+
end
|
59
|
+
|
60
|
+
it "adds the api timestamp parameter to the params hash" do
|
61
|
+
subject.params[:api_timestamp].should_not be_nil
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "#connect" do
|
66
|
+
before do
|
67
|
+
subject.stub(:sign_request!)
|
68
|
+
subject.stub_chain(:adapter, :connect!).and_return("connected!")
|
69
|
+
end
|
70
|
+
|
71
|
+
it "signs the request" do
|
72
|
+
subject.should_receive(:sign_request!).once
|
73
|
+
subject.connect!
|
74
|
+
end
|
75
|
+
|
76
|
+
it "connects via the adapter" do
|
77
|
+
subject.connect!.should == "connected!"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe ShippingEasy::Http::ResponseHandler do
|
4
|
+
|
5
|
+
let(:status) { 200 }
|
6
|
+
let(:body) { { "order_number" => "12345" }}
|
7
|
+
let(:response) do
|
8
|
+
double("response",
|
9
|
+
status: status,
|
10
|
+
body: body.to_json)
|
11
|
+
end
|
12
|
+
|
13
|
+
subject { ShippingEasy::Http::ResponseHandler.new(response) }
|
14
|
+
|
15
|
+
describe "#run" do
|
16
|
+
context "when success" do
|
17
|
+
specify { subject.run.should == body }
|
18
|
+
end
|
19
|
+
context "when authentication fails" do
|
20
|
+
let(:status) { 401 }
|
21
|
+
specify { expect { subject.run }.to raise_error(ShippingEasy::AccessDeniedError) }
|
22
|
+
end
|
23
|
+
context "when resource cannot be found" do
|
24
|
+
let(:status) { 404 }
|
25
|
+
specify { expect { subject.run }.to raise_error(ShippingEasy::ResourceNotFoundError) }
|
26
|
+
end
|
27
|
+
context "when unexpected error occurs" do
|
28
|
+
let(:status) { 500 }
|
29
|
+
specify { expect { subject.run }.to raise_error(ShippingEasy::Error) }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe ShippingEasy::Resources::Base do
|
4
|
+
|
5
|
+
class GenericResource < ShippingEasy::Resources::Base; end
|
6
|
+
|
7
|
+
describe ".command" do
|
8
|
+
before { GenericResource.command(:create, method: :post) }
|
9
|
+
|
10
|
+
it "defines a method on the class" do
|
11
|
+
GenericResource.should respond_to(:create)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "extracts options to send to a request" do
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
context "when a block is provided" do
|
19
|
+
it "uses it as the value for the path" do
|
20
|
+
GenericResource.command(:create, method: :post) do |args|
|
21
|
+
"/this/is/the/path"
|
22
|
+
end
|
23
|
+
GenericResource.should_receive(:execute_request!).with({:relative_path=>"/this/is/the/path", :http_method=>:get})
|
24
|
+
GenericResource.create
|
25
|
+
end
|
26
|
+
|
27
|
+
context "and an argument is passed in" do
|
28
|
+
it "interpolates it" do
|
29
|
+
GenericResource.command(:create, method: :post) do |args|
|
30
|
+
"/this/is/the/#{args.delete(:name)}"
|
31
|
+
end
|
32
|
+
GenericResource.should_receive(:execute_request!).with({:relative_path=>"/this/is/the/ABC123", :http_method=>:get})
|
33
|
+
GenericResource.create(name: "ABC123")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ShippingEasy::Signature do
|
4
|
+
let(:api_secret) { "ABC12345" }
|
5
|
+
let(:method) { :post }
|
6
|
+
let(:path) { "/api/orders" }
|
7
|
+
let(:params) { { test_param: "ABCDE", api_key: "123", api_signature: "XXX" } }
|
8
|
+
let(:request_body) { { orders: { name: "Flip flops", cost: "10.00", shipping_cost: "2.00" } }.to_json.to_s }
|
9
|
+
let(:method) { :post }
|
10
|
+
|
11
|
+
subject { ShippingEasy::Signature.new(api_secret: api_secret, method: method, path: path, params: params, body: request_body) }
|
12
|
+
|
13
|
+
describe "#initialize" do
|
14
|
+
specify { subject.api_secret.should == api_secret }
|
15
|
+
specify { subject.method.should == "POST" }
|
16
|
+
specify { subject.path.should == path }
|
17
|
+
specify { subject.body.should == request_body }
|
18
|
+
specify { subject.params.should == params }
|
19
|
+
specify { subject.params[:api_signature].should be_nil }
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "#plaintext" do
|
23
|
+
specify { subject.plaintext.should == "POST&/api/orders&api_key=123&test_param=ABCDE&{\"orders\":{\"name\":\"Flip flops\",\"cost\":\"10.00\",\"shipping_cost\":\"2.00\"}}"}
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "#encrypted" do
|
27
|
+
specify { subject.encrypted.should == OpenSSL::HMAC::hexdigest("sha256", api_secret, subject.plaintext)}
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "#to_s" do
|
31
|
+
specify { subject.to_s.should == subject.encrypted}
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "#==" do
|
35
|
+
let(:duplicate_signature) { ShippingEasy::Signature.new(api_secret: api_secret, method: method, path: path, params: params, body: request_body) }
|
36
|
+
specify { (subject == OpenSSL::HMAC::hexdigest("sha256", api_secret, subject.plaintext)).should be_true }
|
37
|
+
specify { (subject == OpenSSL::HMAC::hexdigest("sha256", "BADSECRET", subject.plaintext)).should be_false }
|
38
|
+
specify { (subject == duplicate_signature).should be_true }
|
39
|
+
end
|
40
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'shipping_easy'
|
3
|
+
|
4
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
5
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
6
|
+
# Require this file using `require "spec_helper"` to ensure that it is only
|
7
|
+
# loaded once.
|
8
|
+
#
|
9
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
10
|
+
RSpec.configure do |config|
|
11
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
12
|
+
config.run_all_when_everything_filtered = true
|
13
|
+
config.filter_run :focus
|
14
|
+
|
15
|
+
# Run specs in random order to surface order dependencies. If you find an
|
16
|
+
# order dependency and want to debug it, you can fix the order by providing
|
17
|
+
# the seed, which is printed after each run.
|
18
|
+
# --seed 1234
|
19
|
+
config.order = 'random'
|
20
|
+
end
|
metadata
CHANGED
@@ -1,41 +1,83 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shipping_easy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- ShippingEasy
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-03-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: faraday
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.8.7
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.8.7
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rack
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.4.5
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 1.4.5
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: json
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 1.8.0
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 1.8.0
|
13
55
|
- !ruby/object:Gem::Dependency
|
14
56
|
name: bundler
|
15
57
|
requirement: !ruby/object:Gem::Requirement
|
16
58
|
requirements:
|
17
|
-
- - ~>
|
59
|
+
- - "~>"
|
18
60
|
- !ruby/object:Gem::Version
|
19
61
|
version: '1.3'
|
20
62
|
type: :development
|
21
63
|
prerelease: false
|
22
64
|
version_requirements: !ruby/object:Gem::Requirement
|
23
65
|
requirements:
|
24
|
-
- - ~>
|
66
|
+
- - "~>"
|
25
67
|
- !ruby/object:Gem::Version
|
26
68
|
version: '1.3'
|
27
69
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
70
|
+
name: rspec
|
29
71
|
requirement: !ruby/object:Gem::Requirement
|
30
72
|
requirements:
|
31
|
-
- -
|
73
|
+
- - ">="
|
32
74
|
- !ruby/object:Gem::Version
|
33
75
|
version: '0'
|
34
76
|
type: :development
|
35
77
|
prerelease: false
|
36
78
|
version_requirements: !ruby/object:Gem::Requirement
|
37
79
|
requirements:
|
38
|
-
- -
|
80
|
+
- - ">="
|
39
81
|
- !ruby/object:Gem::Version
|
40
82
|
version: '0'
|
41
83
|
description: The official ShippingEasy API client for Ruby.
|
@@ -45,19 +87,34 @@ executables: []
|
|
45
87
|
extensions: []
|
46
88
|
extra_rdoc_files: []
|
47
89
|
files:
|
48
|
-
- .gitignore
|
90
|
+
- ".gitignore"
|
91
|
+
- ".rspec"
|
49
92
|
- Gemfile
|
50
93
|
- LICENSE.txt
|
51
94
|
- README.md
|
52
95
|
- Rakefile
|
53
96
|
- lib/shipping_easy.rb
|
54
97
|
- lib/shipping_easy/authenticator.rb
|
55
|
-
- lib/shipping_easy/
|
98
|
+
- lib/shipping_easy/configuration.rb
|
99
|
+
- lib/shipping_easy/http.rb
|
100
|
+
- lib/shipping_easy/http/faraday_adapter.rb
|
101
|
+
- lib/shipping_easy/http/request.rb
|
102
|
+
- lib/shipping_easy/http/response_handler.rb
|
103
|
+
- lib/shipping_easy/resources.rb
|
104
|
+
- lib/shipping_easy/resources/base.rb
|
105
|
+
- lib/shipping_easy/resources/cancellation.rb
|
56
106
|
- lib/shipping_easy/resources/order.rb
|
57
|
-
- lib/shipping_easy/resources/store.rb
|
58
107
|
- lib/shipping_easy/signature.rb
|
59
108
|
- lib/shipping_easy/version.rb
|
60
109
|
- shipping_easy.gemspec
|
110
|
+
- spec/authenticator_spec.rb
|
111
|
+
- spec/configuration_spec.rb
|
112
|
+
- spec/http/faraday_adapter_spec.rb
|
113
|
+
- spec/http/request_spec.rb
|
114
|
+
- spec/http/response_handler_spec.rb
|
115
|
+
- spec/resources/base_spec.rb
|
116
|
+
- spec/signature_spec.rb
|
117
|
+
- spec/spec_helper.rb
|
61
118
|
homepage: https://github.com/ShippingEasy/shipping_easy-ruby
|
62
119
|
licenses:
|
63
120
|
- MIT
|
@@ -68,18 +125,26 @@ require_paths:
|
|
68
125
|
- lib
|
69
126
|
required_ruby_version: !ruby/object:Gem::Requirement
|
70
127
|
requirements:
|
71
|
-
- -
|
128
|
+
- - ">="
|
72
129
|
- !ruby/object:Gem::Version
|
73
130
|
version: '0'
|
74
131
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
75
132
|
requirements:
|
76
|
-
- -
|
133
|
+
- - ">="
|
77
134
|
- !ruby/object:Gem::Version
|
78
135
|
version: '0'
|
79
136
|
requirements: []
|
80
137
|
rubyforge_project:
|
81
|
-
rubygems_version: 2.
|
138
|
+
rubygems_version: 2.2.0
|
82
139
|
signing_key:
|
83
140
|
specification_version: 4
|
84
141
|
summary: The official ShippingEasy API client for Ruby.
|
85
|
-
test_files:
|
142
|
+
test_files:
|
143
|
+
- spec/authenticator_spec.rb
|
144
|
+
- spec/configuration_spec.rb
|
145
|
+
- spec/http/faraday_adapter_spec.rb
|
146
|
+
- spec/http/request_spec.rb
|
147
|
+
- spec/http/response_handler_spec.rb
|
148
|
+
- spec/resources/base_spec.rb
|
149
|
+
- spec/signature_spec.rb
|
150
|
+
- spec/spec_helper.rb
|
File without changes
|
File without changes
|