Skip to content

Commit 90c5f53

Browse files
authored
Merge pull request alexrudall#165 from petergoldstein/feature/add_vcr_headers_and_body_matching
Adds body and headers matching for VCR
2 parents 869a4d9 + 937926f commit 90c5f53

File tree

2 files changed

+51
-1
lines changed

2 files changed

+51
-1
lines changed

spec/spec_helper.rb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,13 @@
33
require "ruby/openai"
44
require "vcr"
55

6+
Dir[File.expand_path("spec/support/**/*.rb")].sort.each { |f| require f }
7+
68
VCR.configure do |c|
79
c.hook_into :webmock
810
c.cassette_library_dir = "spec/fixtures/cassettes"
9-
c.default_cassette_options = { record: ENV["NO_VCR"] == "true" ? :all : :new_episodes }
11+
c.default_cassette_options = { record: ENV["NO_VCR"] == "true" ? :all : :new_episodes,
12+
match_requests_on: [:method, :uri, VCRMultipartMatcher.new] }
1013
c.filter_sensitive_data("<OPENAI_ACCESS_TOKEN>") { Ruby::OpenAI.configuration.access_token }
1114
c.filter_sensitive_data("<OPENAI_ORGANIZATION_ID>") { Ruby::OpenAI.configuration.organization_id }
1215
end

spec/support/vcr_multipart_matcher.rb

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
class VCRMultipartMatcher
2+
MULTIPART_HEADER_MATCHER = %r{^multipart/form-data; boundary=(.+)$}.freeze
3+
BOUNDARY_SUBSTITUTION = "----MultipartBoundaryAbcD3fGhiXyz00001".freeze
4+
5+
def call(request1, request2)
6+
return false unless same_content_type?(request1, request2)
7+
unless headers_excluding_content_type(request1) == headers_excluding_content_type(request2)
8+
return false
9+
end
10+
11+
normalized_multipart_body(request1) == normalized_multipart_body(request2)
12+
end
13+
14+
private
15+
16+
def same_content_type?(request1, request2)
17+
content_type1 = (request1.headers["Content-Type"] || []).first.to_s
18+
content_type2 = (request2.headers["Content-Type"] || []).first.to_s
19+
20+
if multipart_request?(content_type1)
21+
multipart_request?(content_type2)
22+
elsif multipart_request?(content_type2)
23+
false
24+
else
25+
content_type1 == content_type2
26+
end
27+
end
28+
29+
def headers_excluding_content_type(request)
30+
request.headers.except("Content-Type")
31+
end
32+
33+
def normalized_multipart_body(request)
34+
content_type = (request.headers["Content-Type"] || []).first.to_s
35+
36+
return request.headers unless multipart_request?(content_type)
37+
38+
boundary = MULTIPART_HEADER_MATCHER.match(content_type)[1]
39+
request.body.gsub(boundary, BOUNDARY_SUBSTITUTION)
40+
end
41+
42+
def multipart_request?(content_type)
43+
return false if content_type.empty?
44+
45+
MULTIPART_HEADER_MATCHER.match?(content_type)
46+
end
47+
end

0 commit comments

Comments
 (0)