Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

added new Admin class for the AdminService.asmx #1

Merged
merged 1 commit into from

2 participants

@ttdonovan

I'm looking into integration options the ChannelAdvisor API and found your gem. To get a better understanding of your code structure and test coverage I implemented a new class for the AdminService and fixed a few of your failing specs from the 'refactor' branch. As the code is now it appears that there is going to be lots of duplication and I have some suggestions for possibly drying up the code. My first incline is to create a services module and a class for each service inside. Each request to the API would be a from a service instance. Something like this:

>> os = ChannelAdvisor::Services::OrderService.new
>> os.ping
>> # sends soap API ping request, setting and last_response and returning the response
>> os.last_request
>> # soap request object
>> os.last_response
>> # soap response object

and since #ping is implement in all services it could possibly be moved into a Pingable module.

It's an idea I'm toying around with and would like to hear your feedback. I could create an new feature branch 'service-instances' and implement some of the code for a better example.

Cheers,
Tanner

@ttdonovan ttdonovan Added AdminService .ping .request_access(local_id) and .get_authoriza…
…tion_list(local_id)

Includes AdminService RSpec spec
Fixed few failing specs and moved stub_* wsdl and response into spec helper module
Added SimpleCov for Ruby 1.9 when running specs
fe2dc55
@dnunez24
Owner

This is very much in the early stages. I'm in need of it myself for a current project and am focusing on the order service first as it is most pertinent to the project at hand. My plan was to create a Base class from which the other classes can inherit shared functionality so if there appears to be potential for a lot of duplication it is largely because I haven't focused effort on DRYing things up yet.

As for the API design, this is more what I had in mind because it seemed to me more Rubyesque and/or intuitive in the context of an object oriented API:

module ChannelAdvisor
  class Base
     def self.ping
       # do some pingy stuff
     end
  end
end

module ChannelAdvisor
  class Order < Base
    def self.list
      # list orders from ChannelAdvisor
    end

    def submit
      # submit order instance to ChannelAdvisor
    end
  end
end

# Call the Order.ping method
ChannelAdvisor::Order.ping

ChannelAdvisor::Order.list # returns an array of ChannelAdvisor::Order objects

# Perhaps it makes the most sense in this context
order = ChannelAdvisor::Order.new(
  # some attributes here
)
order.submit

I understand your reasoning behind keeping the classes/modules named after the ChannelAdvisor API services (e.g., OrderService vs Order) but I like the simplicity of having methods like Order.list and order.submit. That being said, I very much welcome your feedback, contribution, criticism, etc. and I will try to provide as much information/documentation as possible as I continue developing the gem. I will review your additions to the code shortly and try to get us on the same page.

@dnunez24
Owner

@ttdonovan, I dig your contributions so far. I think there are a few things I might want to clean up for consistency but I like the modifications you've made. Also, I just realized the other day that I can probably get a lot of the WSDL and web service response stubbing accomplished much faster with the VCR gem. Any objections? I'm going to pull your changes. Feel free to supply any other feedback you feel is necessary. Two heads are better than one, they say . . .

@dnunez24 dnunez24 merged commit eb19012 into from
@ttdonovan

@dnunez24 I think I understand what you are trying to do. Below is something I think could meet both our needs and provide a lot of flexibility for this gem. The idea behind the Services modules is to hide all the SOAPy stuff but if needed a developer could instantiate those clasess and interacte/parse the responses themselves. As for VCR I haven't used the gem extensively but it looks like a good fit for this project.

module ChannelAdvisor
  module Services
    class BaseService
      attr_accessor :last_request, :last_response

      def ping
        # do some pingy stuff
      end

      def client
        # Savon client
      end
    end

    class OrderService < BaseService

      def get_order_list(options={})
        # all the soapy client stuff, could extract the building of header/credentials into a BaseService method...
        # set last_request
        # send the API request
        # set last_response
        # return true (?) # not sure what would be returned...
      end

      # the other ChannelAdvisor order service endpoints
    end
  end
end

module ChannelAdvisor
  class Order

    def self.ping
      order_service.new.ping
    end

    def self.list
      os = order_service.new
      os.get_order_list
      # parse the os.last_response, create new orders instances and return the array
    end

    def submit
      os = order_service.new
      # pass in attributes and submit order instance to ChannelAdvisor using the OrderService method
    end

    private

    def order_service
      ChannelAdvisor::Services::OrderService
    end
  end
end

# Call the Order.ping method
ChannelAdvisor::Order.ping

ChannelAdvisor::Order.list # returns an array of ChannelAdvisor::Order objects

# Perhaps it makes the most sense in this context
order = ChannelAdvisor::Order.new(
  # some attributes here
)
order.submit
@dnunez24
Owner

Yeah, that's interesting. I considered a combination after your initial suggestion. Does it really make sense to add that extra layer of abstraction though? Take a look at this--I've been playing around with an example of the Base class:

module ChannelAdvisor
  class Base
    class << self

    private

      def client
        @client ||= Client.new(const_get(:WSDL))
      end

      def config(attribute)
        ChannelAdvisor.configuration.send(attribute.to_sym)
      end
    end # self
  end # Base
end # ChannelAdvisor

And here's what the Order class would look like:

module ChannelAdvisor
  class Order < Base
    # Unique subclass WSDL gets used in the inherited Base.client method
    WSDL = "https://api.channeladvisor.com/ChannelAdvisorAPI/v6/OrderService.asmx?WSDL"   
...

Is the end game of using your method for a separation of concerns? I can certainly see your point, especially in the Order.list method. One thing to note...the ping method doesn't actually exist in all services in v6 of the API (the Marketplace Ad Service, for example). I can definitely be convinced, I'm just not sure we're quite there yet.

@ttdonovan

Yes, you could say my solution address a issue of separation of concerns. I guess what concerns me is at the level of abstraction you are purposing there will be mix of class where some subclass the 'Base' and others that don't. For example what about an 'Address' or 'LineItem' class? These type of classes have no interactions with the API. The way that I am purposing it's very clear that are specific classes that interact with the CA service API and the method names have a direct correlation. We can always start with your method and if it becomes necessary we can create that extra layer of abstraction that I am purposing (or at least I can branch off your work to demonstrate).

@dnunez24
Owner

A very good point. There certainly would be no need for Address or LineItem to inherit from Base. You've won me over. Since there's still very little code written we might as well start off on the right foot instead of implementing half of it my way and then doing a rewrite. I figure we can just use undef_method on any classes that inherit from BaseService to solve the issue with something like the ping method unless you have a better suggestion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Apr 18, 2012
  1. @ttdonovan

    Added AdminService .ping .request_access(local_id) and .get_authoriza…

    ttdonovan authored
    …tion_list(local_id)
    
    Includes AdminService RSpec spec
    Fixed few failing specs and moved stub_* wsdl and response into spec helper module
    Added SimpleCov for Ruby 1.9 when running specs
This page is out of date. Refresh to see the latest.
View
1  .gitignore
@@ -4,3 +4,4 @@ Gemfile.lock
pkg/*
.yardoc/*
doc/*
+coverage/*
View
9 Gemfile
@@ -15,9 +15,18 @@ group :test do
gem 'win32console', :require => false, :platforms => [:mswin, :mingw]
gem 'rb-fchange', :require => false, :platforms => [:mswin, :mingw]
gem 'rb-notifu', :require => false, :platforms => [:mswin, :mingw]
+
+ platform :ruby_19 do
+ gem 'simplecov'
+ end
end
group :development do
gem 'yard'
gem 'redcarpet'
end
+
+# platform :ruby_19 do
+# gem 'ruby-debug19'
+# gem 'pry'
+# end
View
4 Rakefile
@@ -3,4 +3,6 @@ require "rspec/core/rake_task"
RSpec::Core::RakeTask.new do |t|
t.rspec_opts = ["--format progress"]
-end
+end
+
+task :default => :spec
View
1  lib/channeladvisor.rb
@@ -4,6 +4,7 @@
require 'channeladvisor/configuration'
require 'channeladvisor/client'
require 'channeladvisor/order'
+require 'channeladvisor/admin'
module ChannelAdvisor
def self.configuration
View
117 lib/channeladvisor/admin.rb
@@ -0,0 +1,117 @@
+module ChannelAdvisor
+ class Admin
+ WSDL = "https://api.channeladvisor.com/ChannelAdvisorAPI/v6/AdminService.asmx?WSDL"
+
+ NAMESPACES = {
+ "xmlns:soap" => "http://schemas.xmlsoap.org/soap/envelope/"
+ }
+
+ AccountAuthorization = Struct.new(:account_id, :local_id, :account_name, :account_type, :resource_name, :status)
+
+ # Checks authorization for and availability of the admin service
+ #
+ # @raise [Savon::SOAP::Fault] Raises an exception when the service returns a failure status
+ # @return [String] Status message
+ def self.ping
+ response = client.request :ping do
+ soap.xml do |xml|
+ xml.soap :Envelope, Admin::NAMESPACES do
+ xml.soap :Header do
+ xml.web :APICredentials do
+ xml.web :DeveloperKey, config(:developer_key)
+ xml.web :Password, config(:password)
+ end
+ end
+ xml.soap :Body do
+ xml.web :Ping
+ end
+ end
+ end
+ end
+
+ message = response.xpath('//web:ResultData', 'web' => 'http://api.channeladvisor.com/webservices/').text
+ return message
+ end
+
+ # Allows you to request access to a specific CA Complete Account.
+ #
+ # @raise [ServiceFailure] Raises an exception when the service returns a failure status
+ # @return [String] Status message
+ def self.request_access(local_id)
+ response = client.request :request_access do
+ soap.xml do |xml|
+ xml.soap :Envelope, Admin::NAMESPACES do
+ xml.soap :Header do
+ xml.web :APICredentials do
+ xml.web :DeveloperKey, config(:developer_key)
+ xml.web :Password, config(:password)
+ end
+ end
+ xml.soap :Body do
+ xml.web :RequestAccess do
+ xml.web :localID, local_id
+ end
+ end
+ end
+ end
+ end
+
+ status = response.xpath('//web:Status', 'web' => 'http://api.channeladvisor.com/webservices/').text
+ message = response.xpath('//web:ResultData', 'web' => 'http://api.channeladvisor.com/webservices/').text
+
+ if status == "Failure"
+ raise ServiceFailure, message
+ else
+ message
+ end
+ end
+
+ # Retrieve a list of Account Authorizations for the developer key.
+ #
+ # @return [Array] Account Authorizations
+ def self.get_authorization_list(local_id)
+ response = client.request :request_access do
+ soap.xml do |xml|
+ xml.soap :Envelope, Admin::NAMESPACES do
+ xml.soap :Header do
+ xml.web :APICredentials do
+ xml.web :DeveloperKey, config(:developer_key)
+ xml.web :Password, config(:password)
+ end
+ end
+ xml.soap :Body do
+ xml.web :GetAuthorizationList do
+ xml.web :localID, local_id
+ end
+ end
+ end
+ end
+ end
+
+ auths = []
+ if result_data = response.body[:get_authorization_list_response][:get_authorization_list_result][:result_data]
+ auths << AccountAuthorization.new(
+ result_data[:authorization_response][:account_id],
+ result_data[:authorization_response][:local_id],
+ result_data[:authorization_response][:account_name],
+ result_data[:authorization_response][:account_type],
+ result_data[:authorization_response][:resource_name],
+ result_data[:authorization_response][:status]
+ )
+ auths
+ else
+ auths
+ end
+ end
+
+ private
+
+ def self.client
+ @client ||= Client.new WSDL
+ end
+
+ def self.config(attribute)
+ ChannelAdvisor.configuration.send(attribute.to_sym)
+ end
+ end
+end
View
15 lib/channeladvisor/order.rb
@@ -119,12 +119,19 @@ def self.list(filters = {})
order_criteria.ord :JoinDateFiltersWithOr, xsi_nil(filters[:join_dates])
order_criteria.ord :DetailLevel, xsi_nil(filters[:detail_level])
order_criteria.ord :ExportState, xsi_nil(filters[:export_state])
- order_criteria.ord :OrderIDList do |order_id_list|
- build_id_list(order_id_list, filters[:order_ids])
+
+ if filters[:order_ids]
+ order_criteria.ord :OrderIDList do |order_id_list|
+ build_id_list(order_id_list, filters[:order_ids])
+ end
end
- order_criteria.ord :ClientOrderIdentifierList do |client_order_identifier_list|
- build_id_list(client_order_identifier_list, filters[:client_order_ids])
+
+ if filters[:client_order_ids]
+ order_criteria.ord :ClientOrderIdentifierList do |client_order_identifier_list|
+ build_id_list(client_order_identifier_list, filters[:client_order_ids])
+ end
end
+
order_criteria.ord :OrderStateFilter, xsi_nil(filters[:state])
order_criteria.ord :PaymentStatusFilter, xsi_nil(filters[:payment_status])
order_criteria.ord :CheckoutStatusFilter, xsi_nil(filters[:checkout_status])
View
11 spec/fixtures/responses/admin_service/get_authorization_list/failure.xml
@@ -0,0 +1,11 @@
+<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+ <soap:Body>
+ <GetAuthorizationListResponse xmlns="http://api.channeladvisor.com/webservices/">
+ <GetAuthorizationListResult>
+ <Status>Success</Status>
+ <MessageCode>0</MessageCode>
+ <ResultData/>
+ </GetAuthorizationListResult>
+ </GetAuthorizationListResponse>
+ </soap:Body>
+</soap:Envelope>
View
20 spec/fixtures/responses/admin_service/get_authorization_list/success.xml
@@ -0,0 +1,20 @@
+<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+ <soap:Body>
+ <GetAuthorizationListResponse xmlns="http://api.channeladvisor.com/webservices/">
+ <GetAuthorizationListResult>
+ <Status>Success</Status>
+ <MessageCode>0</MessageCode>
+ <ResultData>
+ <AuthorizationResponse>
+ <AccountID>00000000-1111-2222-3333-444444444444</AccountID>
+ <LocalID>1234567890</LocalID>
+ <AccountName>ACME</AccountName>
+ <AccountType>merchant</AccountType>
+ <ResourceName>/channeladvisorapi</ResourceName>
+ <Status>Enabled</Status>
+ </AuthorizationResponse>
+ </ResultData>
+ </GetAuthorizationListResult>
+ </GetAuthorizationListResponse>
+ </soap:Body>
+</soap:Envelope>
View
9 spec/fixtures/responses/admin_service/ping/failure.xml
@@ -0,0 +1,9 @@
+<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
+ <soap:Body>
+ <soap:Fault>
+ <faultcode>soap:Server</faultcode>
+ <faultstring>Server was unable to process request. Authentication failed.</faultstring>
+ <detail/>
+ </soap:Fault>
+ </soap:Body>
+</soap:Envelope>
View
11 spec/fixtures/responses/admin_service/ping/success.xml
@@ -0,0 +1,11 @@
+<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <soap:Body>
+ <PingResponse xmlns="http://api.channeladvisor.com/webservices/">
+ <PingResult>
+ <Status>Success</Status>
+ <MessageCode>0</MessageCode>
+ <ResultData>OK</ResultData>
+ </PingResult>
+ </PingResponse>
+ </soap:Body>
+</soap:Envelope>
View
12 spec/fixtures/responses/admin_service/request_access/failure.xml
@@ -0,0 +1,12 @@
+<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+ <soap:Body>
+ <RequestAccessResponse xmlns="http://api.channeladvisor.com/webservices/">
+ <RequestAccessResult>
+ <Status>Failure</Status>
+ <MessageCode>12</MessageCode>
+ <Message>An Authorization for the specified ID [1234567890] already exists!</Message>
+ <ResultData>false</ResultData>
+ </RequestAccessResult>
+ </RequestAccessResponse>
+ </soap:Body>
+</soap:Envelope>
View
11 spec/fixtures/responses/admin_service/request_access/success.xml
@@ -0,0 +1,11 @@
+<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+ <soap:Body>
+ <RequestAccessResponse xmlns="http://api.channeladvisor.com/webservices/">
+ <RequestAccessResult>
+ <Status>Success</Status>
+ <MessageCode>0</MessageCode>
+ <ResultData>true</ResultData>
+ </RequestAccessResult>
+ </RequestAccessResponse>
+ </soap:Body>
+</soap:Envelope>
View
216 spec/fixtures/wsdls/admin_service.xml
@@ -0,0 +1,216 @@
+<?xml version="1.0" encoding="utf-8"?>
+<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:tns="http://api.channeladvisor.com/webservices/" xmlns:s="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" targetNamespace="http://api.channeladvisor.com/webservices/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
+ <wsdl:types>
+ <s:schema elementFormDefault="qualified" targetNamespace="http://api.channeladvisor.com/webservices/">
+ <s:element name="GetAuthorizationList">
+ <s:complexType>
+ <s:sequence>
+ <s:element minOccurs="0" maxOccurs="1" name="localID" type="s:integer" />
+ </s:sequence>
+ </s:complexType>
+ </s:element>
+ <s:element name="GetAuthorizationListResponse">
+ <s:complexType>
+ <s:sequence>
+ <s:element minOccurs="0" maxOccurs="1" name="GetAuthorizationListResult" type="tns:APIResultOfArrayOfAuthorizationResponse" />
+ </s:sequence>
+ </s:complexType>
+ </s:element>
+ <s:complexType name="APIResultOfArrayOfAuthorizationResponse">
+ <s:sequence>
+ <s:element minOccurs="1" maxOccurs="1" name="Status" type="tns:ResultStatus" />
+ <s:element minOccurs="1" maxOccurs="1" name="MessageCode" type="s:int" />
+ <s:element minOccurs="0" maxOccurs="1" name="Message" type="s:string" />
+ <s:element minOccurs="0" maxOccurs="1" name="Data" type="s:string" />
+ <s:element minOccurs="0" maxOccurs="1" name="ResultData" type="tns:ArrayOfAuthorizationResponse" />
+ </s:sequence>
+ </s:complexType>
+ <s:simpleType name="ResultStatus">
+ <s:restriction base="s:string">
+ <s:enumeration value="Success" />
+ <s:enumeration value="Failure" />
+ </s:restriction>
+ </s:simpleType>
+ <s:complexType name="ArrayOfAuthorizationResponse">
+ <s:sequence>
+ <s:element minOccurs="0" maxOccurs="unbounded" name="AuthorizationResponse" nillable="true" type="tns:AuthorizationResponse" />
+ </s:sequence>
+ </s:complexType>
+ <s:complexType name="AuthorizationResponse">
+ <s:sequence>
+ <s:element minOccurs="0" maxOccurs="1" name="AccountID" type="s:string" />
+ <s:element minOccurs="1" maxOccurs="1" name="LocalID" type="s:int" />
+ <s:element minOccurs="0" maxOccurs="1" name="AccountName" type="s:string" />
+ <s:element minOccurs="0" maxOccurs="1" name="AccountType" type="s:string" />
+ <s:element minOccurs="0" maxOccurs="1" name="ResourceName" type="s:string" />
+ <s:element minOccurs="0" maxOccurs="1" name="Status" type="s:string" />
+ </s:sequence>
+ </s:complexType>
+ <s:element name="APICredentials" type="tns:APICredentials" />
+ <s:complexType name="APICredentials">
+ <s:sequence>
+ <s:element minOccurs="0" maxOccurs="1" name="DeveloperKey" type="s:string" />
+ <s:element minOccurs="0" maxOccurs="1" name="Password" type="s:string" />
+ </s:sequence>
+ <s:anyAttribute />
+ </s:complexType>
+ <s:element name="RequestAccess">
+ <s:complexType>
+ <s:sequence>
+ <s:element minOccurs="1" maxOccurs="1" name="localID" type="s:int" />
+ </s:sequence>
+ </s:complexType>
+ </s:element>
+ <s:element name="RequestAccessResponse">
+ <s:complexType>
+ <s:sequence>
+ <s:element minOccurs="0" maxOccurs="1" name="RequestAccessResult" type="tns:APIResultOfBoolean" />
+ </s:sequence>
+ </s:complexType>
+ </s:element>
+ <s:complexType name="APIResultOfBoolean">
+ <s:sequence>
+ <s:element minOccurs="1" maxOccurs="1" name="Status" type="tns:ResultStatus" />
+ <s:element minOccurs="1" maxOccurs="1" name="MessageCode" type="s:int" />
+ <s:element minOccurs="0" maxOccurs="1" name="Message" type="s:string" />
+ <s:element minOccurs="0" maxOccurs="1" name="Data" type="s:string" />
+ <s:element minOccurs="1" maxOccurs="1" name="ResultData" type="s:boolean" />
+ </s:sequence>
+ </s:complexType>
+ <s:element name="Ping">
+ <s:complexType />
+ </s:element>
+ <s:element name="PingResponse">
+ <s:complexType>
+ <s:sequence>
+ <s:element minOccurs="0" maxOccurs="1" name="PingResult" type="tns:APIResultOfString" />
+ </s:sequence>
+ </s:complexType>
+ </s:element>
+ <s:complexType name="APIResultOfString">
+ <s:sequence>
+ <s:element minOccurs="1" maxOccurs="1" name="Status" type="tns:ResultStatus" />
+ <s:element minOccurs="1" maxOccurs="1" name="MessageCode" type="s:int" />
+ <s:element minOccurs="0" maxOccurs="1" name="Message" type="s:string" />
+ <s:element minOccurs="0" maxOccurs="1" name="Data" type="s:string" />
+ <s:element minOccurs="0" maxOccurs="1" name="ResultData" type="s:string" />
+ </s:sequence>
+ </s:complexType>
+ </s:schema>
+ </wsdl:types>
+ <wsdl:message name="GetAuthorizationListSoapIn">
+ <wsdl:part name="parameters" element="tns:GetAuthorizationList" />
+ </wsdl:message>
+ <wsdl:message name="GetAuthorizationListSoapOut">
+ <wsdl:part name="parameters" element="tns:GetAuthorizationListResponse" />
+ </wsdl:message>
+ <wsdl:message name="GetAuthorizationListAPICredentials">
+ <wsdl:part name="APICredentials" element="tns:APICredentials" />
+ </wsdl:message>
+ <wsdl:message name="RequestAccessSoapIn">
+ <wsdl:part name="parameters" element="tns:RequestAccess" />
+ </wsdl:message>
+ <wsdl:message name="RequestAccessSoapOut">
+ <wsdl:part name="parameters" element="tns:RequestAccessResponse" />
+ </wsdl:message>
+ <wsdl:message name="RequestAccessAPICredentials">
+ <wsdl:part name="APICredentials" element="tns:APICredentials" />
+ </wsdl:message>
+ <wsdl:message name="PingSoapIn">
+ <wsdl:part name="parameters" element="tns:Ping" />
+ </wsdl:message>
+ <wsdl:message name="PingSoapOut">
+ <wsdl:part name="parameters" element="tns:PingResponse" />
+ </wsdl:message>
+ <wsdl:message name="PingAPICredentials">
+ <wsdl:part name="APICredentials" element="tns:APICredentials" />
+ </wsdl:message>
+ <wsdl:portType name="AdminServiceSoap">
+ <wsdl:operation name="GetAuthorizationList">
+ <wsdl:input message="tns:GetAuthorizationListSoapIn" />
+ <wsdl:output message="tns:GetAuthorizationListSoapOut" />
+ </wsdl:operation>
+ <wsdl:operation name="RequestAccess">
+ <wsdl:input message="tns:RequestAccessSoapIn" />
+ <wsdl:output message="tns:RequestAccessSoapOut" />
+ </wsdl:operation>
+ <wsdl:operation name="Ping">
+ <wsdl:input message="tns:PingSoapIn" />
+ <wsdl:output message="tns:PingSoapOut" />
+ </wsdl:operation>
+ </wsdl:portType>
+ <wsdl:binding name="AdminServiceSoap" type="tns:AdminServiceSoap">
+ <soap:binding transport="http://schemas.xmlsoap.org/soap/http" />
+ <wsdl:operation name="GetAuthorizationList">
+ <soap:operation soapAction="http://api.channeladvisor.com/webservices/GetAuthorizationList" style="document" />
+ <wsdl:input>
+ <soap:body use="literal" />
+ <soap:header message="tns:GetAuthorizationListAPICredentials" part="APICredentials" use="literal" />
+ </wsdl:input>
+ <wsdl:output>
+ <soap:body use="literal" />
+ </wsdl:output>
+ </wsdl:operation>
+ <wsdl:operation name="RequestAccess">
+ <soap:operation soapAction="http://api.channeladvisor.com/webservices/RequestAccess" style="document" />
+ <wsdl:input>
+ <soap:body use="literal" />
+ <soap:header message="tns:RequestAccessAPICredentials" part="APICredentials" use="literal" />
+ </wsdl:input>
+ <wsdl:output>
+ <soap:body use="literal" />
+ </wsdl:output>
+ </wsdl:operation>
+ <wsdl:operation name="Ping">
+ <soap:operation soapAction="http://api.channeladvisor.com/webservices/Ping" style="document" />
+ <wsdl:input>
+ <soap:body use="literal" />
+ <soap:header message="tns:PingAPICredentials" part="APICredentials" use="literal" />
+ </wsdl:input>
+ <wsdl:output>
+ <soap:body use="literal" />
+ </wsdl:output>
+ </wsdl:operation>
+ </wsdl:binding>
+ <wsdl:binding name="AdminServiceSoap12" type="tns:AdminServiceSoap">
+ <soap12:binding transport="http://schemas.xmlsoap.org/soap/http" />
+ <wsdl:operation name="GetAuthorizationList">
+ <soap12:operation soapAction="http://api.channeladvisor.com/webservices/GetAuthorizationList" style="document" />
+ <wsdl:input>
+ <soap12:body use="literal" />
+ <soap12:header message="tns:GetAuthorizationListAPICredentials" part="APICredentials" use="literal" />
+ </wsdl:input>
+ <wsdl:output>
+ <soap12:body use="literal" />
+ </wsdl:output>
+ </wsdl:operation>
+ <wsdl:operation name="RequestAccess">
+ <soap12:operation soapAction="http://api.channeladvisor.com/webservices/RequestAccess" style="document" />
+ <wsdl:input>
+ <soap12:body use="literal" />
+ <soap12:header message="tns:RequestAccessAPICredentials" part="APICredentials" use="literal" />
+ </wsdl:input>
+ <wsdl:output>
+ <soap12:body use="literal" />
+ </wsdl:output>
+ </wsdl:operation>
+ <wsdl:operation name="Ping">
+ <soap12:operation soapAction="http://api.channeladvisor.com/webservices/Ping" style="document" />
+ <wsdl:input>
+ <soap12:body use="literal" />
+ <soap12:header message="tns:PingAPICredentials" part="APICredentials" use="literal" />
+ </wsdl:input>
+ <wsdl:output>
+ <soap12:body use="literal" />
+ </wsdl:output>
+ </wsdl:operation>
+ </wsdl:binding>
+ <wsdl:service name="AdminService">
+ <wsdl:port name="AdminServiceSoap" binding="tns:AdminServiceSoap">
+ <soap:address location="https://api.channeladvisor.com/ChannelAdvisorAPI/v6/AdminService.asmx" />
+ </wsdl:port>
+ <wsdl:port name="AdminServiceSoap12" binding="tns:AdminServiceSoap12">
+ <soap12:address location="https://api.channeladvisor.com/ChannelAdvisorAPI/v6/AdminService.asmx" />
+ </wsdl:port>
+ </wsdl:service>
+</wsdl:definitions>
View
127 spec/lib/channeladvisor/admin_spec.rb
@@ -0,0 +1,127 @@
+require 'spec_helper'
+
+module ChannelAdvisor
+ describe Admin, "AccountAuthorization" do
+ context "a new instance" do
+ let(:account_authorization) do
+ ChannelAdvisor::Admin::AccountAuthorization.new(
+ '00000000-1111-2222-3333-444444444444',
+ 1234567890,
+ 'ACME',
+ 'merchant',
+ '/channeladvisorapi',
+ 'Enabled'
+ )
+ end
+
+ describe '#account_id' do
+ subject { account_authorization.account_id }
+
+ it { should == '00000000-1111-2222-3333-444444444444' }
+ end
+
+ describe '#local_id' do
+ subject { account_authorization.local_id }
+
+ it { should == 1234567890 }
+ end
+
+ describe '#account_name' do
+ subject { account_authorization.account_name }
+
+ it { should == 'ACME' }
+ end
+
+ describe '#account_type' do
+ subject { account_authorization.account_type }
+
+ it { should == 'merchant' }
+ end
+
+ describe '#resource_name' do
+ subject { account_authorization.resource_name }
+
+ it { should == '/channeladvisorapi' }
+ end
+
+ describe '#status' do
+ subject { account_authorization.status }
+
+ it { should == 'Enabled' }
+ end
+ end
+ end
+
+ describe Admin, ".ping" do
+ let(:wsdl) { ChannelAdvisor::Admin::WSDL }
+
+ before(:each) do
+ stub_wsdl(wsdl)
+ stub_response(wsdl, :ping, data)
+ end
+
+ subject { ChannelAdvisor::Admin.ping }
+
+ context "when successful" do
+ let(:data) { :success }
+
+ it { should == 'OK' }
+ end
+
+ context "when unsuccessful" do
+ let(:data) { :failure }
+
+ it "raises a Savon SOAP fault" do
+ expect { subject }.to raise_error Savon::SOAP::Fault
+ end
+ end
+ end # Admin.ping
+
+ describe Admin, ".request_access" do
+ let(:wsdl) { ChannelAdvisor::Admin::WSDL }
+
+ before(:each) do
+ stub_wsdl(wsdl)
+ stub_response(wsdl, :request_access, data)
+ end
+
+ subject { ChannelAdvisor::Admin.request_access(1234567890) }
+
+ context "when successful" do
+ let(:data) { :success }
+
+ it { should be_true }
+ end
+
+ context "when unsuccessful" do
+ let(:data) { :failure }
+
+ it "raises a Savon SOAP fault" do
+ expect { subject }.to raise_error ServiceFailure
+ end
+ end
+ end # Admin.request_access
+
+ describe Admin, ".get_authorization_list" do
+ let(:wsdl) { ChannelAdvisor::Admin::WSDL }
+
+ before(:each) do
+ stub_response(wsdl, :get_authorization_list, data)
+ stub_wsdl(wsdl)
+ end
+
+ subject { ChannelAdvisor::Admin.get_authorization_list(1234567890) }
+
+ context "when successful" do
+ let(:data) { :success }
+
+ it { should_not be_empty }
+ end
+
+ context "when unsuccessful" do
+ let(:data) { :failure }
+
+ it { should be_empty }
+ end
+ end # Admin.get_authorization_list
+end # ChannelAdvisor
View
36 spec/lib/channeladvisor/order_spec.rb
@@ -1,30 +1,13 @@
require 'spec_helper'
-def stub_wsdl
- FakeWeb.register_uri(
- :get,
- "https://api.channeladvisor.com/ChannelAdvisorAPI/v6/OrderService.asmx?WSDL",
- :body => File.expand_path("../../../fixtures/wsdls/order_service.xml", __FILE__)
- )
-end
-
-def stub_response(method, data, status=nil)
- file_name = data.kind_of?(String) ? data : data.to_s
- response_xml = File.expand_path("../../../fixtures/responses/order_service/#{method.to_s}/#{file_name}.xml", __FILE__)
- response = {:body => response_xml}
- response.update(:status => status) unless status.nil?
-
- FakeWeb.register_uri(
- :post,
- "https://api.channeladvisor.com/ChannelAdvisorAPI/v6/OrderService.asmx",
- response
- )
-end
-
module ChannelAdvisor
describe Order, ".ping" do
- before(:all) { stub_wsdl }
- before(:each) { stub_response :ping, data }
+ let (:wsdl) { ChannelAdvisor::Order::WSDL }
+
+ before(:each) do
+ stub_wsdl(wsdl)
+ stub_response(wsdl, :ping, data)
+ end
subject { ChannelAdvisor::Order.ping }
context "when successful" do
@@ -43,12 +26,13 @@ module ChannelAdvisor
end
describe Order, ".list" do
- before(:all) { stub_wsdl }
+ let (:wsdl) { ChannelAdvisor::Order::WSDL }
+
before(:each) do
+ stub_wsdl(wsdl)
status ||= nil
- stub_response :get_order_list, data, status
+ stub_response(wsdl, :get_order_list, data, status)
end
- after(:all) { FakeWeb.clean_registry }
let(:request) { FakeWeb.last_request.body }
View
6 spec/lib/channeladvisor_spec.rb
@@ -5,21 +5,21 @@
describe "account_id" do
it "sets the account ID" do
ChannelAdvisor.configure { |config| config.account_id = "e83a0b1e-75f7-41e3-8aac-d8ff01f9d1ea" }
- ChannelAdvisor.account_id.should == "e83a0b1e-75f7-41e3-8aac-d8ff01f9d1ea"
+ ChannelAdvisor.configuration.account_id.should == "e83a0b1e-75f7-41e3-8aac-d8ff01f9d1ea"
end
end
describe "developer_key" do
it "sets the developer ID" do
ChannelAdvisor.configure { |config| config.developer_key = "11111111-1111-1111-1111-999999999999" }
- ChannelAdvisor.developer_key.should == "11111111-1111-1111-1111-999999999999"
+ ChannelAdvisor.configuration.developer_key.should == "11111111-1111-1111-1111-999999999999"
end
end
describe "password" do
it "sets the password" do
ChannelAdvisor.configure { |config| config.password = "mypassword" }
- ChannelAdvisor.password.should == "mypassword"
+ ChannelAdvisor.configuration.password.should == "mypassword"
end
end
end
View
30 spec/spec_helper.rb
@@ -1,5 +1,15 @@
require 'rubygems'
require 'bundler/setup'
+
+begin
+ require 'simplecov'
+ SimpleCov.start do
+ add_filter 'spec'
+ end
+rescue => LoadError
+ # not able to load 'simplecov' do nothing
+end
+
require 'channeladvisor'
require 'fakeweb'
@@ -7,6 +17,11 @@
RSpec.configure do |config|
config.mock_with :rr
+ config.include StubWsdlAndResponse
+
+ config.before(:each) do
+ FakeWeb.clean_registry
+ end
end
Savon.configure do |config|
@@ -16,18 +31,3 @@
HTTPI.log = false
FakeWeb.allow_net_connect = false
-
-# def stub_response(*args)
-# service = args[0].to_s.downcase
-# method = args[1].to_s.downcase
-# result = args[2].to_s.downcase
-# status = args[3]
-# response = {:body => File.expand_path("../fixtures/responses/#{service}_service/#{method}/#{result}.xml", __FILE__)}
-# response.update(:status => status) unless status.nil?
-
-# FakeWeb.register_uri(
-# :post,
-# "https://api.channeladvisor.com/ChannelAdvisorAPI/v6/OrderService.asmx",
-# response
-# )
-# end
View
34 spec/support/stub_wsdl_and_response.rb
@@ -0,0 +1,34 @@
+module StubWsdlAndResponse
+
+ def stub_wsdl(wsdl_url)
+ service_name = underscore(wsdl_url.match(%r{v6\/(\w+)\.asmx})[1])
+
+ FakeWeb.register_uri(
+ :get,
+ wsdl_url,
+ :body => File.join(File.dirname(__FILE__), "../fixtures/wsdls/#{service_name}.xml")
+ )
+ end
+
+ def stub_response(wsdl_url, method, data, status=nil)
+ service_name = underscore(wsdl_url.match(%r{v6\/(\w+)\.asmx})[1])
+ file_name = data.kind_of?(String) ? data : data.to_s
+
+ response_xml = File.join(File.dirname(__FILE__), "../fixtures/responses/#{service_name}/#{method.to_s}/#{file_name}.xml")
+ response = {:body => response_xml}
+ response.update(:status => status) unless status.nil?
+
+ FakeWeb.register_uri(
+ :post,
+ wsdl_url.gsub(/\?WSDL/, ''),
+ response
+ )
+ end
+
+private
+
+ def underscore(string='')
+ string.gsub!(/(.)([A-Z])/,'\1_\2').downcase!
+ end
+
+end
Something went wrong with that request. Please try again.