diff --git a/lib/pact/provider/pact_spec_runner.rb b/lib/pact/provider/pact_spec_runner.rb index cc7e50a9..f0107f06 100644 --- a/lib/pact/provider/pact_spec_runner.rb +++ b/lib/pact/provider/pact_spec_runner.rb @@ -12,6 +12,7 @@ require 'pact/provider/rspec/json_formatter' require 'pact/provider/rspec' require 'pact/provider/rspec/calculate_exit_code' +require 'pact/utils/metrics' module Pact module Provider @@ -130,6 +131,8 @@ def initialize_specs ignore_failures: options[:ignore_failures], request_customizer: options[:request_customizer] } + Pact::Utils::Metrics.report_metric("Pacts verified", "ProviderTest", "Completed") + honour_pactfile pact_source, ordered_pact_json(pact_source.pact_json), spec_options end end diff --git a/lib/pact/utils/metrics.rb b/lib/pact/utils/metrics.rb new file mode 100644 index 00000000..1d86d032 --- /dev/null +++ b/lib/pact/utils/metrics.rb @@ -0,0 +1,85 @@ +require 'securerandom' +require 'digest' +require 'socket' +require 'pact/version' +require 'net/http' + +module Pact + module Utils + class Metrics + + def self.report_metric(event, category, action, value = 1) + in_thread do + begin + if track_events? + Pact.configuration.output_stream.puts "WARN: Please note: we are tracking events anonymously to gather important usage statistics like Pact-Ruby version + and operating system. To disable tracking, set the 'PACT_DO_NOT_TRACK' environment + variable to 'true'." + + uri = URI('https://www.google-analytics.com/collect') + req = Net::HTTP::Post.new(uri) + req.set_form_data(create_tracking_event(event, category, action, value)) + + Net::HTTP.start(uri.hostname, uri.port, read_timeout:2, open_timeout:2, :use_ssl => true ) do |http| + http.request(req) + end + end + rescue StandardError => e + handle_error(e) + end + end + end + + private + def self.handle_error e + if ENV['PACT_METRICS_DEBUG'] == 'true' + Pact.configuration.output_stream.puts("DEBUG: #{e.inspect}\n" + e.backtrace.join("\n")) + end + end + + def self.in_thread + Thread.new do + yield + end + end + + def self.create_tracking_event(event, category, action, value) + { + "v" => 1, + "t" => "event", + "tid" => "UA-117778936-1", + "cid" => calculate_cid, + "an" => "Pact Ruby", + "av" => Pact::VERSION, + "aid" => "pact-ruby", + "aip" => 1, + "ds" => ENV['PACT_EXECUTING_LANGUAGE'] ? "client" : "cli", + "cd2" => ENV['CI'] == "true" ? "CI" : "unknown", + "cd3" => RUBY_PLATFORM, + "cd6" => ENV['PACT_EXECUTING_LANGUAGE'] || "unknown", + "cd7" => ENV['PACT_EXECUTING_LANGUAGE_VERSION'], + "el" => event, + "ec" => category, + "ea" => action, + "ev" => value + } + end + + def self.track_events? + ENV['PACT_DO_NOT_TRACK'] != 'true' + end + + def self.calculate_cid + if RUBY_PLATFORM.include? "windows" + hostname = ENV['COMPUTERNAME'] + else + hostname = ENV['HOSTNAME'] + end + if !hostname + hostname = Socket.gethostname + end + Digest::MD5.hexdigest hostname || SecureRandom.urlsafe_base64(5) + end + end + end +end diff --git a/spec/lib/pact/provider/pact_spec_runner_spec.rb b/spec/lib/pact/provider/pact_spec_runner_spec.rb index 09f57f84..9a8cbacb 100644 --- a/spec/lib/pact/provider/pact_spec_runner_spec.rb +++ b/spec/lib/pact/provider/pact_spec_runner_spec.rb @@ -44,6 +44,7 @@ end allow(subject).to receive(:configure_rspec) allow(subject).to receive(:run_specs) + allow(Pact::Utils::Metrics).to receive(:report_metric) expect(Pact::Provider::PactSource).to receive(:new).with(pact_url).and_return(pact_source) end @@ -62,6 +63,13 @@ subject.run end + it 'reports pacts verified metric' do + allow(subject).to receive(:honour_pactfile).and_return([]) + + expect(Pact::Utils::Metrics).to receive(:report_metric).with("Pacts verified", "ProviderTest", "Completed") + subject.run + end + context 'and interactions_replay_order option set to random' do let(:interactions_replay_order) { :random } @@ -82,6 +90,5 @@ end end end - end end diff --git a/spec/pact/utils/metrics_spec.rb b/spec/pact/utils/metrics_spec.rb new file mode 100644 index 00000000..bee9f334 --- /dev/null +++ b/spec/pact/utils/metrics_spec.rb @@ -0,0 +1,51 @@ +require 'rspec' +require 'pact/utils/metrics' + +describe Pact::Utils::Metrics do + + before do + stub_request(:post, "https://www.google-analytics.com/collect").to_return(status: 200, body: "", headers: {}) + ENV['COMPUTERNAME'] = 'test' + ENV['HOSTNAME'] = 'test' + end + + describe ".report_metric" do + subject { Pact::Utils::Metrics.report_metric("Event", "Category", "Action", "Value") } + context 'when do not track is not set' do + let(:expected_event) { { + "v" => 1, + "t" => "event", + "tid" => "UA-117778936-1", + "cid" => "098f6bcd4621d373cade4e832627b4f6", + "an" => "Pact Ruby", + "av" => Pact::VERSION, + "aid" => "pact-ruby", + "aip" => 1, + "ds" => ENV['PACT_EXECUTING_LANGUAGE'] ? "client" : "cli", + "cd2" => ENV['CI'] == "true" ? "CI" : "unknown", + "cd3" => RUBY_PLATFORM, + "cd6" => ENV['PACT_EXECUTING_LANGUAGE'] || "unknown", + "cd7" => ENV['PACT_EXECUTING_LANGUAGE_VERSION'], + "el" => "Event", + "ec" => "Category", + "ea" => "Action", + "ev" => "Value" + } } + + it 'sends metrics' do + expect_any_instance_of(Net::HTTP::Post).to receive(:set_form_data).with(expected_event) + expect(Net::HTTP).to receive(:start) + subject + end + end + context 'when do not track is set to true' do + before do + ENV['PACT_DO_NOT_TRACK'] = "true" + end + it 'does not send metrics' do + expect(Net::HTTP).to_not receive(:post) + subject + end + end + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 9800ca85..56256da5 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -7,7 +7,7 @@ require 'support/spec_support' require 'pact/provider/rspec' -WebMock.disable_net_connect!(allow_localhost: true) +WebMock.disable_net_connect!(allow_localhost: true, allow: 'https://www.google-analytics.com') require './spec/support/active_support_if_configured' require './spec/support/warning_silencer'