Back to Repositories

failed

This test suite examines VCR’s Faraday middleware integration, focusing on HTTP request recording and playback functionality. It validates multipart uploads, parallel requests, and various HTTP library adapters while ensuring proper request handling and cassette management.

Test Coverage Overview

The test suite provides comprehensive coverage of VCR’s Faraday middleware functionality.

Key areas tested include:
  • Multiple HTTP library adapters (typhoeus, net_http, patron)
  • Multipart upload handling
  • Parallel request processing
  • Response body extensions
  • Cassette recording and playback verification

Implementation Analysis

The testing approach utilizes RSpec’s shared examples and contexts to validate different HTTP adapters and scenarios. The implementation employs sophisticated patterns for testing asynchronous operations and middleware behavior, with particular attention to connection handling and request lifecycles.

Framework-specific features include:
  • RSpec shared behavior testing
  • Dynamic test generation for different HTTP libraries
  • Parallel request testing with Typhoeus
  • Middleware hook validation

Technical Details

Testing tools and configuration:
  • RSpec as the testing framework
  • VCR for HTTP interaction recording
  • Faraday for HTTP client abstraction
  • Multiple HTTP adapters (Typhoeus, Net::HTTP, Patron)
  • Sinatra for mock server implementation
  • Custom middleware hooks and request stubbing

Best Practices Demonstrated

The test suite exemplifies high-quality testing practices through comprehensive coverage and robust implementation.

Notable practices include:
  • Isolation of HTTP adapter testing
  • Proper cleanup and resource management
  • Thorough edge case handling
  • Consistent test organization
  • Effective use of shared examples
  • Comprehensive middleware lifecycle testing

vcr/vcr

spec/lib/vcr/middleware/faraday_spec.rb

            
require 'spec_helper'
require 'vcr/library_hooks/faraday'
require 'faraday/multipart'

RSpec.describe VCR::Middleware::Faraday do
  http_libs = %w[ typhoeus net_http patron ]
  http_libs.each do |lib|
    flags = [ :does_not_support_rotating_responses ]
    if lib == 'typhoeus'
      flags << :status_message_not_exposed
    end

    it_behaves_like 'a hook into an HTTP library', :faraday, "faraday (w/ #{lib})", *flags
  end

  context 'when performing a multipart upload' do
    let(:connection) do
      ::Faraday.new("http://localhost:#{VCR::SinatraApp.port}/") do |b|
        b.request :multipart
      end
    end

    def self.test_recording
      it 'records the request body correctly' do
        payload = { :file => Faraday::FilePart.new(__FILE__, 'text/plain') }

        expect(VCR).to receive(:record_http_interaction) do |i|
          expect(i.request.headers['Content-Type'].first).to include("multipart")
          expect(i.request.body).to include(File.read(__FILE__))
        end

        VCR.use_cassette("upload") do
          connection.post '/files', payload
        end
      end
    end

    context 'when the net_http adapter is used' do
      before { connection.builder.adapter :net_http }
      test_recording
    end

    context 'when no adapter is used' do
      test_recording
    end
  end

  context 'when extending the response body with an extension module' do
    let(:connection) { ::Faraday.new("http://localhost:#{VCR::SinatraApp.port}/") }

    def process_response(response)
      response.body.extend Module.new { attr_accessor :_response }
      response.body._response = response
    end

    it 'does not record the body extensions to the cassette' do
      3.times do |i|
        VCR.use_cassette("hack", :record => :new_episodes) do
          response = connection.get("/foo")
          process_response(response)

          # Do something different after the first time to
          # ensure new interactions are added to an existing
          # cassette.
          if i > 1
            response = connection.get("/")
            process_response(response)
          end
        end
      end

      contents = VCR::Cassette.new("hack").send(:raw_cassette_bytes)
      expect(contents).not_to include("ruby/object:Faraday::Response")
    end
  end

  context 'when making parallel requests' do
    include VCRStubHelpers
    let(:connection)         { ::Faraday.new { |b| b.adapter :typhoeus } }
    let(:request_url) { "http://localhost:#{VCR::SinatraApp.port}/" }

    it 'works correctly with multiple parallel requests' do
      recorded, played_back = [1, 2].map do
        responses = []

        VCR.use_cassette("multiple_parallel") do
          connection.in_parallel do
            responses << connection.get(request_url)
            responses << connection.get(request_url)
          end
        end

        responses.map(&:body)
      end

      # there should be no blanks
      expect(recorded.select { |r| r.to_s == '' }).to eq([])
      expect(played_back).to eq(recorded)
    end

    shared_examples_for "exclusive library hook" do
      def make_request
        connection.in_parallel { connection.get(request_url) }
      end

      it 'makes the faraday middleware exclusively enabled for the duration of the request' do
        expect(VCR.library_hooks).not_to be_disabled(:webmock)

        hook_called = false
        VCR.configuration.after_http_request do
          hook_called = true
          expect(VCR.library_hooks).to be_disabled(:webmock)
        end

        make_request
        expect(VCR.library_hooks).not_to be_disabled(:webmock)
        expect(hook_called).to be true
      end
    end

    context 'for an ignored request' do
      before(:each) { VCR.configuration.ignore_request { true } }
      it_behaves_like "exclusive library hook"
    end

    context 'for a stubbed request' do
      it_behaves_like "exclusive library hook" do
        before(:each) do
          stub_requests([http_interaction(request_url)], [:method, :uri])
        end
      end
    end

    context "when another adapter is exclusive" do
      it 'still makes requests properly' do
        response = VCR.library_hooks.exclusively_enabled(:typhoeus) do
          Faraday.get("http://localhost:#{VCR::SinatraApp.port}/")
        end

        expect(response.body).to eq("GET to root")
      end
    end

    context 'for a recorded request' do
      let!(:inserted_cassette) { VCR.insert_cassette('new_cassette') }
      before(:each) { expect(VCR).to receive(:record_http_interaction) }
      it_behaves_like "exclusive library hook"
    end

    context 'for a disallowed request' do
      it_behaves_like "exclusive library hook" do
        undef make_request
        def make_request
          expect {
            connection.in_parallel { connection.get(request_url) }
          }.to raise_error(VCR::Errors::UnhandledHTTPRequestError)
        end
      end
    end

    it_behaves_like "request hooks", :faraday, :recordable do
      let!(:inserted_cassette) { VCR.insert_cassette('new_cassette') }

      undef make_request
      def make_request(disabled = false)
        response = nil
        connection.in_parallel do
          response = connection.get(request_url)
        end
        response
      end

      it 'can be used to eject a cassette after the request is recorded' do
        VCR.configuration.after_http_request { |request| VCR.eject_cassette }

        expect(VCR).to receive(:record_http_interaction) do |interaction|
          expect(VCR.current_cassette).to be(inserted_cassette)
        end

        make_request
        expect(VCR.current_cassette).to be_nil
      end
    end
  end if defined?(::Typhoeus)

  describe '#close' do
    let(:faraday_app) { double }

    def close
      described_class.new(faraday_app).close
    end

    context 'when adapter supports persistent connections' do
      it 'calls adapter close method' do
        expect(faraday_app).to receive(:close)
        close
      end
    end

    context 'when adapter does not support persistent connections' do
      it 'does not raise error' do
        expect { close }.not_to raise_error
      end
    end
  end
end