<commit_before>require 'test_helper'

class AmazonMarketplaceWebServiceTest < Test::Unit::TestCase
  def setup
    @service = AmazonMarketplaceWebService.new(
                                               :login => 'l',
                                               :password => 'p'
                                               )
    
    @options = { 
      :shipping_method => 'Standard',
      :order_date => Time.now.utc.yesterday,
      :comment => "Delayed due to tornados"
    }
    
    @address = { 
      :name => '<NAME>',
      :address1 => '100 Information Super Highway',
      :address2 => 'Suite 66',
      :city => 'Beverly Hills',
      :state => 'CA',
      :country => 'US',
      :zip => '90210',
      :phone => "(555)555-5555"
    }
    
    @line_items = [
                   { :sku => 'SETTLERS1',
                     :quantity => 1,
                     :comment => 'Awesome'
                   }
                  ]
  end

  def test_get_default_fulfillment_gateway
    assert_equal AmazonMarketplaceWebService::ENDPOINTS[:us], @service.endpoint
  end

  def test_create_service_with_different_fulfillment_gateway
    service = AmazonMarketplaceWebService.new(:login => 'l', :password => 'p', :endpoint => :jp)
    assert_equal AmazonMarketplaceWebService::ENDPOINTS[:jp], service.endpoint
  end

  def test_build_basic_api_query
    options = {
      "Action" => "SubmitFeed",
      "FeedType" => "_POST_INVENTORY_AVAILABILITY_DATA_",
      "Merchant" => "SuperMerchant123"
    }
    expected_keys = ["AWSAccessKeyId", "Action", "FeedType", "Merchant", "SignatureMethod", "SignatureVersion", "Timestamp", "Version"]
    opts = @service.build_basic_api_query(options)
    assert_equal expected_keys.sort, opts.keys.map(&:to_s).sort
    assert_equal "l", opts["AWSAccessKeyId"]
    assert_equal AmazonMarketplaceWebService::SIGNATURE_VERSION, opts["SignatureVersion"]
    assert_equal "Hmac#{AmazonMarketplaceWebService::SIGNATURE_METHOD}", opts["SignatureMethod"]
    assert_equal AmazonMarketplaceWebService::VERSION, opts["Version"]
  end

  def test_build_inventory_list_request
    skus = ["CITADELS", "INNOVATION", "JAIPUR"]
    request_params = @service.build_inventory_list_request(:skus => skus)
    keys = request_params.keys

    assert keys.include?("SellerSkus.member.1")
    assert keys.include?("SellerSkus.member.2")
    assert keys.include?("SellerSkus.member.3")
    assert_equal 'CITADELS', request_params['SellerSkus.member.1']
    assert_equal 'INNOVATION', request_params['SellerSkus.member.2']
    assert_equal 'JAIPUR', request_params["SellerSkus.member.3"]
  end

  def test_create_signature
    service = AmazonMarketplaceWebService.new(:login => "0PExampleR2", :password => "<PASSWORD>")
    expected_signature = "39XxH6iKLysjjDmWZSkyr2z8iSxfECHBYE1Pd0Qqpwo%3D"
    options = {
      "AWSAccessKeyId" => "0PExampleR2",
      "Action" => "SubmitFeed",
      "FeedType" => "_POST_INVENTORY_AVAILABILITY_DATA_",
      "Marketplace" => "ATExampleER",
      "Merchant" => "A1ExampleE6", 
      "SignatureMethod" => "HmacSHA256",
      "SignatureVersion" => "2",
      "Timestamp" => "2009-08-20T01:10:27.607Z",
      "Version" => "2009-01-01"
    }

    uri = URI.parse("https://#{AmazonMarketplaceWebService::ENDPOINTS[:us]}")
    
    assert_equal expected_signature, service.sign(:POST, uri, options)
  end

  def test_verify_amazon_response
    service = AmazonMarketplaceWebService.new(:login => "AKIAFJPPO5KLY6G4XO7Q", :password => "<PASSWORD>")
    string_signed_by_amazon = "POST\nhttps://www.vendor.com/mwsApp1\n/orders/listRecentOrders.jsp?sessionId=123"
    string_signed_by_amazon += "\nAWSAccessKeyId=<KEY>&Marketplace=ATVPDKIKX0DER&Merchant=A047950713KM6AGKQCBRD&SignatureMethod=HmacSHA256&SignatureVersion=2"
    assert service.amazon_request?(string_signed_by_amazon, "b0hxWov1RfBOqNk77UDfNRRZmf3tkdM7vuNa%2FolfnWg%3D")
  end

  def test_build_address
    expected_items = {
      "DestinationAddress.Name" => @address[:name],
      "DestinationAddress.Line1" => @address[:address1],
      "DestinationAddress.Line2" => @address[:address2],
      "DestinationAddress.City" => @address[:city],
      "DestinationAddress.StateOrProvinceCode" => @address[:state],
      "DestinationAddress.CountryCode" => @address[:country],
      "DestinationAddress.PostalCode" => @address[:zip],
      "DestinationAddress.PhoneNumber" => @address[:phone]
    }
    assert_equal expected_items, @service.build_address(@address)
  end

  def test_build_address_with_missing_fields
    expected_items = {
      "DestinationAddress.Name" => @address[:name],
      "DestinationAddress.Line1" => @address[:address1],
      "DestinationAddress.City" => @address[:city],
      "DestinationAddress.StateOrProvinceCode" => @address[:state],
      "DestinationAddress.CountryCode" => @address[:country],
      "DestinationAddress.PostalCode" => @address[:zip],
      "DestinationAddress.PhoneNumber" => @address[:phone]
    }
    @address[:address2] = ""

    assert_equal expected_items, @service.build_address(@address)
  end

  def test_integrated_registration_url_creation
    service = AmazonMarketplaceWebService.new(:login => "AKIAFJPPO5KLY6G4XO7Q", :password => "<PASSWORD>", :app_id => "1014f5ad-c359-4e86-8e50-bb8f8e431a9")
    options = {
      "returnPathAndParameters" => "/orders/listRecentOrders.jsp?sessionId=123"
    }
    expected_registration_url = "#{AmazonMarketplaceWebService::REGISTRATION_URI.to_s}?AWSAccessKeyId=<KEY>&SignatureMethod=HmacSHA256&SignatureVersion=2&id=1<PASSWORD>-8<PASSWORD>8f8e431a9&returnPathAndParameters=%2Forders%2FlistRecentOrders.jsp%3FsessionId%3D123&Signature=zpZyHd8rMf5gg5rpO5ri5RGUi0kks03ZkhAtPm4npVk%3D"
    assert_equal expected_registration_url, service.registration_url(options)
  end

  def test_build_items
    expected_items = {
      "Items.member.1.DisplayableComment" => "Awesome",
      "Items.member.1.Quantity" => 1,
      "Items.member.1.SellerFulfillmentOrderItemId" => "SETTLERS1",
      "Items.member.1.SellerSKU" => "SETTLERS1"
    }

    actual_items = @service.build_items(@line_items)
                        
    assert_equal expected_items, @service.build_items(@line_items)
  end

  def test_successful_fulfillment
    @service.expects(:ssl_post).returns(successful_fulfillment_response)
    response = @service.fulfill('12345678', @address, @line_items, @options)
    assert response.success?
  end

  def test_invalid_arguments
    http_response = build_mock_response(invalid_params_response, "", 500)
    @service.expects(:ssl_post).raises(ActiveMerchant::ResponseError.new(http_response))
    response = @service.fulfill('12345678', @address, @line_items, @options)
    assert !response.success?
    assert_equal "MalformedInput: timestamp must follow ISO8601", response.params['response_comment']
  end

  def test_missing_order_date
    @options.delete(:order_date)
    assert_raise(ArgumentError) { @service.fulfill('12345678', @address, @line_items, @options) }
  end

  def test_missing_shipping_method
    @options.delete(:shipping_method)
    assert_raise(ArgumentError) { @service.fulfill('12345678', @address, @line_items, @options) }
  end

  def test_get_service_status
    @service.expects(:ssl_post).returns(successful_status_response)

    response = @service.status
    assert response.success?
  end

  def test_get_inventory
    @service.expects(:ssl_post).returns(xml_fixture('amazon_mws/inventory_list_inventory_supply'))

    response = @service.fetch_stock_levels
    assert response.success?
    assert_equal 202, response.stock_levels['GN-00-01A']
    assert_equal 199, response.stock_levels['GN-00-02A']
  end

  def test_get_inventory_multipage
    @service.expects(:ssl_post).twice.returns(
                                              xml_fixture('amazon_mws/inventory_list_inventory_supply_by_next_token'),
                                              xml_fixture('amazon_mws/inventory_list_inventory_supply')
                                              )

    response = @service.fetch_stock_levels
    assert response.success?
    assert_equal 202, response.stock_levels['GN-00-01A']
    assert_equal 199, response.stock_levels['GN-00-02A']
    assert_equal 0, response.stock_levels['GN-01-01A']
    assert_equal 5259, response.stock_levels['GN-01-02A']
  end

  def test_get_next_page_builds_query_with_proper_params
    @service.expects(:build_basic_api_query).with(:NextToken => "abracadabra", :Action => 'ListInventorySupplyByNextToken')
    @service.send(:build_next_inventory_list_request, "abracadabra")
  end

  def test_fetch_tracking_numbers
    @service.expects(:ssl_post).twice.
      returns(xml_fixture('amazon_mws/fulfillment_get_fulfillment_order')).
      returns(xml_fixture('amazon_mws/fulfillment_get_fulfillment_order_2'))

    response = @service.fetch_tracking_numbers(['extern_id_1154539615776', 'extern_id_1154539615777'])
    assert response.success?
    assert_equal '93ZZ00', response.tracking_numbers['extern_id_1154539615776']
    assert_nil response.tracking_numbers['extern_id_1154539615777']
  end

  def test_that_generated_requests_do_not_double_escape_spaces
    fulfillment_request = @service.send(:build_fulfillment_request, "12345", @address, @line_items, @options)
    result = @service.build_full_query(:post, URI.parse("http://example.com/someservice/2011"), fulfillment_request)<commit_msg>Improved inventory multipage test to ensure that ssl_post is being called with correct parameters.<commit_after>require 'test_helper'

class AmazonMarketplaceWebServiceTest < Test::Unit::TestCase
  def setup
    @service = AmazonMarketplaceWebService.new(
                                               :login => 'l',
                                               :password => 'p'
                                               )
    
    @options = { 
      :shipping_method => 'Standard',
      :order_date => Time.now.utc.yesterday,
      :comment => "Delayed due to tornados"
    }
    
    @address = { 
      :name => '<NAME>',
      :address1 => '100 Information Super Highway',
      :address2 => 'Suite 66',
      :city => 'Beverly Hills',
      :state => 'CA',
      :country => 'US',
      :zip => '90210',
      :phone => "(555)555-5555"
    }
    
    @line_items = [
                   { :sku => 'SETTLERS1',
                     :quantity => 1,
                     :comment => 'Awesome'
                   }
                  ]
  end

  def test_get_default_fulfillment_gateway
    assert_equal AmazonMarketplaceWebService::ENDPOINTS[:us], @service.endpoint
  end

  def test_create_service_with_different_fulfillment_gateway
    service = AmazonMarketplaceWebService.new(:login => 'l', :password => 'p', :endpoint => :jp)
    assert_equal AmazonMarketplaceWebService::ENDPOINTS[:jp], service.endpoint
  end

  def test_build_basic_api_query
    options = {
      "Action" => "SubmitFeed",
      "FeedType" => "_POST_INVENTORY_AVAILABILITY_DATA_",
      "Merchant" => "SuperMerchant123"
    }
    expected_keys = ["AWSAccessKeyId", "Action", "FeedType", "Merchant", "SignatureMethod", "SignatureVersion", "Timestamp", "Version"]
    opts = @service.build_basic_api_query(options)
    assert_equal expected_keys.sort, opts.keys.map(&:to_s).sort
    assert_equal "l", opts["AWSAccessKeyId"]
    assert_equal AmazonMarketplaceWebService::SIGNATURE_VERSION, opts["SignatureVersion"]
    assert_equal "Hmac#{AmazonMarketplaceWebService::SIGNATURE_METHOD}", opts["SignatureMethod"]
    assert_equal AmazonMarketplaceWebService::VERSION, opts["Version"]
  end

  def test_build_inventory_list_request
    skus = ["CITADELS", "INNOVATION", "JAIPUR"]
    request_params = @service.build_inventory_list_request(:skus => skus)
    keys = request_params.keys

    assert keys.include?("SellerSkus.member.1")
    assert keys.include?("SellerSkus.member.2")
    assert keys.include?("SellerSkus.member.3")
    assert_equal 'CITADELS', request_params['SellerSkus.member.1']
    assert_equal 'INNOVATION', request_params['SellerSkus.member.2']
    assert_equal 'JAIPUR', request_params["SellerSkus.member.3"]
  end

  def test_create_signature
    service = AmazonMarketplaceWebService.new(:login => "0PExampleR2", :password => "<PASSWORD>")
    expected_signature = "39XxH6iKLysjjDmWZSkyr2z8iSxfECHBYE1Pd0Qqpwo%3D"
    options = {
      "AWSAccessKeyId" => "0PExampleR2",
      "Action" => "SubmitFeed",
      "FeedType" => "_POST_INVENTORY_AVAILABILITY_DATA_",
      "Marketplace" => "ATExampleER",
      "Merchant" => "A1ExampleE6", 
      "SignatureMethod" => "HmacSHA256",
      "SignatureVersion" => "2",
      "Timestamp" => "2009-08-20T01:10:27.607Z",
      "Version" => "2009-01-01"
    }

    uri = URI.parse("https://#{AmazonMarketplaceWebService::ENDPOINTS[:us]}")
    
    assert_equal expected_signature, service.sign(:POST, uri, options)
  end

  def test_verify_amazon_response
    service = AmazonMarketplaceWebService.new(:login => "AKIAFJPPO5KLY6G4XO7Q", :password => "<PASSWORD>")
    string_signed_by_amazon = "POST\nhttps://www.vendor.com/mwsApp1\n/orders/listRecentOrders.jsp?sessionId=123"
    string_signed_by_amazon += "\nAWSAccessKeyId=<KEY>&Marketplace=ATVPDKIKX0DER&Merchant=A047950713KM6AGKQCBRD&SignatureMethod=HmacSHA256&SignatureVersion=2"
    assert service.amazon_request?(string_signed_by_amazon, "b0hxWov1RfBOqNk77UDfNRRZmf3tkdM7vuNa%2FolfnWg%3D")
  end

  def test_build_address
    expected_items = {
      "DestinationAddress.Name" => @address[:name],
      "DestinationAddress.Line1" => @address[:address1],
      "DestinationAddress.Line2" => @address[:address2],
      "DestinationAddress.City" => @address[:city],
      "DestinationAddress.StateOrProvinceCode" => @address[:state],
      "DestinationAddress.CountryCode" => @address[:country],
      "DestinationAddress.PostalCode" => @address[:zip],
      "DestinationAddress.PhoneNumber" => @address[:phone]
    }
    assert_equal expected_items, @service.build_address(@address)
  end

  def test_build_address_with_missing_fields
    expected_items = {
      "DestinationAddress.Name" => @address[:name],
      "DestinationAddress.Line1" => @address[:address1],
      "DestinationAddress.City" => @address[:city],
      "DestinationAddress.StateOrProvinceCode" => @address[:state],
      "DestinationAddress.CountryCode" => @address[:country],
      "DestinationAddress.PostalCode" => @address[:zip],
      "DestinationAddress.PhoneNumber" => @address[:phone]
    }
    @address[:address2] = ""

    assert_equal expected_items, @service.build_address(@address)
  end

  def test_integrated_registration_url_creation
    service = AmazonMarketplaceWebService.new(:login => "AKIAFJPPO5KLY6G4XO7Q", :password => "<PASSWORD>", :app_id => "1014f5ad-c359-4e86-8e50-bb8f8e431a9")
    options = {
      "returnPathAndParameters" => "/orders/listRecentOrders.jsp?sessionId=123"
    }
    expected_registration_url = "#{AmazonMarketplaceWebService::REGISTRATION_URI.to_s}?AWSAccessKeyId=<KEY>&SignatureMethod=HmacSHA256&SignatureVersion=2&id=1014f5ad-c359-4e86-8e50-bb8f8e431a9&returnPathAndParameters=%2Forders%2FlistRecentOrders.jsp%3FsessionId%3D123&Signature=zpZyHd8rMf5gg5rpO5ri5RGUi0kks03ZkhAtPm4npVk%3D"
    assert_equal expected_registration_url, service.registration_url(options)
  end

  def test_build_items
    expected_items = {
      "Items.member.1.DisplayableComment" => "Awesome",
      "Items.member.1.Quantity" => 1,
      "Items.member.1.SellerFulfillmentOrderItemId" => "SETTLERS1",
      "Items.member.1.SellerSKU" => "SETTLERS1"
    }

    actual_items = @service.build_items(@line_items)
                        
    assert_equal expected_items, @service.build_items(@line_items)
  end

  def test_successful_fulfillment
    @service.expects(:ssl_post).returns(successful_fulfillment_response)
    response = @service.fulfill('12345678', @address, @line_items, @options)
    assert response.success?
  end

  def test_invalid_arguments
    http_response = build_mock_response(invalid_params_response, "", 500)
    @service.expects(:ssl_post).raises(ActiveMerchant::ResponseError.new(http_response))
    response = @service.fulfill('12345678', @address, @line_items, @options)
    assert !response.success?
    assert_equal "MalformedInput: timestamp must follow ISO8601", response.params['response_comment']
  end

  def test_missing_order_date
    @options.delete(:order_date)
    assert_raise(ArgumentError) { @service.fulfill('12345678', @address, @line_items, @options) }
  end

  def test_missing_shipping_method
    @options.delete(:shipping_method)
    assert_raise(ArgumentError) { @service.fulfill('12345678', @address, @line_items, @options) }
  end

  def test_get_service_status
    @service.expects(:ssl_post).returns(successful_status_response)

    response = @service.status
    assert response.success?
  end

  def test_get_inventory
    @service.expects(:ssl_post).returns(xml_fixture('amazon_mws/inventory_list_inventory_supply'))

    response = @service.fetch_stock_levels
    assert response.success?
    assert_equal 202, response.stock_levels['GN-00-01A']
    assert_equal 199, response.stock_levels['GN-00-02A']
  end

  def test_get_inventory_multipage
    @service.expects(:ssl_post).with() { |uri, query, headers|
      query.include?('ListInventorySupply') && !query.include?('ListInventorySupplyByNextToken')
    }.returns(xml_fixture('amazon_mws/inventory_list_inventory_supply_by_next_token'))
    
    @service.expects(:ssl_post).with() { |uri, query, headers|
      query.include?('ListInventorySupplyByNextToken') && query.include?('NextToken')
    }.returns(xml_fixture('amazon_mws/inventory_list_inventory_supply'))

    response = @service.fetch_stock_levels
    assert response.success?
    
    assert_equal 202, response.stock_levels['GN-00-01A']
    assert_equal 199, response.stock_levels['GN-00-02A']
    assert_equal 0, response.stock_levels['GN-01-01A']
    assert_equal 5259, response.stock_levels['GN-01-02A']
  end

  def test_get_next_page_builds_query_with_proper_params
    @service.expects(:build_basic_api_query).with(:NextToken => "abracadabra", :Action => 'ListInventorySupplyByNextToken')
    @service.send(:build_next_inventory_list_request, "abracadabra")
  end

  def test_fetch_tracking_numbers
    @service.expects(:ssl_post).twice.
      returns(xml_fixture('amazon_mws/fulfillment_get_fulfillment_order')).
      returns(xml_fixture('amazon_mws/fulfillment_get_fulfillment_order_2'))

    response = @service.fetch_tracking_numbers(['extern_id_1154539615776', 'extern_id_1154539615777'])
    assert response.success?
    assert_equal '93ZZ00', response.tracking_numbers['extern_id_1154539615776']
    assert_nil response.tracking_numbers['extern_id_1154539615777']
  end

  def test_that_generated_requests_do_not_double_escape_spaces
    fulfillment_request = @service.send(:build_fulfillment_request, "12345", @address, @line_items, @options)
    result = @service.build_full_query(:post, URI.parse("http://example.com/someservice/2011"), fulfillment_request)
{'fraction_non_alphanumeric': 0.1216436340707267, 'fraction_numerical': 0.034575166833061846, 'mean_word_length': 4.241531258606445, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 139, 'https://': 4, 'lorem ipsum': 0, 'www.': 2, 'xml': 10}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 18, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5884693', 'n_tokens_mistral': 6616, 'n_tokens_neox': 6138, 'n_words': 817}