diff --git a/lib/stoplight.rb b/lib/stoplight.rb index 818f4609..ace8493f 100644 --- a/lib/stoplight.rb +++ b/lib/stoplight.rb @@ -26,6 +26,7 @@ module Stoplight # rubocop:disable Style/Documentation require 'stoplight/notifier/logger' require 'stoplight/notifier/raven' require 'stoplight/notifier/slack' +require 'stoplight/notifier/data_dog_service_check' require 'stoplight/default' diff --git a/lib/stoplight/notifier/data_dog_service_check.rb b/lib/stoplight/notifier/data_dog_service_check.rb new file mode 100644 index 00000000..b7bef896 --- /dev/null +++ b/lib/stoplight/notifier/data_dog_service_check.rb @@ -0,0 +1,61 @@ +# coding: utf-8 + +module Stoplight + module Notifier + # @see Base + class DataDogServiceCheck < Base + DEFAULT_OPTIONS = { + timestamp: Time.now, + tags: {} + }.freeze + + # @return [Proc] + attr_reader :formatter + # @return [::Dogapi::Client] + attr_reader :dogapi + # @return[Hash{Symbol => Object}] + attr_reader :options + # @return [String] + attr_reader :prefix + # @return [String] + attr_reader :host + + # @param dogapi [::Dogapi::Client] + # @param prefix [String] + # @param host [String] + # @param formatter [Proc, nil] + # @param options [Hash{Symbol => Object}] + # @option options [Time] :timestamp + # @option options [Hash] :tags + def initialize(dogapi, host, prefix, formatter = nil, options = {}) + @dogapi = dogapi + @host = host + @prefix = prefix + @formatter = formatter || Default::FORMATTER + @options = DEFAULT_OPTIONS.merge(options) + end + + def notify(light, from_color, to_color, error) + message = formatter.call(light, from_color, to_color, error) + opts = options.merge( + message: message, + timestamp: options[:timestamp].to_i + ) + dogapi.service_check(check(light), host, get_status(light.color), opts) + message + end + + def check(light) + prefix.gsub(/\.$/, '') + '.' + light.name + end + + def get_status(color) + case color + when Color::GREEN then 0 + when Color::RED then 2 + else 1 + end + end + end + end +end diff --git a/spec/stoplight/notifier/data_dog_service_check_spec.rb b/spec/stoplight/notifier/data_dog_service_check_spec.rb new file mode 100644 index 00000000..d3e0979f --- /dev/null +++ b/spec/stoplight/notifier/data_dog_service_check_spec.rb @@ -0,0 +1,139 @@ +# coding: utf-8 + +require 'spec_helper' + +# require 'dogapi' +module Dogapi + class Client + def initialize(*) + end + end +end + +RSpec.describe Stoplight::Notifier::DataDogServiceCheck do + prefix = 'stoplight' + host = 'myhostname' + it 'is a class' do + expect(described_class).to be_a(Class) + end + + it 'is a subclass of Base' do + expect(described_class).to be < Stoplight::Notifier::Base + end + + describe '#formatter' do + it 'is initially the default' do + expect(described_class.new(nil, host, prefix).formatter).to eql( + Stoplight::Default::FORMATTER + ) + end + + it 'reads the formatter' do + formatter = proc {} + expect(described_class + .new(nil, host, prefix, formatter).formatter) + .to eql(formatter) + end + end + + describe '#options' do + it 'is intiially the default' do + expect(described_class.new(nil, host, prefix).options).to eql( + Stoplight::Notifier::DataDogServiceCheck::DEFAULT_OPTIONS + ) + end + + it 'reads the options' do + options = { key: :value } + expect(described_class + .new(nil, host, prefix, nil, options).options) + .to eql( + Stoplight::Notifier::DataDogServiceCheck::DEFAULT_OPTIONS + .merge(options) + ) + end + end + + describe '#dogapi' do + it 'reads the Dogapi client' do + dogapi = Dogapi::Client.new('API token') + expect(described_class.new(dogapi, host, prefix).dogapi) + .to eql(dogapi) + end + end + + describe '#host' do + it 'reads the host' do + expect(described_class.new(nil, host, prefix).host).to eql(host) + end + end + + describe '#prefix' do + it 'reads the prefix' do + expect(described_class.new(nil, host, prefix).prefix).to eql(prefix) + end + end + + describe '#check' do + let(:light) { Stoplight::Light.new(name, &code) } + let(:name) { ('a'..'z').to_a.shuffle.join } + let(:code) { -> {} } + let(:notifier) { described_class.new(nil, host, prefix) } + + it 'returns the prefix combined with the stoplight name' do + expect(notifier.check(light)).to eql(prefix + '.' + name) + end + end + + describe '#get_status' do + let(:light) { Stoplight::Light.new(name, &code) } + let(:name) { ('a'..'z').to_a.shuffle.join } + let(:code) { -> {} } + let(:notifier) { described_class.new(nil, host, prefix) } + + it 'returns 0 for a working stoplight' do + expect(notifier.get_status(light.color)).to eql(0) + end + + context 'when the stoplight is yellow' do + it 'returns 1' do + expect(notifier.get_status('yellow')).to eql(1) + end + end + + context 'when the stoplight is red' do + let(:light) { Stoplight::Light.new(name, &code).with_threshold(0) } + let(:code) { -> { 0 / 0 } } + it 'returns 2' do + expect(notifier.get_status(light.color)).to eql(2) + end + end + end + + describe '#notify' do + let(:light) { Stoplight::Light.new(name, &code) } + let(:name) { ('a'..'z').to_a.shuffle.join } + let(:code) { -> {} } + let(:from_color) { Stoplight::Color::GREEN } + let(:to_color) { Stoplight::Color::RED } + let(:notifier) { described_class.new(dogapi, host, prefix) } + let(:dogapi) { double(Dogapi::Client) } + let(:api_key) { ('a'..'z').to_a.shuffle.join } + + before do + allow(dogapi).to receive(:service_check) + end + + it 'returns the message' do + error = nil + expect(notifier.notify(light, from_color, to_color, error)) + .to eql(notifier.formatter.call(light, from_color, to_color, error)) + end + + it 'returns the message with an error' do + error = ZeroDivisionError.new('divide by 0') + expect(notifier.notify(light, from_color, to_color, error)) + .to eql(notifier.formatter.call(light, from_color, to_color, error)) + end + end +end diff --git a/stoplight.gemspec b/stoplight.gemspec index b9bf14be..59324c40 100644 --- a/stoplight.gemspec +++ b/stoplight.gemspec @@ -38,6 +38,7 @@ Gem::Specification.new do |gem| 'fakeredis' => '0.5', 'hipchat' => '1.5', 'honeybadger' => '2.5', + 'dogapi' => '1.25.0', 'sentry-raven' => '1.2', 'rake' => '11.1', 'redis' => '3.2',