161 lines
4.9 KiB
Ruby
161 lines
4.9 KiB
Ruby
# typed: false
|
|
require "rails_helper"
|
|
|
|
RSpec.describe HttpLogEntry, type: :model do
|
|
describe "validations" do
|
|
subject { build(:http_log_entry) }
|
|
|
|
it { should validate_presence_of(:uri_scheme) }
|
|
it { should validate_presence_of(:uri_host) }
|
|
it { should validate_presence_of(:uri_path) }
|
|
it { should validate_presence_of(:verb) }
|
|
it { should validate_presence_of(:performed_by) }
|
|
it { should validate_presence_of(:status_code) }
|
|
it { should validate_presence_of(:response_time_ms) }
|
|
it { should validate_presence_of(:content_type) }
|
|
it { should validate_presence_of(:requested_at) }
|
|
|
|
it { should validate_length_of(:response_sha256).is_equal_to(32) }
|
|
end
|
|
|
|
describe "associations" do
|
|
it { should belong_to(:response).class_name("::BlobFile") }
|
|
it { should belong_to(:request_headers).class_name("::HttpLogEntryHeader") }
|
|
it do
|
|
should belong_to(:response_headers).class_name("::HttpLogEntryHeader")
|
|
end
|
|
it do
|
|
should belong_to(:caused_by_entry).class_name("::HttpLogEntry").optional
|
|
end
|
|
it { should have_many(:triggered_entries).class_name("::HttpLogEntry") }
|
|
end
|
|
|
|
describe "immutability" do
|
|
let(:entry) { create(:http_log_entry) }
|
|
|
|
it "prevents updates" do
|
|
expect { entry.update!(verb: :post) }.to raise_error(
|
|
ActiveRecord::ReadOnlyRecord,
|
|
)
|
|
end
|
|
|
|
it "prevents deletion" do
|
|
expect { entry.destroy }.to raise_error(ActiveRecord::ReadOnlyRecord)
|
|
end
|
|
end
|
|
|
|
describe "#uri=" do
|
|
let(:entry) { build(:http_log_entry) }
|
|
|
|
it "parses and sets URI components" do
|
|
entry.uri = "https://example.com/path?query=value#fragment"
|
|
|
|
expect(entry.uri_scheme).to eq("https")
|
|
expect(entry.uri_host).to eq("example.com")
|
|
expect(entry.uri_path).to eq("/path")
|
|
expect(entry.uri_query).to eq("query=value")
|
|
expect(entry.uri_hash).to eq("fragment")
|
|
end
|
|
|
|
it "handles URIs without optional components" do
|
|
entry.uri = "https://example.com/path"
|
|
|
|
expect(entry.uri_scheme).to eq("https")
|
|
expect(entry.uri_host).to eq("example.com")
|
|
expect(entry.uri_path).to eq("/path")
|
|
expect(entry.uri_query).to be_nil
|
|
expect(entry.uri_hash).to be_nil
|
|
end
|
|
|
|
it "parses complex URLs with multiple query parameters" do
|
|
entry.uri =
|
|
"https://www.example.com/big/path/here?and=query&other=query2#smaz"
|
|
|
|
expect(entry.uri_scheme).to eq("https")
|
|
expect(entry.uri_host).to eq("www.example.com")
|
|
expect(entry.uri_path).to eq("/big/path/here")
|
|
expect(entry.uri_query).to eq("and=query&other=query2")
|
|
expect(entry.uri_hash).to eq("smaz")
|
|
end
|
|
end
|
|
|
|
describe "#uri" do
|
|
let(:entry) { build(:http_log_entry, :with_query, :with_fragment) }
|
|
|
|
it "reconstructs the full URI" do
|
|
expect(entry.uri).to be_a(Addressable::URI)
|
|
expect(entry.uri.to_s).to eq(
|
|
"https://#{entry.uri_host}/path?foo=bar&baz=qux#section1",
|
|
)
|
|
end
|
|
end
|
|
|
|
describe "#uri_str" do
|
|
it "returns full URI string" do
|
|
entry = build(:http_log_entry, :with_query, :with_fragment)
|
|
expect(entry.uri_str).to eq(
|
|
"https://#{entry.uri_host}/path?foo=bar&baz=qux#section1",
|
|
)
|
|
end
|
|
|
|
it "handles URI without optional components" do
|
|
entry = build(:http_log_entry)
|
|
expect(entry.uri_str).to eq("https://#{entry.uri_host}/path")
|
|
end
|
|
end
|
|
|
|
describe "#uri_str_without_host" do
|
|
it "returns path and query components" do
|
|
entry = build(:http_log_entry, :with_query, :with_fragment)
|
|
expect(entry.uri_str_without_host).to eq("/path?foo=bar&baz=qux#section1")
|
|
end
|
|
|
|
it "handles path only" do
|
|
entry = build(:http_log_entry)
|
|
expect(entry.uri_str_without_host).to eq("/path")
|
|
end
|
|
end
|
|
|
|
describe ".find_by_uri_host_path" do
|
|
let!(:entry) { create(:http_log_entry) }
|
|
|
|
it "finds entry by URI string" do
|
|
found =
|
|
described_class.find_by_uri_host_path("https://#{entry.uri_host}/path")
|
|
expect(found).to eq(entry)
|
|
end
|
|
|
|
it "finds entry by Addressable::URI" do
|
|
uri = Addressable::URI.parse("https://#{entry.uri_host}/path")
|
|
found = described_class.find_by_uri_host_path(uri)
|
|
expect(found).to eq(entry)
|
|
end
|
|
|
|
it "returns nil for non-existent URI" do
|
|
found =
|
|
described_class.find_by_uri_host_path("https://nonexistent.com/path")
|
|
expect(found).to be_nil
|
|
end
|
|
end
|
|
|
|
describe "#response_size" do
|
|
let(:entry) { create(:http_log_entry) }
|
|
|
|
context "when response association is loaded" do
|
|
it "returns size from response object" do
|
|
test_content = "test content"
|
|
entry.response = build(:blob_file, contents: test_content)
|
|
expect(entry.response_size).to eq(test_content.bytesize)
|
|
end
|
|
end
|
|
|
|
context "when response association is not loaded" do
|
|
it "queries size directly from database" do
|
|
size = entry.response.size_bytes
|
|
entry.association(:response).reset
|
|
expect(entry.response_size).to eq(size)
|
|
end
|
|
end
|
|
end
|
|
end
|