|
| 1 | +# encoding: utf-8 |
| 2 | +require "logstash/devutils/rspec/spec_helper" |
| 3 | +require "logstash/filters/geoip" |
| 4 | +require_relative 'test_helper' |
| 5 | +require 'logstash/plugin_mixins/ecs_compatibility_support/spec_helper' |
| 6 | + |
| 7 | +CITYDB = ::Dir.glob(::File.expand_path(::File.join("..", "..", "..", "vendor", "GeoLite2-City.mmdb"), __FILE__)).first |
| 8 | +ASNDB = ::Dir.glob(::File.expand_path(::File.join("..", "..", "..", "vendor", "GeoLite2-ASN.mmdb"), __FILE__)).first |
| 9 | + |
| 10 | +describe LogStash::Filters::GeoIP do |
| 11 | + let(:options) { {} } |
| 12 | + let(:plugin) { LogStash::Filters::GeoIP.new(options) } |
| 13 | + |
| 14 | + describe "simple ip filter", :aggregate_failures do |
| 15 | + |
| 16 | + context "when specifying the target", :ecs_compatibility_support do |
| 17 | + ecs_compatibility_matrix(:disabled, :v1) do |ecs_select| |
| 18 | + |
| 19 | + let(:ip) { "8.8.8.8" } |
| 20 | + let(:event) { LogStash::Event.new("message" => ip) } |
| 21 | + let(:target) { "server" } |
| 22 | + let(:common_options) { {"source" => "message", "database" => CITYDB, "target" => target} } |
| 23 | + |
| 24 | + before(:each) do |
| 25 | + allow_any_instance_of(described_class).to receive(:ecs_compatibility).and_return(ecs_compatibility) |
| 26 | + plugin.register |
| 27 | + end |
| 28 | + |
| 29 | + context "with city database" do |
| 30 | + let(:options) { common_options } |
| 31 | + |
| 32 | + it "should return geo in target" do |
| 33 | + plugin.filter(event) |
| 34 | + |
| 35 | + expect( event.get ecs_select[disabled: "[#{target}][ip]", v1: "[#{target}][ip]"] ).to eq ip |
| 36 | + expect( event.get ecs_select[disabled: "[#{target}][country_code2]", v1: "[#{target}][geo][country_iso_code]"] ).to eq 'US' |
| 37 | + expect( event.get ecs_select[disabled: "[#{target}][country_name]", v1: "[#{target}][geo][country_name]"] ).to eq 'United States' |
| 38 | + expect( event.get ecs_select[disabled: "[#{target}][continent_code]", v1: "[#{target}][geo][continent_code]"] ).to eq 'NA' |
| 39 | + expect( event.get ecs_select[disabled: "[#{target}][location][lat]", v1: "[#{target}][geo][location][lat]"] ).to eq 37.751 |
| 40 | + expect( event.get ecs_select[disabled: "[#{target}][location][lon]", v1: "[#{target}][geo][location][lon]"] ).to eq -97.822 |
| 41 | + |
| 42 | + if ecs_select.active_mode == :disabled |
| 43 | + expect( event.get "[#{target}][country_code3]" ).to eq 'US' |
| 44 | + else |
| 45 | + expect( event.get "[#{target}][geo][country_code3]" ).to be_nil |
| 46 | + expect( event.get "[#{target}][country_code3]" ).to be_nil |
| 47 | + end |
| 48 | + end |
| 49 | + end |
| 50 | + |
| 51 | + |
| 52 | + context "with ASN database" do |
| 53 | + let(:options) { common_options.merge({"database" => ASNDB}) } |
| 54 | + |
| 55 | + it "should return geo in target" do |
| 56 | + plugin.filter(event) |
| 57 | + |
| 58 | + expect( event.get ecs_select[disabled: "[#{target}][ip]", v1: "[#{target}][ip]"] ).to eq ip |
| 59 | + expect( event.get ecs_select[disabled: "[#{target}][asn]", v1: "[#{target}][as][number]"] ).to eq 15169 |
| 60 | + expect( event.get ecs_select[disabled: "[#{target}][as_org]", v1: "[#{target}][as][organization][name]"] ).to eq "Google LLC" |
| 61 | + end |
| 62 | + end |
| 63 | + |
| 64 | + context "with customize fields" do |
| 65 | + let(:fields) { ["continent_name", "timezone"] } |
| 66 | + let(:options) { common_options.merge({"fields" => fields}) } |
| 67 | + |
| 68 | + it "should return fields" do |
| 69 | + plugin.filter(event) |
| 70 | + |
| 71 | + expect( event.get ecs_select[disabled: "[#{target}][ip]", v1: "[#{target}][ip]"] ).to be_nil |
| 72 | + expect( event.get ecs_select[disabled: "[#{target}][country_code2]", v1: "[#{target}][geo][country_iso_code]"] ).to be_nil |
| 73 | + expect( event.get ecs_select[disabled: "[#{target}][country_name]", v1: "[#{target}][geo][country_name]"] ).to be_nil |
| 74 | + expect( event.get ecs_select[disabled: "[#{target}][continent_code]", v1: "[#{target}][geo][continent_code]"] ).to be_nil |
| 75 | + expect( event.get ecs_select[disabled: "[#{target}][location][lat]", v1: "[#{target}][geo][location][lat]"] ).to be_nil |
| 76 | + expect( event.get ecs_select[disabled: "[#{target}][location][lon]", v1: "[#{target}][geo][location][lon]"] ).to be_nil |
| 77 | + |
| 78 | + expect( event.get ecs_select[disabled: "[#{target}][continent_name]", v1: "[#{target}][geo][continent_name]"] ).to eq "North America" |
| 79 | + expect( event.get ecs_select[disabled: "[#{target}][timezone]", v1: "[#{target}][geo][timezone]"] ).to eq "America/Chicago" |
| 80 | + end |
| 81 | + end |
| 82 | + |
| 83 | + end |
| 84 | + end |
| 85 | + |
| 86 | + context "setup target field" do |
| 87 | + let(:ip) { "8.8.8.8" } |
| 88 | + let(:event) { LogStash::Event.new("message" => ip) } |
| 89 | + let(:common_options) { {"source" => "message", "database" => CITYDB} } |
| 90 | + |
| 91 | + context "ECS disabled" do |
| 92 | + before do |
| 93 | + allow_any_instance_of(described_class).to receive(:ecs_compatibility).and_return(:disabled) |
| 94 | + plugin.register |
| 95 | + plugin.filter(event) |
| 96 | + end |
| 97 | + |
| 98 | + context "`target` is unset" do |
| 99 | + let(:options) { common_options } |
| 100 | + it "should use 'geoip'" do |
| 101 | + expect( event.get "[geoip][ip]" ).to eq ip |
| 102 | + end |
| 103 | + end |
| 104 | + |
| 105 | + context "`target` is set" do |
| 106 | + let(:target) { 'host' } |
| 107 | + let(:options) { common_options.merge({"target" => target}) } |
| 108 | + it "should use `target`" do |
| 109 | + expect( event.get "[#{target}][ip]" ).to eq ip |
| 110 | + end |
| 111 | + end |
| 112 | + end |
| 113 | + |
| 114 | + context "ECS mode" do |
| 115 | + before do |
| 116 | + allow_any_instance_of(described_class).to receive(:ecs_compatibility).and_return(:v1) |
| 117 | + end |
| 118 | + |
| 119 | + context "`target` is unset" do |
| 120 | + |
| 121 | + context "`source` end with [ip]" do |
| 122 | + let(:event) { LogStash::Event.new("host" => {"ip" => ip}) } |
| 123 | + let(:options) { common_options.merge({"source" => "[host][ip]"}) } |
| 124 | + |
| 125 | + it "should use source's parent as target" do |
| 126 | + plugin.register |
| 127 | + plugin.filter(event) |
| 128 | + expect( event.get "[host][geo][country_iso_code]" ).to eq 'US' |
| 129 | + end |
| 130 | + end |
| 131 | + |
| 132 | + context "`source` end with [ip] but `target` does not match ECS template" do |
| 133 | + let(:event) { LogStash::Event.new("hostname" => {"ip" => ip}) } |
| 134 | + let(:options) { common_options.merge({"source" => "[hostname][ip]"}) } |
| 135 | + |
| 136 | + it "should use source's parent as target with warning" do |
| 137 | + expect(plugin.logger).to receive(:warn).with(/ECS expect `target`/) |
| 138 | + plugin.register |
| 139 | + plugin.filter(event) |
| 140 | + expect( event.get "[hostname][geo][country_iso_code]" ).to eq 'US' |
| 141 | + end |
| 142 | + end |
| 143 | + |
| 144 | + context "`source` == [ip]" do |
| 145 | + let(:event) { LogStash::Event.new("ip" => ip) } |
| 146 | + let(:options) { common_options.merge({"source" => "[ip]"}) } |
| 147 | + |
| 148 | + it "should raise error to require `target`" do |
| 149 | + expect { plugin.register }.to raise_error LogStash::ConfigurationError, /requires a `target`/ |
| 150 | + end |
| 151 | + end |
| 152 | + |
| 153 | + context "`source` not end with [ip]" do |
| 154 | + let(:event) { LogStash::Event.new("host_ip" => ip) } |
| 155 | + let(:options) { common_options.merge({"source" => "host_ip"}) } |
| 156 | + |
| 157 | + it "should raise error to require `target`" do |
| 158 | + expect { plugin.register }.to raise_error LogStash::ConfigurationError, /requires a `target`/ |
| 159 | + end |
| 160 | + end |
| 161 | + end |
| 162 | + |
| 163 | + context "`target` is set" do |
| 164 | + let(:event) { LogStash::Event.new("client" => {"ip" => ip}) } |
| 165 | + let(:options) { common_options.merge({"source" => "[client][ip]", "target" => target}) } |
| 166 | + |
| 167 | + context "`target` matches ECS template" do |
| 168 | + let(:target) { 'host' } |
| 169 | + |
| 170 | + it "should use `target`" do |
| 171 | + plugin.register |
| 172 | + plugin.filter(event) |
| 173 | + expect( event.get "[#{target}][geo][country_iso_code]" ).to eq 'US' |
| 174 | + end |
| 175 | + end |
| 176 | + |
| 177 | + context "`target` in canonical field reference syntax matches ECS template" do |
| 178 | + let(:target) { '[host]' } |
| 179 | + |
| 180 | + it "should normalize and use `target`" do |
| 181 | + expect(plugin.logger).to receive(:warn).never |
| 182 | + plugin.register |
| 183 | + plugin.filter(event) |
| 184 | + expect( event.get "[host][geo][country_iso_code]" ).to eq 'US' |
| 185 | + end |
| 186 | + end |
| 187 | + |
| 188 | + context "`target` does not match ECS template" do |
| 189 | + let(:target) { 'host_ip' } |
| 190 | + |
| 191 | + it "should use `target` with warning" do |
| 192 | + expect(plugin.logger).to receive(:warn).with(/ECS expect `target`/) |
| 193 | + plugin.register |
| 194 | + plugin.filter(event) |
| 195 | + expect( event.get "[#{target}][geo][country_iso_code]" ).to eq 'US' |
| 196 | + end |
| 197 | + end |
| 198 | + end |
| 199 | + end |
| 200 | + end |
| 201 | + |
| 202 | + end |
| 203 | +end |
0 commit comments