hushed 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +64 -0
- data/Rakefile +9 -0
- data/hushed.gemspec +29 -0
- data/lib/hushed.rb +6 -0
- data/lib/hushed/blackboard.rb +44 -0
- data/lib/hushed/client.rb +92 -0
- data/lib/hushed/documents/document.rb +15 -0
- data/lib/hushed/documents/request/shipment_order.rb +89 -0
- data/lib/hushed/documents/response/shipment_order_result.rb +56 -0
- data/lib/hushed/message.rb +43 -0
- data/lib/hushed/queue.rb +26 -0
- data/lib/hushed/request.rb +11 -0
- data/lib/hushed/response.rb +11 -0
- data/lib/hushed/version.rb +3 -0
- data/spec/fixtures/credentials.yml +12 -0
- data/spec/fixtures/documents/responses/shipment_order_result.xml +23 -0
- data/spec/fixtures/messages/purchase_order_message.xml +11 -0
- data/spec/remote/blackboard_spec.rb +43 -0
- data/spec/remote/queue_spec.rb +63 -0
- data/spec/spec_helper.rb +169 -0
- data/spec/unit/blackboard_spec.rb +102 -0
- data/spec/unit/client_spec.rb +97 -0
- data/spec/unit/documents/document_spec.rb +44 -0
- data/spec/unit/documents/request/shipment_order_spec.rb +90 -0
- data/spec/unit/documents/response/shipment_order_result_spec.rb +26 -0
- data/spec/unit/message_spec.rb +71 -0
- data/spec/unit/queue_spec.rb +48 -0
- metadata +207 -0
| @@ -0,0 +1,43 @@ | |
| 1 | 
            +
            module Hushed
         | 
| 2 | 
            +
              class Message
         | 
| 3 | 
            +
             | 
| 4 | 
            +
                NAMESPACE = "http://schemas.quietlogistics.com/V2/EventMessage.xsd"
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                class MissingDocumentError < StandardError; end
         | 
| 7 | 
            +
                class MissingClientError < StandardError; end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                attr_reader :client, :document, :xml
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                def initialize(options = {})
         | 
| 12 | 
            +
                  @xml = Nokogiri::XML::Document.parse(options[:xml]) if options[:xml]
         | 
| 13 | 
            +
                  @client = options[:client]
         | 
| 14 | 
            +
                  @document = options[:document]
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                def to_xml
         | 
| 18 | 
            +
                  builder = Nokogiri::XML::Builder.new do |xml|
         | 
| 19 | 
            +
                    xml.EventMessage(attributes)
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
                  builder.to_xml
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                def document_type
         | 
| 25 | 
            +
                  @document ? @document.type : @xml.css('EventMessage').first['DocumentType']
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                def document_name
         | 
| 29 | 
            +
                  @document ? @document.filename : @xml.css('EventMessage').first['DocumentName']
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                def attributes
         | 
| 33 | 
            +
                  raise(MissingClientError.new("client cannot be missing")) unless @client
         | 
| 34 | 
            +
                  raise(MissingDocumentError.new("document cannot be missing")) unless @document
         | 
| 35 | 
            +
                  {
         | 
| 36 | 
            +
                    ClientId: @client.client_id, BusinessUnit: @client.business_unit,
         | 
| 37 | 
            +
                    DocumentName: @document.filename, DocumentType: @document.type,
         | 
| 38 | 
            +
                    Warehouse: @document.warehouse, MessageDate: @document.date.utc,
         | 
| 39 | 
            +
                    MessageId: @document.message_id, xmlns: NAMESPACE
         | 
| 40 | 
            +
                  }
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
              end
         | 
| 43 | 
            +
            end
         | 
    
        data/lib/hushed/queue.rb
    ADDED
    
    | @@ -0,0 +1,26 @@ | |
| 1 | 
            +
            module Hushed
         | 
| 2 | 
            +
              class Queue
         | 
| 3 | 
            +
                attr_reader :client
         | 
| 4 | 
            +
                def initialize(client)
         | 
| 5 | 
            +
                  @client = client
         | 
| 6 | 
            +
                end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                def send(message)
         | 
| 9 | 
            +
                  queue = client.to_quiet_queue
         | 
| 10 | 
            +
                  queue.send_message(message.to_xml)
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                def receive
         | 
| 14 | 
            +
                  queue = client.from_quiet_queue
         | 
| 15 | 
            +
                  message = nil
         | 
| 16 | 
            +
                  queue.receive_message do |msg|
         | 
| 17 | 
            +
                    message = Message.new(xml: msg.body)
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
                  message || Message.new
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                def approximate_pending_messages
         | 
| 23 | 
            +
                  client.from_quiet_queue.approximate_number_of_messages
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
              end
         | 
| 26 | 
            +
            end
         | 
| @@ -0,0 +1,12 @@ | |
| 1 | 
            +
            access_key_id: abracadabra
         | 
| 2 | 
            +
            secret_access_key: alakazam
         | 
| 3 | 
            +
            client_id: HUSHED
         | 
| 4 | 
            +
            business_unit: HUSHED
         | 
| 5 | 
            +
            warehouse: SPACE
         | 
| 6 | 
            +
            buckets:
         | 
| 7 | 
            +
              to: hushed-to-quiet
         | 
| 8 | 
            +
              from: hushed-from-quiet
         | 
| 9 | 
            +
            queues:
         | 
| 10 | 
            +
              to: http://queue.amazonaws/1234567890/hushed_to_quiet
         | 
| 11 | 
            +
              from: http://queue.amazonaws/1234567890/hushed_from_quiet
         | 
| 12 | 
            +
              inventory: http://queue.amazonaws/1234567890/hushed_inventory
         | 
| @@ -0,0 +1,23 @@ | |
| 1 | 
            +
            <?xml version="1.0" encoding="utf-8"?>
         | 
| 2 | 
            +
            <SOResult 
         | 
| 3 | 
            +
              xmlns="http://schemas.quiettechnology.com/V2/SOResultDocument.xsd"
         | 
| 4 | 
            +
              ClientID="HUSHED"
         | 
| 5 | 
            +
              BusinessUnit="HUSHED"
         | 
| 6 | 
            +
              CartonCount="1"
         | 
| 7 | 
            +
              DateShipped="2009-09-01T00:00:00Z"
         | 
| 8 | 
            +
              FreightCost="10.00"
         | 
| 9 | 
            +
              OrderNumber="1234567890">
         | 
| 10 | 
            +
              <Line Line="1" Quantity="1" />
         | 
| 11 | 
            +
              <Line Line="2" Quantity="1" />
         | 
| 12 | 
            +
              <Carton 
         | 
| 13 | 
            +
                Carrier="USPS"
         | 
| 14 | 
            +
                CartonId="S12345678901"
         | 
| 15 | 
            +
                CartonNumber="1"
         | 
| 16 | 
            +
                FreightCost="10.00"
         | 
| 17 | 
            +
                ServiceLevel="FIRST"
         | 
| 18 | 
            +
                TrackingId="40000000000"
         | 
| 19 | 
            +
                Weight="0.66">
         | 
| 20 | 
            +
                <Content Line="1"Quantity="1" />
         | 
| 21 | 
            +
                <Content Line="2"Quantity="1" />
         | 
| 22 | 
            +
              </Carton>
         | 
| 23 | 
            +
            </SOResult>
         | 
| @@ -0,0 +1,11 @@ | |
| 1 | 
            +
            <?xml version="1.0" encoding="utf-8"?>
         | 
| 2 | 
            +
            <EventMessage
         | 
| 3 | 
            +
              xmlns="http://schemas.quietlogistics.com/V2/EventMessage.xsd"
         | 
| 4 | 
            +
              ClientId="HUSHED"
         | 
| 5 | 
            +
              BusinessUnit="HUSHED"
         | 
| 6 | 
            +
              DocumentName="HUSHED_PurchaseOrder_1234_20100927_132505124.xml"
         | 
| 7 | 
            +
              DocumentType="PurchaseOrder"
         | 
| 8 | 
            +
              MessageId="EF1CE966-38A2-428b-BA67-EFF23AF22F57"
         | 
| 9 | 
            +
              Warehouse="CORP1"
         | 
| 10 | 
            +
              MessageDate="2009-09-01T12:00:00Z">
         | 
| 11 | 
            +
            </EventMessage>
         | 
| @@ -0,0 +1,43 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
            require 'hushed'
         | 
| 3 | 
            +
            require 'hushed/blackboard'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module Hushed
         | 
| 6 | 
            +
              describe "BlackboardRemote" do
         | 
| 7 | 
            +
                include Configuration
         | 
| 8 | 
            +
                include Fixtures
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                before do
         | 
| 11 | 
            +
                  AWS.config(stub_requests: false)
         | 
| 12 | 
            +
                  @client = Client.new(load_configuration)
         | 
| 13 | 
            +
                  @blackboard = Blackboard.new(@client)
         | 
| 14 | 
            +
                  @document = DocumentDouble.new(
         | 
| 15 | 
            +
                    message_id: '1234567',
         | 
| 16 | 
            +
                    date: Time.new(2013, 04, 05, 12, 30, 15).utc,
         | 
| 17 | 
            +
                    filename: 'neat_beans.xml',
         | 
| 18 | 
            +
                    client: @client,
         | 
| 19 | 
            +
                    type: 'ShipmentOrderResult'
         | 
| 20 | 
            +
                  )
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                after do
         | 
| 24 | 
            +
                  buckets = [@client.to_quiet_bucket, @client.from_quiet_bucket]
         | 
| 25 | 
            +
                  buckets.each { |bucket| bucket.objects.delete_all }
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                it "should be able to write a document to an S3 bucket" do
         | 
| 29 | 
            +
                  message = @blackboard.post(@document)
         | 
| 30 | 
            +
                  file = message.document_name
         | 
| 31 | 
            +
                  bucket = @client.to_quiet_bucket
         | 
| 32 | 
            +
                  assert bucket.objects[file].exists?, "It appears that #{file} was not written to S3"
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                it "should be able to fetch a document from an S3 bucket when given a message" do
         | 
| 36 | 
            +
                  expected_contents = load_response('shipment_order_result').read()
         | 
| 37 | 
            +
                  @client.from_quiet_bucket.objects[@document.filename].write(expected_contents)
         | 
| 38 | 
            +
                  message = MessageDouble.new(document_name: @document.filename, document_type: @document.type)
         | 
| 39 | 
            +
                  document = @blackboard.fetch(message)
         | 
| 40 | 
            +
                  assert_equal expected_contents, document.io
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
              end
         | 
| 43 | 
            +
            end
         | 
| @@ -0,0 +1,63 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
            require 'openssl'
         | 
| 3 | 
            +
            require 'hushed'
         | 
| 4 | 
            +
            require 'hushed/message'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            module Hushed
         | 
| 7 | 
            +
              describe "QueueRemote" do
         | 
| 8 | 
            +
                include Configuration
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                before do
         | 
| 11 | 
            +
                  AWS.config(:stub_requests => false)
         | 
| 12 | 
            +
                  @client = Client.new(load_configuration)
         | 
| 13 | 
            +
                  @sqs_queues = [@client.to_quiet_queue, @client.from_quiet_queue]
         | 
| 14 | 
            +
                  @default_wait_time = @sqs_queues.map(&:wait_time_seconds).max
         | 
| 15 | 
            +
                  @sqs_queues.each { |queue| queue.wait_time_seconds = 1 }
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  @document = DocumentDouble.new(
         | 
| 18 | 
            +
                    :message_id => '1234567',
         | 
| 19 | 
            +
                    :date => Time.new(2013, 04, 05, 12, 30, 15).utc,
         | 
| 20 | 
            +
                    :filename => 'neat_beans.xml',
         | 
| 21 | 
            +
                    :client => @client,
         | 
| 22 | 
            +
                    :type => 'Thinger'
         | 
| 23 | 
            +
                  )
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                  @message = Message.new(:client => @client, :document => @document)
         | 
| 26 | 
            +
                  @queue = Queue.new(@client)
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                after do
         | 
| 30 | 
            +
                  @sqs_queues.each do |queue|
         | 
| 31 | 
            +
                    flush(queue)
         | 
| 32 | 
            +
                  end
         | 
| 33 | 
            +
                  @sqs_queues.each { |queue| queue.wait_time_seconds = @default_wait_time }
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                it "should be able to push a message onto the queue" do
         | 
| 37 | 
            +
                  expected_md5 = OpenSSL::Digest::MD5.new.hexdigest(@message.to_xml)
         | 
| 38 | 
            +
                  sent_message = @queue.send(@message)
         | 
| 39 | 
            +
                  assert_equal 1, @client.to_quiet_queue.approximate_number_of_messages
         | 
| 40 | 
            +
                  assert_equal expected_md5, sent_message.md5
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                it "should be able to fetch a message from the queue" do
         | 
| 44 | 
            +
                  @client.from_quiet_queue.send_message(@message.to_xml)
         | 
| 45 | 
            +
                  message = @queue.receive
         | 
| 46 | 
            +
                  assert_equal @message.to_xml, message.xml.to_xml
         | 
| 47 | 
            +
                  assert_equal @message.document_type, message.document_type
         | 
| 48 | 
            +
                  assert_equal @message.document_name, message.document_name
         | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                private
         | 
| 52 | 
            +
                def flush(queue)
         | 
| 53 | 
            +
                  pending_messages = queue.approximate_number_of_messages
         | 
| 54 | 
            +
                  while pending_messages > 0
         | 
| 55 | 
            +
                    queue.receive_message do |message|
         | 
| 56 | 
            +
                      message.delete
         | 
| 57 | 
            +
                      pending_messages -= 1
         | 
| 58 | 
            +
                    end
         | 
| 59 | 
            +
                  end
         | 
| 60 | 
            +
                end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
              end
         | 
| 63 | 
            +
            end
         | 
    
        data/spec/spec_helper.rb
    ADDED
    
    | @@ -0,0 +1,169 @@ | |
| 1 | 
            +
            require 'minitest/autorun'
         | 
| 2 | 
            +
            require 'nokogiri'
         | 
| 3 | 
            +
            require 'yaml'
         | 
| 4 | 
            +
            require 'mocha/setup'
         | 
| 5 | 
            +
            require 'hushed'
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            module Fixtures
         | 
| 8 | 
            +
              def load_fixture(path)
         | 
| 9 | 
            +
                File.open(path, 'rb')
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              def load_response(response_name)
         | 
| 13 | 
            +
                load_fixture("spec/fixtures/documents/responses/#{response_name}.xml")
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              def load_message(message_name)
         | 
| 17 | 
            +
                load_fixture("spec/fixtures/messages/#{message_name}.xml")
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
            end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            module Configuration
         | 
| 22 | 
            +
              def load_configuration
         | 
| 23 | 
            +
                test_credentials_file = ENV['HOME'] + '/.hushed/credentials.yml'
         | 
| 24 | 
            +
                test_credentials_file = "spec/fixtures/credentials.yml" unless File.exists?(test_credentials_file)
         | 
| 25 | 
            +
                YAML.load(File.open(test_credentials_file, 'rb'))
         | 
| 26 | 
            +
              end
         | 
| 27 | 
            +
            end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
            class LineItemDouble
         | 
| 30 | 
            +
              DEFAULT_OPTIONS = {
         | 
| 31 | 
            +
                :id => 123456,
         | 
| 32 | 
            +
                :quantity => 1,
         | 
| 33 | 
            +
                :unit_of_measure => 'EA',
         | 
| 34 | 
            +
                :price => '12.95'
         | 
| 35 | 
            +
              }
         | 
| 36 | 
            +
             | 
| 37 | 
            +
              attr_reader :id, :quantity, :unit_of_measure, :price
         | 
| 38 | 
            +
              def initialize(options = {})
         | 
| 39 | 
            +
                @id = options[:id]
         | 
| 40 | 
            +
                @quantity = options[:quantity]
         | 
| 41 | 
            +
                @unit_of_measure = options[:unit_of_measure]
         | 
| 42 | 
            +
                @price = options[:price]
         | 
| 43 | 
            +
              end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
              def self.example(options = {})
         | 
| 46 | 
            +
                self.new(DEFAULT_OPTIONS.merge(options))
         | 
| 47 | 
            +
              end
         | 
| 48 | 
            +
            end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
            class AddressDouble
         | 
| 51 | 
            +
              DEFAULT_OPTIONS = {
         | 
| 52 | 
            +
                :company => 'Shopify',
         | 
| 53 | 
            +
                :name => 'John Smith',
         | 
| 54 | 
            +
                :address1 => '123 Fake St',
         | 
| 55 | 
            +
                :address2 => 'Unit 128',
         | 
| 56 | 
            +
                :city => 'Ottawa',
         | 
| 57 | 
            +
                :province_code => 'ON',
         | 
| 58 | 
            +
                :country_code => 'CA',
         | 
| 59 | 
            +
                :zip => 'K1N 5T5'
         | 
| 60 | 
            +
              }
         | 
| 61 | 
            +
             | 
| 62 | 
            +
              attr_reader :company, :name, :address1, :address2, :city, :province_code
         | 
| 63 | 
            +
              attr_reader :country_code, :zip
         | 
| 64 | 
            +
              def initialize(options = {})
         | 
| 65 | 
            +
                @company = options[:company]
         | 
| 66 | 
            +
                @name = options[:name]
         | 
| 67 | 
            +
                @address1 = options[:address1]
         | 
| 68 | 
            +
                @address2 = options[:address2]
         | 
| 69 | 
            +
                @city = options[:city]
         | 
| 70 | 
            +
                @province_code = options[:province_code]
         | 
| 71 | 
            +
                @country_code = options[:country_code]
         | 
| 72 | 
            +
                @zip = options[:zip]
         | 
| 73 | 
            +
              end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
              def self.example(options = {})
         | 
| 76 | 
            +
                self.new(DEFAULT_OPTIONS.merge(options))
         | 
| 77 | 
            +
              end
         | 
| 78 | 
            +
            end
         | 
| 79 | 
            +
             | 
| 80 | 
            +
            class ShippingLineDouble
         | 
| 81 | 
            +
              def initialize(options = {})
         | 
| 82 | 
            +
                @options = options
         | 
| 83 | 
            +
              end
         | 
| 84 | 
            +
             | 
| 85 | 
            +
              def carrier
         | 
| 86 | 
            +
                @options[:code].split('_').first
         | 
| 87 | 
            +
              end
         | 
| 88 | 
            +
             | 
| 89 | 
            +
              def service_level
         | 
| 90 | 
            +
                @options[:code].split('_').last
         | 
| 91 | 
            +
              end
         | 
| 92 | 
            +
            end
         | 
| 93 | 
            +
             | 
| 94 | 
            +
            class OrderDouble
         | 
| 95 | 
            +
              DEFAULT_OPTIONS = {
         | 
| 96 | 
            +
                :line_items => [LineItemDouble.example],
         | 
| 97 | 
            +
                :shipping_address => AddressDouble.example,
         | 
| 98 | 
            +
                :billing_address => AddressDouble.example,
         | 
| 99 | 
            +
                :note => 'Happy Birthday',
         | 
| 100 | 
            +
                :created_at => Time.new(2013, 04, 05, 12, 30, 00),
         | 
| 101 | 
            +
                :id => 123456,
         | 
| 102 | 
            +
                :shipping_lines => [ShippingLineDouble.new(code: "FEDEX_GROUND", price: "34.40", source: "fedex", title: "FedEx Ground")],
         | 
| 103 | 
            +
                :email => 'john@smith.com',
         | 
| 104 | 
            +
                :total_price => '123.45'
         | 
| 105 | 
            +
              }
         | 
| 106 | 
            +
             | 
| 107 | 
            +
              attr_reader :line_items, :shipping_address, :billing_address, :note, :email
         | 
| 108 | 
            +
              attr_reader :total_price, :email, :id, :type, :created_at, :shipping_lines
         | 
| 109 | 
            +
              def initialize(options = {})
         | 
| 110 | 
            +
                @line_items = options[:line_items]
         | 
| 111 | 
            +
                @shipping_address = options[:shipping_address]
         | 
| 112 | 
            +
                @billing_address = options[:billing_address]
         | 
| 113 | 
            +
                @note = options[:note]
         | 
| 114 | 
            +
                @created_at = options[:created_at]
         | 
| 115 | 
            +
                @id = options[:id]
         | 
| 116 | 
            +
                @shipping_lines = options[:shipping_lines]
         | 
| 117 | 
            +
                @email = options[:email]
         | 
| 118 | 
            +
                @total_price = options[:total_price]
         | 
| 119 | 
            +
              end
         | 
| 120 | 
            +
             | 
| 121 | 
            +
              def self.example(options = {})
         | 
| 122 | 
            +
                self.new(DEFAULT_OPTIONS.merge(options))
         | 
| 123 | 
            +
              end
         | 
| 124 | 
            +
             | 
| 125 | 
            +
              def type
         | 
| 126 | 
            +
                @type || "SO"
         | 
| 127 | 
            +
              end
         | 
| 128 | 
            +
            end
         | 
| 129 | 
            +
             | 
| 130 | 
            +
            class DocumentDouble
         | 
| 131 | 
            +
              include Hushed::Documents::Document
         | 
| 132 | 
            +
              attr_accessor :type, :message_id, :warehouse, :date, :client
         | 
| 133 | 
            +
              attr_accessor :business_unit, :document_number, :io
         | 
| 134 | 
            +
             | 
| 135 | 
            +
              def initialize(options = {})
         | 
| 136 | 
            +
                options.each do |key, value|
         | 
| 137 | 
            +
                  self.public_send("#{key}=".to_sym, value)
         | 
| 138 | 
            +
                end
         | 
| 139 | 
            +
              end
         | 
| 140 | 
            +
             | 
| 141 | 
            +
              def to_xml
         | 
| 142 | 
            +
                builder = Nokogiri::XML::Builder.new do |xml|
         | 
| 143 | 
            +
                  xml.DocumentDouble 'Hello World'
         | 
| 144 | 
            +
                end
         | 
| 145 | 
            +
                builder.to_xml
         | 
| 146 | 
            +
              end
         | 
| 147 | 
            +
             | 
| 148 | 
            +
              def filename=(filename)
         | 
| 149 | 
            +
                @filename = filename
         | 
| 150 | 
            +
              end
         | 
| 151 | 
            +
            end
         | 
| 152 | 
            +
             | 
| 153 | 
            +
            class MessageDouble
         | 
| 154 | 
            +
              attr_accessor :document_name, :document_type
         | 
| 155 | 
            +
             | 
| 156 | 
            +
              def initialize(options = {})
         | 
| 157 | 
            +
                @document_name = options[:document_name]
         | 
| 158 | 
            +
                @document_type = options[:document_type]
         | 
| 159 | 
            +
              end
         | 
| 160 | 
            +
            end
         | 
| 161 | 
            +
             | 
| 162 | 
            +
            class ClientDouble
         | 
| 163 | 
            +
              attr_accessor :client_id, :business_unit
         | 
| 164 | 
            +
             | 
| 165 | 
            +
              def initialize(options = {})
         | 
| 166 | 
            +
                @client_id = options[:client_id]
         | 
| 167 | 
            +
                @business_unit = options[:business_unit]
         | 
| 168 | 
            +
              end
         | 
| 169 | 
            +
            end
         | 
| @@ -0,0 +1,102 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
            require 'hushed/blackboard'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module Hushed
         | 
| 5 | 
            +
              module Documents
         | 
| 6 | 
            +
                module Response
         | 
| 7 | 
            +
                  class ThingerResponse
         | 
| 8 | 
            +
                    attr_reader :contents
         | 
| 9 | 
            +
                    def initialize(contents)
         | 
| 10 | 
            +
                      @contents = contents
         | 
| 11 | 
            +
                    end
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                module Request
         | 
| 16 | 
            +
                  class ThingerRequest
         | 
| 17 | 
            +
                    attr_reader :contents
         | 
| 18 | 
            +
                    def initialize(contents)
         | 
| 19 | 
            +
                      @contents = contents
         | 
| 20 | 
            +
                    end
         | 
| 21 | 
            +
                  end
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
              end
         | 
| 24 | 
            +
            end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
            module Hushed
         | 
| 27 | 
            +
              describe "Blackboard" do
         | 
| 28 | 
            +
                before do
         | 
| 29 | 
            +
                  @bucket = mock()
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                  @client = mock()
         | 
| 32 | 
            +
                  @client.stubs(:to_quiet_bucket).returns(@bucket)
         | 
| 33 | 
            +
                  @client.stubs(:from_quiet_bucket).returns(@bucket)
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                  @io = StringIO.new
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                  @document = mock()
         | 
| 38 | 
            +
                  @document.stubs(:to_xml).returns("actually doesn't matter")
         | 
| 39 | 
            +
                  @document.stubs(:filename).returns("abracadabra_1234_xyz.xml")
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                  @message = mock()
         | 
| 42 | 
            +
                  @message.stubs(:document_type).returns('ShipmentOrderResult')
         | 
| 43 | 
            +
                  @message.stubs(:document_name).returns('abracadabra_4321_zyx.xml')
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                  @blackboard = Blackboard.new(@client)
         | 
| 46 | 
            +
                end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                it "should be possible to post a document to the blackboard" do
         | 
| 49 | 
            +
                  @bucket.expects(:objects).returns({@document.filename => @io})
         | 
| 50 | 
            +
                  @blackboard.post(@document)
         | 
| 51 | 
            +
                  assert_io(@document.to_xml, @io)
         | 
| 52 | 
            +
                end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                it "should be possible to build a document for a response type" do
         | 
| 55 | 
            +
                  Response.expects(:valid_type?).returns(true)
         | 
| 56 | 
            +
                  response = @blackboard.build_document('ThingerResponse', 'thinger')
         | 
| 57 | 
            +
                  assert_equal 'thinger', response.contents[:io]
         | 
| 58 | 
            +
                end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                it "should be possible to build a document for a request type" do
         | 
| 61 | 
            +
                  Request.expects(:valid_type?).returns(true)
         | 
| 62 | 
            +
                  response = @blackboard.build_document('ThingerRequest', 'thinger')
         | 
| 63 | 
            +
                  assert_equal 'thinger', response.contents[:io]
         | 
| 64 | 
            +
                end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                it "should return nil if the type was not valid" do
         | 
| 67 | 
            +
                  assert_equal nil, @blackboard.build_document('ThingerRequest', 'thinger')
         | 
| 68 | 
            +
                end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                it "should be possible to fetch a document from the blackboard" do
         | 
| 71 | 
            +
                  @io.write('fancy noodles')
         | 
| 72 | 
            +
                  @io.rewind
         | 
| 73 | 
            +
                  @bucket.expects(:objects).returns({@message.document_name => @io})
         | 
| 74 | 
            +
                  Response.expects(:valid_type?).returns(true)
         | 
| 75 | 
            +
                  @message.stubs(:document_type).returns('ThingerResponse')
         | 
| 76 | 
            +
                  assert_equal 'fancy noodles', @blackboard.fetch(@message).contents[:io]
         | 
| 77 | 
            +
                end
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                it "should be possible to remove a document from the blackboard" do
         | 
| 80 | 
            +
                  s3object = mock()
         | 
| 81 | 
            +
                  s3object.expects(:delete)
         | 
| 82 | 
            +
                  s3object.expects(:exists?).returns(true)
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                  @bucket.expects(:objects).returns({@message.document_name => s3object})
         | 
| 85 | 
            +
                  assert_equal true, @blackboard.remove(@message)
         | 
| 86 | 
            +
                end
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                it "should not raise an exception if the document for removal couldn't be found" do
         | 
| 89 | 
            +
                  s3object = mock()
         | 
| 90 | 
            +
                  s3object.expects(:delete).never
         | 
| 91 | 
            +
                  s3object.expects(:exists?).returns(false)
         | 
| 92 | 
            +
             | 
| 93 | 
            +
                  @bucket.expects(:objects).returns({@message.document_name => s3object})
         | 
| 94 | 
            +
                  assert_equal false, @blackboard.remove(@message)
         | 
| 95 | 
            +
                end
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                def assert_io(expectation, io)
         | 
| 98 | 
            +
                  io.rewind
         | 
| 99 | 
            +
                  assert_equal expectation, io.read
         | 
| 100 | 
            +
                end
         | 
| 101 | 
            +
              end
         | 
| 102 | 
            +
            end
         |