Skip to content

Commit

Permalink
ensure order on all modes
Browse files Browse the repository at this point in the history
  • Loading branch information
jsvd committed Aug 21, 2020
1 parent c761fa1 commit 2bb56fc
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 23 deletions.
6 changes: 3 additions & 3 deletions lib/logstash/filters/fingerprint.rb
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ def filter(event)
end
else
@source.sort.each do |k|
to_string << "|#{k}|#{event.get(k)}"
to_string << "|#{k}|#{deep_sort_hashes(event.get(k))}"
end
end
to_string << "|"
Expand All @@ -134,9 +134,9 @@ def filter(event)
@source.each do |field|
next unless event.include?(field)
if event.get(field).is_a?(Array)
event.set(@target, event.get(field).collect { |v| fingerprint(v) })
event.set(@target, event.get(field).collect { |v| fingerprint(deep_sort_hashes(v)) })
else
event.set(@target, fingerprint(event.get(field)))
event.set(@target, fingerprint(deep_sort_hashes(event.get(field))))
end
end
end
Expand Down
63 changes: 43 additions & 20 deletions spec/filters/fingerprint_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -231,29 +231,52 @@
end

describe "tolerance to hash order" do
let(:config) { { "concatenate_all_fields" => true } }
context "when two events have same content but different hash order" do
# insertion order can influence the result of to_hash's keys
let(:data1) { { "a" => {"a0" => 0, "a1" => 1} } }
let(:event1) { LogStash::Event.new(data1) }
let(:data2) { { "a" => {"a1" => 1, "a0" => 0} } }
let(:event2) { LogStash::Event.new(data2) }
# insertion order can influence the result of to_hash's keys
let(:data1) { {
"a" => {"a0" => 0, "a1" => 1},
"b" => {"b0" => 0, "b1" => 1},
} }
let(:event1) { LogStash::Event.new(data1) }
let(:data2) { {
"b" => {"b1" => 1, "b0" => 0},
"a" => {"a1" => 1, "a0" => 0},
} }
let(:event2) { LogStash::Event.new(data2) }
let(:config) { { "source" => [ "a" ] } }

before(:each) do
# for testing purposes we want to ensure the hash order is different.
# unfortunately we can't really control the order on the underlying Map
# so we're mocking the order here
allow(event1).to receive(:to_hash).and_return(data1)
allow(event2).to receive(:to_hash).and_return(data2)
plugin.filter(event1)
plugin.filter(event2)
before(:each) do
# for testing purposes we want to ensure the hash order is different.
# unfortunately we can't really control the order on the underlying Map
# so we're mocking the order here
allow(event1).to receive(:to_hash).and_return(data1)
allow(event2).to receive(:to_hash).and_return(data2)
# mock event.get("a") and event.get("b") for both events
allow(event1).to receive(:get).with("a") {|arg| event1.to_hash["a"] }
allow(event1).to receive(:get).with("b") {|arg| event1.to_hash["b"] }
allow(event2).to receive(:get).with("a") {|arg| event2.to_hash["a"] }
allow(event2).to receive(:get).with("b") {|arg| event2.to_hash["b"] }
# wire event.get("fingerprint") directly
allow(event1).to receive(:get).with("fingerprint").and_call_original
allow(event2).to receive(:get).with("fingerprint").and_call_original
plugin.filter(event1)
plugin.filter(event2)
end
it "computes the same hash" do
# confirm the order of the keys in the nested hash is different
# (of course it is, we just mocked the to_hash return)
expect(event1.to_hash["a"].keys).to_not eq(event2.to_hash["a"].keys)
# let's check that the fingerprint doesn't care about the insertion order
expect(event1.get("fingerprint")).to eq(event2.get("fingerprint"))
end
context "concatenate_sources" do
let("config") { { "source" => [ "a", "b"], "concatenate_sources" => true } }
it "computes the same hash" do
expect(event1.get("fingerprint")).to eq(event2.get("fingerprint"))
end

end
context "concatenate_all_fields => true" do
let(:config) { { "concatenate_all_fields" => true } }
it "computes the same hash" do
# confirm the order of the keys in the nested hash is different
# (of course it is, we just mocked the to_hash return)
expect(event1.to_hash["a"].keys).to_not eq(event2.to_hash["a"].keys)
# let's check that the fingerprint doesn't care about the insertion order
expect(event1.get("fingerprint")).to eq(event2.get("fingerprint"))
end
end
Expand Down

0 comments on commit 2bb56fc

Please sign in to comment.