Back to Repositories

Testing HTTP Utility Functions Implementation in Faraday

This test suite validates Faraday’s utility functions, focusing on HTTP header parsing, URI handling, and deep merging capabilities. The tests ensure robust handling of HTTP responses and configuration options in the Faraday HTTP client library.

Test Coverage Overview

The test suite covers three main utility components:
  • Header parsing for multi-response scenarios
  • URI parsing with different parser implementations
  • Deep merging of connection options and configurations
Key edge cases include safe buffer escaping and handling of nested configuration structures.

Implementation Analysis

The testing approach uses RSpec’s describe/context blocks to organize related test cases. It leverages let blocks for test data setup and implements custom matchers for header validation. The implementation demonstrates proper isolation of test scenarios and careful handling of complex nested data structures.

Technical Details

Testing tools and configuration:
  • RSpec as the testing framework
  • Custom FakeSafeBuffer implementation
  • Mock URI parser configurations
  • ConnectionOptions structs for configuration testing

Best Practices Demonstrated

The test suite exemplifies several testing best practices:
  • Proper test isolation and setup
  • Clear test case organization
  • Comprehensive edge case coverage
  • Effective use of RSpec’s let blocks for data preparation
  • Thorough validation of complex data structures

lostisland/faraday

spec/faraday/utils_spec.rb

            
# frozen_string_literal: true

RSpec.describe Faraday::Utils do
  describe 'headers parsing' do
    let(:multi_response_headers) do
      "HTTP/1.x 500 OK\r
Content-Type: text/html; charset=UTF-8\r
" \
        "HTTP/1.x 200 OK\r
Content-Type: application/json; charset=UTF-8\r
\r
"
    end

    it 'parse headers for aggregated responses' do
      headers = Faraday::Utils::Headers.new
      headers.parse(multi_response_headers)

      result = headers.to_hash

      expect(result['Content-Type']).to eq('application/json; charset=UTF-8')
    end
  end

  describe 'URI parsing' do
    let(:url) { 'http://example.com/abc' }

    it 'escapes safe buffer' do
      str = FakeSafeBuffer.new('$32,000.00')
      expect(Faraday::Utils.escape(str)).to eq('%2432%2C000.00')
    end

    it 'parses with default parser' do
      with_default_uri_parser(nil) do
        uri = normalize(url)
        expect(uri.host).to eq('example.com')
      end
    end

    it 'parses with URI' do
      with_default_uri_parser(::URI) do
        uri = normalize(url)
        expect(uri.host).to eq('example.com')
      end
    end

    it 'parses with block' do
      with_default_uri_parser(->(u) { "booya#{'!' * u.size}" }) do
        expect(normalize(url)).to eq('booya!!!!!!!!!!!!!!!!!!!!!!')
      end
    end

    it 'replaces headers hash' do
      headers = Faraday::Utils::Headers.new('authorization' => 't0ps3cr3t!')
      expect(headers).to have_key('authorization')

      headers.replace('content-type' => 'text/plain')
      expect(headers).not_to have_key('authorization')
    end
  end

  describe '.deep_merge!' do
    let(:connection_options) { Faraday::ConnectionOptions.new }
    let(:url) do
      {
        url: 'http://example.com/abc',
        headers: { 'Mime-Version' => '1.0' },
        request: { oauth: { consumer_key: 'anonymous' } },
        ssl: { version: '2' }
      }
    end

    it 'recursively merges the headers' do
      connection_options.headers = { user_agent: 'My Agent 1.0' }
      deep_merge = Faraday::Utils.deep_merge!(connection_options, url)

      expect(deep_merge.headers).to eq('Mime-Version' => '1.0', user_agent: 'My Agent 1.0')
    end

    context 'when a target hash has an Options Struct value' do
      let(:request) do
        {
          params_encoder: nil,
          proxy: nil,
          bind: nil,
          timeout: nil,
          open_timeout: nil,
          read_timeout: nil,
          write_timeout: nil,
          boundary: nil,
          oauth: { consumer_key: 'anonymous' },
          context: nil,
          on_data: nil
        }
      end
      let(:ssl) do
        {
          verify: nil,
          ca_file: nil,
          ca_path: nil,
          verify_mode: nil,
          cert_store: nil,
          client_cert: nil,
          client_key: nil,
          certificate: nil,
          private_key: nil,
          verify_depth: nil,
          version: '2',
          min_version: nil,
          max_version: nil,
          verify_hostname: nil,
          ciphers: nil
        }
      end

      it 'does not overwrite an Options Struct value' do
        deep_merge = Faraday::Utils.deep_merge!(connection_options, url)

        expect(deep_merge.request.to_h).to eq(request)
        expect(deep_merge.ssl.to_h).to eq(ssl)
      end
    end
  end
end