Async::HTTP::CaptureSourceAsyncHTTPCaptureCassette

class Cassette

Represents a collection of HTTP interactions using content-addressed storage.

A cassette serves as a container for multiple class Async::HTTP::Capture::Interaction objects, storing each interaction as a separate JSON file in a directory. Files are named using the content hash of the interaction, providing automatic de-duplication and parallel-safe recording.

Definitions

attr_reader :interactions

Signature

attribute Array(Interaction)

The collection of interactions.

def initialize(interactions = [])

Initialize a new cassette with the provided interactions.

Signature

parameter interactions Array(Interaction)

The interactions to include in the cassette.

Implementation

def initialize(interactions = [])
	@interactions = interactions
end

def each(&block)

Iterate over each interaction in the cassette.

Signature

yields {|interaction| ...}

Each interaction in the cassette.

parameter interaction Interaction

The current interaction being yielded.

Implementation

def each(&block)
	@interactions.each(&block)
end

def self.load(directory_path)

Load a cassette from a directory of JSON interaction files.

Signature

parameter directory_path String

The path to the directory containing JSON interaction files.

returns Cassette

A new cassette instance with the loaded interactions.

raises JSON::ParserError

If any file contains invalid JSON.

Implementation

def self.load(directory_path)
	return new([]) unless File.directory?(directory_path)
	
	json_files = Dir.glob(File.join(directory_path, "*.json"))
	interactions = json_files.map do |file_path|
		data = JSON.parse(File.read(file_path), symbolize_names: true)
		Interaction.new(data)
	end
	
	return self.new(interactions)
end

def save(directory_path)

Save the cassette to a directory using timestamped files. Each interaction is saved as a separate JSON file with a timestamp-based name. This approach provides parallel-safe recording.

Signature

parameter directory_path String

The path to the directory where interactions should be saved.

Implementation

def save(directory_path)
	FileUtils.mkdir_p(directory_path)
	
	@interactions.each_with_index do |interaction, index|
		timestamp = Time.now.strftime("%Y%m%d-%H%M%S-%6N") 
		filename = "#{timestamp}-#{index}.json"
		file_path = File.join(directory_path, filename)
		File.write(file_path, JSON.pretty_generate(interaction.to_h))
	end
end

def replay(app)

Replay all interactions against the provided application. This is useful for warming up applications by replaying recorded traffic.

Signature

parameter app #call

The application to replay interactions against.

Implementation

def replay(app)
	count = @interactions.length
	Console.info(self) {"Replaying #{count} interactions for warmup..."}
	
	@interactions.each do |interaction|
		Console.debug(self, "Replaying interaction:", interaction)
		
		# Replay the interaction against the app:
		if request = interaction.request
			begin
				response = app.call(request)
				response.finish
			rescue => error
				Console.warn(self, "Failed to replay interaction:", error)
			end
		end
	end
	
	Console.info(self) {"Warmup complete."}
end