victor_ops-client 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ef7b0ede3d1b7572df728e8824d3999c05391f1b
4
+ data.tar.gz: 37c171cd2e582019d437e5dfdf09c4932dab4fed
5
+ SHA512:
6
+ metadata.gz: 7947fbdd8c0ecc7d81206aacee0fb41464525b34c858e8562fd4663b26f98cc808c4c3757397703e0c1fd8ea75512f6500dd4aeb7f4efd938544d018c19a9102
7
+ data.tar.gz: 2b218795188a34caea06f4a0332f063ea030ddecb1a2ff2d67e9a337b062e1b00b6fcc57584fcec5e96cdec32a7f587fb3166ed7b34e07e1f67086a39f4131de
@@ -0,0 +1,35 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /test/tmp/
9
+ /test/version_tmp/
10
+ /tmp/
11
+
12
+ ## Specific to RubyMotion:
13
+ .dat*
14
+ .repl_history
15
+ build/
16
+
17
+ ## Documentation cache and generated files:
18
+ /.yardoc/
19
+ /_yardoc/
20
+ /doc/
21
+ /rdoc/
22
+
23
+ ## Environment normalisation:
24
+ /.bundle/
25
+ /vendor/bundle
26
+ /lib/bundler/man/
27
+
28
+ # for a library or gem, you might want to ignore these files since the code is
29
+ # intended to run in multiple environments; otherwise, check them in:
30
+ Gemfile.lock
31
+ .ruby-version
32
+ .ruby-gemset
33
+
34
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
35
+ .rvmrc
@@ -0,0 +1,9 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.0
4
+ - 2.1.0
5
+ - 2.0.0
6
+ - 1.9.3
7
+ addons:
8
+ code_climate:
9
+ repo_token: 86322de3b5909460dccb9d35d43d90178899a4887fefc28b2bf6ac5818708918
data/Gemfile ADDED
@@ -0,0 +1,13 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
3
+
4
+ gem 'rake'
5
+ gem 'rest-client'
6
+ gem 'awesome_print'
7
+ gem 'daybreak'
8
+
9
+ group :test do
10
+ gem 'rspec', '~> 3.1'
11
+ gem 'simplecov', require: false
12
+ gem 'codeclimate-test-reporter', require: false
13
+ end
data/History ADDED
@@ -0,0 +1,20 @@
1
+ == 0.3.0 2015-04-09
2
+
3
+ * refactored payload generation
4
+
5
+ == 0.2.1 2015-04-08
6
+
7
+ * minor change to default naming
8
+
9
+ == 0.2.0 2015-04-08
10
+
11
+ * added persistence layer
12
+ * ability to track and update incidents between Client runs
13
+
14
+ == 0.1.0 2015-04-04
15
+
16
+ * Initial deployment
17
+
18
+ == 0.0.1 2015-04-03
19
+
20
+ * Initial development
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) [year] [fullname]
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,60 @@
1
+ [![Gem Version](https://img.shields.io/gem/v/victor_ops-client.svg)](https://rubygems.org/gems/victor_ops-client)
2
+ [![Build Status](https://travis-ci.org/clok/victor-ops-client.svg?branch=master)](https://travis-ci.org/clok/victor-ops-client)
3
+ [![Code Climate](https://codeclimate.com/github/clok/victor-ops-client/badges/gpa.svg)](https://codeclimate.com/github/clok/victor-ops-client)
4
+ [![Test Coverage](https://codeclimate.com/github/clok/victor-ops-client/badges/coverage.svg)](https://codeclimate.com/github/clok/victor-ops-client)
5
+
6
+ VictorOps Ruby Client
7
+ ---
8
+
9
+ A simple REST API client for use with the [VictorOps REST API](http://victorops.force.com/knowledgebase/articles/Integration/Alert-Ingestion-API-Documentation/)
10
+
11
+ # Install
12
+
13
+ ```
14
+ gem install victor_ops-client
15
+ ```
16
+
17
+ ## Requirements
18
+
19
+ - Ruby 1.9.3 or higher
20
+ - `rest-client` & `awesome_print`
21
+ - VictorOps API Access
22
+
23
+ ## Example
24
+
25
+ ``` ruby
26
+ $:.unshift(File.join(File.dirname(__FILE__), "/../lib"))
27
+ require 'victor_ops/client'
28
+
29
+ # Required for Initializing Client
30
+ API_URL = 'https://alert.victorops.com/REST_END_POINT/API_KEY'
31
+ ROUTING_KEY = 'example_routing_key'
32
+
33
+ client = VictorOps::Client.new api_url: API_URL, routing_key: ROUTING_KEY
34
+
35
+ # Send a CRITICAL alert
36
+ client.critical 'THE DISK IS FULL!!!'
37
+
38
+ # Send a WARNING alert
39
+ client.warn desc: 'Disk is nearing capacity', stats: `df -h`
40
+
41
+ # Send an INFO alert
42
+ client.info [ 'this', 'is', 'an', 'array' ]
43
+
44
+ # Send an ACKNOWLEDGMENT
45
+ client.ack 'bot ack'
46
+
47
+ # Send a RECOVERY
48
+ client.recovery desc: 'Disk has space', emoji: ':saiyan:'
49
+ ```
50
+
51
+ ## Contributing
52
+
53
+ * Fork the project.
54
+ * Run `bundle install`
55
+ * Run `bundle exec rake`
56
+ * Make your feature addition or bug fix.
57
+ * Add tests for it. This is important so I don't break it in a future version unintentionally.
58
+ * Run `bundle exec rake` (No, REALLY :))
59
+ * Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself in another branch so I can ignore when I pull)
60
+ * Send me a pull request. Bonus points for topic branches.
@@ -0,0 +1,9 @@
1
+ ENV['CODECLIMATE_REPO_TOKEN'] = '86322de3b5909460dccb9d35d43d90178899a4887fefc28b2bf6ac5818708918'
2
+
3
+ begin
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new(:spec)
6
+ rescue LoadError
7
+ end
8
+
9
+ task default: [:spec]
File without changes
@@ -0,0 +1,25 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ $:.unshift(File.join(File.dirname(__FILE__), "/../lib"))
4
+ require 'victor_ops/client'
5
+
6
+ # Required for Initializing Client
7
+ API_URL = 'INSERT_URL_HERE'
8
+ ROUTING_KEY = 'INSERT_ROUTING_KEY_HERE'
9
+
10
+ client = VictorOps::Client.new api_url: API_URL, routing_key: ROUTING_KEY
11
+
12
+ # Send a CRITICAL alert
13
+ client.critical 'THE DISK IS FULL!!!'
14
+
15
+ # Send a WARNING alert
16
+ client.warn desc: 'Disk is nearing capacity', stats: `df -h`
17
+
18
+ # Send an INFO alert
19
+ client.info [ 'this', 'is', 'an', 'array' ]
20
+
21
+ # Send an ACKNOWLEDGMENT
22
+ client.ack 'bot ack'
23
+
24
+ # Send a RECOVERY
25
+ client.recovery desc: 'Disk has space', emoji: ':saiyan:'
@@ -0,0 +1,155 @@
1
+ require 'victor_ops/defaults'
2
+ require 'victor_ops/client/version'
3
+ require 'victor_ops/client/exceptions'
4
+ require 'victor_ops/client/persistence'
5
+
6
+ module VictorOps
7
+ class Client
8
+ require 'ostruct'
9
+ require 'awesome_print'
10
+ require 'json'
11
+ require 'rest-client'
12
+
13
+ attr_accessor :settings
14
+
15
+ def initialize(opts)
16
+ @settings = OpenStruct.new opts
17
+ AwesomePrint.defaults = { indent: -2, plain: true }
18
+ set_default_settings
19
+ configure_data_store unless settings.persist.nil?
20
+ raise VictorOps::Client::MissingSettings unless valid_settings?
21
+ end
22
+
23
+ def entity_display_name
24
+ if settings.entity_display_name.nil?
25
+ "#{settings.host}/#{settings.name}"
26
+ else
27
+ settings.entity_display_name
28
+ end
29
+ end
30
+
31
+ def entity_display_name=(str)
32
+ settings.entity_display_name = str
33
+ end
34
+
35
+ def monitoring_tool
36
+ if settings.monitoring_tool.nil?
37
+ "#{settings.routing_key}::#{settings.name}"
38
+ else
39
+ settings.monitoring_tool
40
+ end
41
+ end
42
+
43
+ def monitoring_tool=(str)
44
+ settings.monitoring_tool = str
45
+ end
46
+
47
+ def critical(data)
48
+ post critical_payload(data)
49
+ end
50
+
51
+ def warn(data)
52
+ post warn_payload(data)
53
+ end
54
+
55
+ def info(data)
56
+ post info_payload(data)
57
+ end
58
+
59
+ def ack(data)
60
+ post ack_payload(data)
61
+ end
62
+
63
+ def recovery(data)
64
+ post recovery_payload(data)
65
+ end
66
+
67
+ private
68
+
69
+ def epochtime
70
+ Time.now.to_i
71
+ end
72
+
73
+ def set_default_settings
74
+ settings.host = VictorOps::Defaults::HOST if settings.host.nil?
75
+ settings.name = VictorOps::Defaults::NAME if settings.name.nil?
76
+ end
77
+
78
+ def endpoint
79
+ "#{settings.api_url}/#{settings.routing_key}"
80
+ end
81
+
82
+ def post(payload)
83
+ resp = nil
84
+ begin
85
+ json = RestClient.post endpoint, payload.to_json
86
+ resp = JSON::parse(json)
87
+ raise VictorOps::Client::PostFailure, "Response from VictorOps contains a failure message: #{resp.ai}" if resp['result'] == 'failure'
88
+ rescue Exception => e
89
+ raise VictorOps::Client::PostFailure, "Error posting to VictorOps: #{e}"
90
+ end
91
+ resp
92
+ end
93
+
94
+ def generate_payload(data)
95
+ if data.nil? || data[:vo_alert_type].nil?
96
+ raise VictorOps::Client::MissingMessageType
97
+ end
98
+ payload = {
99
+ message_type: data.delete(:vo_alert_type),
100
+ state_start_time: epochtime,
101
+ entity_display_name: entity_display_name,
102
+ monitoring_tool: monitoring_tool,
103
+ }
104
+ payload.merge! data
105
+ payload.delete_if { |k,v| v.nil? }
106
+ end
107
+
108
+ def critical_payload(data)
109
+ generate_payload data.merge({
110
+ vo_alert_type: VictorOps::Defaults::MessageTypes::CRITICAL,
111
+ state_message: data[:message].nil? ? nil : data.delete(:message).ai
112
+ })
113
+ end
114
+
115
+ def warn_payload(data)
116
+ generate_payload data.merge({
117
+ vo_alert_type: VictorOps::Defaults::MessageTypes::WARN,
118
+ state_message: data[:message].nil? ? nil : data.delete(:message).ai
119
+ })
120
+ end
121
+
122
+ def info_payload(data)
123
+ generate_payload data.merge({
124
+ vo_alert_type: VictorOps::Defaults::MessageTypes::INFO,
125
+ state_message: data[:message].nil? ? nil : data.delete(:message).ai
126
+ })
127
+ end
128
+
129
+ def ack_payload(data)
130
+ generate_payload data.merge({
131
+ vo_alert_type: VictorOps::Defaults::MessageTypes::ACK,
132
+ ack_msg: data[:message].nil? ? nil : data.delete(:message).ai,
133
+ ack_author: data[:author].nil? ? monitoring_tool : data.delete(:author)
134
+ })
135
+ end
136
+
137
+ def recovery_payload(data)
138
+ generate_payload data.merge({
139
+ vo_alert_type: VictorOps::Defaults::MessageTypes::RECOVERY,
140
+ state_message: data[:message].nil? ? nil : data.delete(:message).ai
141
+ })
142
+ end
143
+
144
+ def valid_settings?
145
+ valid = true
146
+ [:api_url, :routing_key].each do |k|
147
+ next if valid == false
148
+ valid = false unless settings.send(k)
149
+ end
150
+ settings.api_url.chop! if settings.api_url =~ /\/$/
151
+ valid
152
+ end
153
+
154
+ end
155
+ end
@@ -0,0 +1,15 @@
1
+ module VictorOps
2
+ class Client
3
+
4
+ class Error < StandardError; end
5
+
6
+ class MissingSettings < Error; end
7
+
8
+ class PostFailure < Error; end
9
+
10
+ class MissingMessageType < Error; end
11
+
12
+ class NotYetImplemented < Error; end
13
+
14
+ end
15
+ end
@@ -0,0 +1,31 @@
1
+ module VictorOps
2
+ class Client
3
+ require 'daybreak'
4
+
5
+ attr_accessor :db
6
+
7
+ def configure_data_store
8
+ settings.store_file = VictorOps::Defaults::Daybreak::PATH unless settings.store_file
9
+ @db = Daybreak::DB.new settings.store_file
10
+ ObjectSpace.define_finalizer(self, proc { shutdown })
11
+ end
12
+
13
+ def set(key, value)
14
+ db.set! key, value
15
+ end
16
+
17
+ def retrieve(key)
18
+ db[key]
19
+ end
20
+
21
+ def delete(key)
22
+ db.delete! key
23
+ end
24
+
25
+ def shutdown
26
+ db.flush
27
+ db.compact
28
+ db.close
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,5 @@
1
+ module VictorOps
2
+ class Client
3
+ VERSION = '0.3.0'
4
+ end
5
+ end
@@ -0,0 +1,18 @@
1
+ module VictorOps
2
+ module Defaults
3
+ HOST = 'localhost'
4
+ NAME = 'ruby REST client'
5
+
6
+ module MessageTypes
7
+ INFO = 'INFO'
8
+ WARN = 'WARNING'
9
+ ACK = 'ACKNOWLEDGEMENT'
10
+ CRITICAL = 'CRITICAL'
11
+ RECOVERY = 'RECOVERY'
12
+ end
13
+
14
+ module Daybreak
15
+ PATH = '/tmp/victor_ops-client.db'
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,407 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
2
+
3
+ RSpec.describe VictorOps::Client do
4
+ before do
5
+ @valid_params = { api_url: 'test url', routing_key: 'test key' }
6
+ end
7
+
8
+ describe 'settings' do
9
+ before do
10
+ @client = VictorOps::Client.new @valid_params.merge(option: 'this is working')
11
+ end
12
+
13
+ it 'should return an OpenStruct hash with the input options hash as settings methods' do
14
+ expect(@client.settings).to be_a(OpenStruct)
15
+ expect(@client.settings.api_url).to eq 'test url'
16
+ expect(@client.settings.routing_key).to eq 'test key'
17
+ expect(@client.settings.option).to eq 'this is working'
18
+ expect(@client.settings.not_a_passed_option).to be_nil
19
+ end
20
+ end
21
+
22
+ describe '.monitoring_tool' do
23
+ context 'a parameter is provided on initialization' do
24
+ before do
25
+ @client = VictorOps::Client.new @valid_params.merge(monitoring_tool: 'monitorting tool')
26
+ end
27
+
28
+ it 'should return the passed in name' do
29
+ expect(@client.monitoring_tool).to eq 'monitorting tool'
30
+ end
31
+ end
32
+
33
+ context 'default initialization' do
34
+ before do
35
+ @client = VictorOps::Client.new @valid_params
36
+ end
37
+
38
+ it 'should return the default name' do
39
+ expect(@client.monitoring_tool).to eq 'test key::ruby REST client'
40
+ end
41
+ end
42
+ end
43
+
44
+ describe '.monitoring_tool=' do
45
+ it 'should set the entity_display_name name' do
46
+ @client = VictorOps::Client.new @valid_params
47
+ @client.monitoring_tool = 'cool name bro'
48
+ expect(@client.monitoring_tool).to eq 'cool name bro'
49
+ end
50
+ end
51
+
52
+ describe '.entity_display_name' do
53
+ context 'a parameter is provided on initialization' do
54
+ before do
55
+ @client = VictorOps::Client.new @valid_params.merge(entity_display_name: 'super cool tool')
56
+ end
57
+
58
+ it 'should return the passed in nanme' do
59
+ expect(@client.entity_display_name).to eq 'super cool tool'
60
+ end
61
+ end
62
+
63
+ context 'default initialization' do
64
+ before do
65
+ @client = VictorOps::Client.new @valid_params
66
+ end
67
+
68
+ it 'should return the default name' do
69
+ expect(@client.entity_display_name).to eq 'localhost/ruby REST client'
70
+ end
71
+ end
72
+ end
73
+
74
+ describe '.entity_display_name=' do
75
+ it 'should set the entity_display_name' do
76
+ @client = VictorOps::Client.new @valid_params
77
+ @client.entity_display_name = 'cool name bro'
78
+ expect(@client.entity_display_name).to eq 'cool name bro'
79
+ end
80
+ end
81
+
82
+ describe '.critical' do
83
+ before do
84
+ @client = VictorOps::Client.new api_url: 'http://victorops.com', routing_key: '1234'
85
+ allow(@client).to receive(:post).and_return(file_fixture_to_json('victor_ops_success.json'))
86
+ end
87
+
88
+ it 'should resturn the result of the post to VictorOps' do
89
+ resp = @client.critical(message: 'test')
90
+ expect(resp).to be_a(Hash)
91
+ expect(resp['result']).to eq 'success'
92
+ end
93
+ end
94
+
95
+ describe '.warn' do
96
+ before do
97
+ @client = VictorOps::Client.new api_url: 'http://victorops.com', routing_key: '1234'
98
+ allow(@client).to receive(:post).and_return(file_fixture_to_json('victor_ops_success.json'))
99
+ end
100
+
101
+ it 'should resturn the result of the post to VictorOps' do
102
+ resp = @client.warn(message: 'test')
103
+ expect(resp).to be_a(Hash)
104
+ expect(resp['result']).to eq 'success'
105
+ end
106
+ end
107
+
108
+ describe '.info' do
109
+ before do
110
+ @client = VictorOps::Client.new api_url: 'http://victorops.com', routing_key: '1234'
111
+ allow(@client).to receive(:post).and_return(file_fixture_to_json('victor_ops_success.json'))
112
+ end
113
+
114
+ it 'should resturn the result of the post to VictorOps' do
115
+ resp = @client.info(message: 'test')
116
+ expect(resp).to be_a(Hash)
117
+ expect(resp['result']).to eq 'success'
118
+ end
119
+ end
120
+
121
+ describe '.ack' do
122
+ before do
123
+ @client = VictorOps::Client.new api_url: 'http://victorops.com', routing_key: '1234'
124
+ allow(@client).to receive(:post).and_return(file_fixture_to_json('victor_ops_success.json'))
125
+ end
126
+
127
+ it 'should resturn the result of the post to VictorOps' do
128
+ resp = @client.ack(message: 'test')
129
+ expect(resp).to be_a(Hash)
130
+ expect(resp['result']).to eq 'success'
131
+ end
132
+ end
133
+
134
+ describe '.recovery' do
135
+ before do
136
+ @client = VictorOps::Client.new api_url: 'http://victorops.com', routing_key: '1234'
137
+ allow(@client).to receive(:post).and_return(file_fixture_to_json('victor_ops_success.json'))
138
+ end
139
+
140
+ it 'should resturn the result of the post to VictorOps' do
141
+ resp = @client.recovery(message: 'test')
142
+ expect(resp).to be_a(Hash)
143
+ expect(resp['result']).to eq 'success'
144
+ end
145
+ end
146
+
147
+ context 'private methods' do
148
+ describe '.valid_settings?' do
149
+ context 'settings include required items' do
150
+ before do
151
+ @client = VictorOps::Client.new @valid_params
152
+ end
153
+
154
+ it 'should return true' do
155
+ expect(@client.send(:valid_settings?)).to be_truthy
156
+ end
157
+ end
158
+
159
+ context 'the api url has a slash at the end' do
160
+ before do
161
+ @client = VictorOps::Client.new api_url: 'slashy/url/', routing_key: 'test key'
162
+ end
163
+
164
+ it 'should return true' do
165
+ expect(@client.send(:valid_settings?)).to be_truthy
166
+ expect(@client.settings.api_url).to_not end_with('/')
167
+ expect(@client.settings.api_url).to eq 'slashy/url'
168
+ end
169
+ end
170
+
171
+ context 'the api url has no slash at the end' do
172
+ before do
173
+ @client = VictorOps::Client.new api_url: 'no/slashy/url', routing_key: 'test key'
174
+ end
175
+
176
+ it 'should return true' do
177
+ expect(@client.send(:valid_settings?)).to be_truthy
178
+ expect(@client.settings.api_url).to_not end_with('/')
179
+ expect(@client.settings.api_url).to eq 'no/slashy/url'
180
+ end
181
+ end
182
+
183
+ context 'settings do not include required items' do
184
+ before do
185
+ @client = VictorOps::Client.new @valid_params
186
+ @client.settings.routing_key = nil
187
+ end
188
+
189
+ it 'should return false' do
190
+ expect(@client.send(:valid_settings?)).to be_falsey
191
+ end
192
+ end
193
+ end
194
+
195
+ describe '.generate_payload' do
196
+ before do
197
+ @client = VictorOps::Client.new api_url: 'http://victorops.com', routing_key: '1234'
198
+ end
199
+
200
+ context 'a nil hash was passed in' do
201
+ it 'should raise an expetion for no message_type provided' do
202
+ expect { @client.send(:generate_payload, nil) }.to raise_exception(VictorOps::Client::MissingMessageType)
203
+ end
204
+ end
205
+
206
+ context 'a hash without required message_type' do
207
+ it 'should raise an expetion for no message_type provided' do
208
+ expect { @client.send(:generate_payload, {stuff: 'test'}) }.to raise_exception(VictorOps::Client::MissingMessageType)
209
+ end
210
+ end
211
+
212
+ context 'a properly formed hash is passed in' do
213
+ it 'should return a payload hash' do
214
+ payload = @client.send(:generate_payload, {vo_alert_type: 'TEST'})
215
+ expect(payload[:message_type]).to eq 'TEST'
216
+ expect(payload[:state_start_time]).to be_a(Fixnum)
217
+ expect(payload[:entity_display_name]).to be_a(String)
218
+ expect(payload[:monitoring_tool]).to be_a(String)
219
+ end
220
+ end
221
+
222
+ context 'a properly formed hash is passed in with extra variables' do
223
+ it 'should return a payload hash' do
224
+ payload = @client.send(:generate_payload, {vo_alert_type: 'TEST', special_var: 'i am special'})
225
+ expect(payload[:message_type]).to eq 'TEST'
226
+ expect(payload[:special_var]).to eq 'i am special'
227
+ expect(payload[:state_start_time]).to be_a(Fixnum)
228
+ expect(payload[:entity_display_name]).to be_a(String)
229
+ expect(payload[:monitoring_tool]).to be_a(String)
230
+ end
231
+ end
232
+
233
+ context 'a properly formed hash is passed in with nil values' do
234
+ it 'should return a payload hash with the nil values removed' do
235
+ payload = @client.send(:generate_payload, {vo_alert_type: 'TEST', special_var: 'i am special', nil_value: nil})
236
+ expect(payload[:message_type]).to eq 'TEST'
237
+ expect(payload[:special_var]).to eq 'i am special'
238
+ expect(payload[:state_start_time]).to be_a(Fixnum)
239
+ expect(payload[:entity_display_name]).to be_a(String)
240
+ expect(payload[:monitoring_tool]).to be_a(String)
241
+ expect(payload.has_key?(:nil_value)).to be_falsey
242
+ end
243
+ end
244
+ end
245
+
246
+ context 'utility methods' do
247
+ before do
248
+ @client = VictorOps::Client.new @valid_params
249
+ end
250
+
251
+ describe '.epochtime' do
252
+ it 'should return the current time in intenger form' do
253
+ expect(@client.send(:epochtime)).to be_a(Fixnum)
254
+ end
255
+ end
256
+
257
+ describe '.set_default_settings' do
258
+ context 'no overides provided' do
259
+ it 'should set the default settings for the client' do
260
+ expect(@client.settings.host).to eq 'localhost'
261
+ expect(@client.settings.name).to eq 'ruby REST client'
262
+ end
263
+ end
264
+
265
+ context 'overides provided' do
266
+ before do
267
+ @client = VictorOps::Client.new @valid_params.merge(host: 'db1.com', name: 'jester')
268
+ end
269
+
270
+ it 'should set the settings to the overides for the client' do
271
+ expect(@client.settings.host).to eq 'db1.com'
272
+ expect(@client.settings.name).to eq 'jester'
273
+ end
274
+ end
275
+ end
276
+
277
+ describe '.endpoint' do
278
+ before do
279
+ @client = VictorOps::Client.new api_url: 'http://victorops.com', routing_key: '1234'
280
+ end
281
+
282
+ it 'should provide the proper REST endpoint to post to' do
283
+ expect(@client.send(:endpoint)).to eq 'http://victorops.com/1234'
284
+ end
285
+ end
286
+
287
+ describe '.post' do
288
+ context 'there is a failure response from VictorOps' do
289
+ before do
290
+ @client = VictorOps::Client.new api_url: 'http://victorops.com', routing_key: '1234'
291
+ allow(RestClient).to receive(:post).and_return(file_fixture('victor_ops_failure.json'))
292
+ end
293
+
294
+ it 'should raise an exception' do
295
+ expect { @client.send(:post, { test: 'hash' } ) }.to raise_exception(VictorOps::Client::PostFailure)
296
+ end
297
+ end
298
+
299
+ context 'there is a failure while posting to VictorOps' do
300
+ before do
301
+ @client = VictorOps::Client.new api_url: 'http://victorops.com', routing_key: '1234'
302
+ allow(RestClient).to receive(:post).and_raise(Exception.new('test exception'))
303
+ end
304
+
305
+ it 'should raise an exception' do
306
+ expect { @client.send(:post, { test: 'hash' } ) }.to raise_exception(VictorOps::Client::PostFailure)
307
+ end
308
+ end
309
+
310
+ context 'the POST is successful' do
311
+ before do
312
+ @client = VictorOps::Client.new api_url: 'http://victorops.com', routing_key: '1234'
313
+ allow(RestClient).to receive(:post).and_return(file_fixture('victor_ops_success.json'))
314
+ end
315
+
316
+ it 'return the parsed response' do
317
+ resp = @client.send(:post, { test: 'hash' } )
318
+ expect(resp).to be_a(Hash)
319
+ expect(resp['result']).to eq 'success'
320
+ expect(resp['entity_id']).to be_a(String)
321
+ end
322
+ end
323
+ end
324
+
325
+ describe '.critical_payload' do
326
+ it 'should return a Hash without duplicate data' do
327
+ data = @client.send(:critical_payload, message: 'test')
328
+ expect(data).to be_a(Hash)
329
+ expect(data[:message_type]).to eql 'CRITICAL'
330
+ expect(data[:entity_display_name]).to_not be_nil
331
+ expect(data[:monitoring_tool]).to_not be_nil
332
+ expect(data[:state_message]).to eq '"test"'
333
+ expect(data[:message]).to be_nil
334
+ end
335
+ end
336
+
337
+ describe '.warn_payload' do
338
+ it 'should return a Hash without duplicate data' do
339
+ data = @client.send(:warn_payload, message: 'test')
340
+ expect(data).to be_a(Hash)
341
+ expect(data[:message_type]).to eql 'WARNING'
342
+ expect(data[:entity_display_name]).to_not be_nil
343
+ expect(data[:monitoring_tool]).to_not be_nil
344
+ expect(data[:state_message]).to eq '"test"'
345
+ expect(data[:message]).to be_nil
346
+ end
347
+ end
348
+
349
+ describe '.info_payload' do
350
+ it 'should return a Hash without duplicate data' do
351
+ data = @client.send(:info_payload, message: 'test')
352
+ expect(data).to be_a(Hash)
353
+ expect(data[:message_type]).to eql 'INFO'
354
+ expect(data[:entity_display_name]).to_not be_nil
355
+ expect(data[:monitoring_tool]).to_not be_nil
356
+ expect(data[:state_message]).to eq '"test"'
357
+ expect(data[:message]).to be_nil
358
+ end
359
+ end
360
+
361
+ describe '.ack_payload' do
362
+ context 'no author provided' do
363
+ it 'should return a Hash without duplicate data' do
364
+ data = @client.send(:ack_payload, message: 'test')
365
+ expect(data).to be_a(Hash)
366
+ expect(data[:message_type]).to eql 'ACKNOWLEDGEMENT'
367
+ expect(data[:entity_display_name]).to_not be_nil
368
+ expect(data[:monitoring_tool]).to_not be_nil
369
+ expect(data[:state_message]).to be_nil
370
+ expect(data[:ack_msg]).to eq '"test"'
371
+ expect(data[:ack_author]).to eq data[:monitoring_tool]
372
+ expect(data[:message]).to be_nil
373
+ end
374
+ end
375
+
376
+ context 'an author is provieded' do
377
+ it 'should return a Hash without duplicate data' do
378
+ data = @client.send(:ack_payload, message: 'test', author: 'test author')
379
+ expect(data).to be_a(Hash)
380
+ expect(data[:message_type]).to eql 'ACKNOWLEDGEMENT'
381
+ expect(data[:entity_display_name]).to_not be_nil
382
+ expect(data[:monitoring_tool]).to_not be_nil
383
+ expect(data[:state_message]).to be_nil
384
+ expect(data[:ack_msg]).to eq '"test"'
385
+ expect(data[:ack_author]).to eq 'test author'
386
+ expect(data[:message]).to be_nil
387
+ expect(data[:author]).to be_nil
388
+ end
389
+ end
390
+ end
391
+
392
+ describe '.recovery_payload' do
393
+ it 'should return a Hash without duplicate data' do
394
+ data = @client.send(:recovery_payload, message: 'test')
395
+ expect(data).to be_a(Hash)
396
+ expect(data[:message_type]).to eql 'RECOVERY'
397
+ expect(data[:entity_display_name]).to_not be_nil
398
+ expect(data[:monitoring_tool]).to_not be_nil
399
+ expect(data[:state_message]).to eq '"test"'
400
+ expect(data[:message]).to be_nil
401
+ end
402
+ end
403
+ end
404
+
405
+ end
406
+
407
+ end
@@ -0,0 +1,26 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
2
+
3
+ RSpec.describe VictorOps::Defaults do
4
+ describe 'MessageTypes' do
5
+ it 'should be have VictorOps defined values' do
6
+ expect(VictorOps::Defaults::MessageTypes::INFO).to eq 'INFO'
7
+ expect(VictorOps::Defaults::MessageTypes::WARN).to eq 'WARNING'
8
+ expect(VictorOps::Defaults::MessageTypes::CRITICAL).to eq 'CRITICAL'
9
+ expect(VictorOps::Defaults::MessageTypes::ACK).to eq 'ACKNOWLEDGEMENT'
10
+ expect(VictorOps::Defaults::MessageTypes::RECOVERY).to eq 'RECOVERY'
11
+ end
12
+ end
13
+
14
+ describe 'client defautlts' do
15
+ it 'should have generic defaults set' do
16
+ expect(VictorOps::Defaults::HOST).to eq 'localhost'
17
+ expect(VictorOps::Defaults::NAME).to eq 'ruby REST client'
18
+ end
19
+ end
20
+
21
+ describe 'daybreak defaults' do
22
+ it 'should have defaults needed for daybreak persistence' do
23
+ expect(VictorOps::Defaults::Daybreak::PATH).to eq '/tmp/victor_ops-client.db'
24
+ end
25
+ end
26
+ end
File without changes
@@ -0,0 +1,4 @@
1
+ {
2
+ "result": "failure",
3
+ "entity_id": "Missing something important"
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "result": "success",
3
+ "entity_id": "392c55f1-f5b6-42fa-b6d9-8aa033465ce6"
4
+ }
@@ -0,0 +1,75 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
2
+
3
+ RSpec.describe VictorOps::Client do
4
+ before do
5
+ @valid_params = { api_url: 'test url', routing_key: 'test key' }
6
+ end
7
+
8
+ context 'persistence layer' do
9
+ describe 'client does not want persistence' do
10
+ before do
11
+ @client = VictorOps::Client.new @valid_params.merge(persist: nil)
12
+ end
13
+
14
+ it 'should not configure daybreak' do
15
+ expect(@client.settings.test).to be_nil
16
+ end
17
+ end
18
+
19
+ context 'client does want persistence' do
20
+ before do
21
+ @client = VictorOps::Client.new @valid_params.merge(persist: true, store_file: 'tmp/test.db')
22
+ end
23
+
24
+ after do
25
+ @client.shutdown
26
+ end
27
+
28
+ it 'should configure daybreak' do
29
+ expect(@client.settings.store_file).to eq 'tmp/test.db'
30
+ expect(@client.db).to be_a(Daybreak::DB)
31
+ end
32
+
33
+ it 'should allow for interactions with the database directly' do
34
+ @client.db.set! 'test', 'worked'
35
+ expect(@client.db['test']).to eq 'worked'
36
+ expect(@client.db.include?('test')).to be_truthy
37
+ @client.db.delete 'test'
38
+ expect(@client.db.include?('test')).to be_falsey
39
+ expect(@client.db['test']).to be_nil
40
+ end
41
+
42
+ describe '.set' do
43
+ it 'will allow the setting of persisted values' do
44
+ @client.set('answer to all', 42)
45
+ expect(@client.db['answer to all']).to eq 42
46
+ @client.shutdown
47
+ @client = VictorOps::Client.new @valid_params.merge(persist: true, store_file: 'tmp/test.db')
48
+ expect(@client.db['answer to all']).to eq 42
49
+ end
50
+ end
51
+
52
+ describe '.retrieve' do
53
+ it 'will retrieve a persisted value' do
54
+ @client.set('tester', 'woot')
55
+ expect(@client.retrieve('tester')).to eq 'woot'
56
+ expect(@client.retrieve('not in here')).to be_nil
57
+ @client.shutdown
58
+ @client = VictorOps::Client.new @valid_params.merge(persist: true, store_file: 'tmp/test.db')
59
+ expect(@client.retrieve('tester')).to eq 'woot'
60
+ expect(@client.retrieve('not in here')).to be_nil
61
+ end
62
+ end
63
+
64
+ describe '.delete' do
65
+ it 'will delete a persisted value' do
66
+ @client.set('this will be deleted', 'woot')
67
+ expect(@client.delete('this will be deleted')).to eq 'woot'
68
+ @client.shutdown
69
+ @client = VictorOps::Client.new @valid_params.merge(persist: true, store_file: 'tmp/test.db')
70
+ expect(@client.delete('this will be deleted')).to be_nil
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,57 @@
1
+ require 'simplecov'
2
+ require 'codeclimate-test-reporter'
3
+
4
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
5
+ SimpleCov::Formatter::HTMLFormatter,
6
+ CodeClimate::TestReporter::Formatter
7
+ ]
8
+ SimpleCov.start
9
+
10
+ require 'victor_ops/client'
11
+ require 'json'
12
+
13
+ def file_fixture(filename)
14
+ open(File.join(File.dirname(__FILE__), 'fixtures', "#{filename.to_s}")).read
15
+ end
16
+
17
+ def file_fixture_to_json(filename)
18
+ JSON::parse(open(File.join(File.dirname(__FILE__), 'fixtures', "#{filename.to_s}")).read)
19
+ end
20
+
21
+ def file_fixture_path(filename)
22
+ File.join(File.dirname(__FILE__), 'fixtures', "#{filename.to_s}")
23
+ end
24
+
25
+ def open_tmp_file(filename)
26
+ open(File.join(File.dirname(__FILE__), '..', 'tmp', "#{filename.to_s}")).read
27
+ end
28
+
29
+ RSpec.configure do |config|
30
+ config.expect_with :rspec do |expectations|
31
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
32
+ end
33
+
34
+ config.mock_with :rspec do |mocks|
35
+ mocks.verify_partial_doubles = false
36
+ end
37
+
38
+ # config.filter_run :focus
39
+ # config.run_all_when_everything_filtered = true
40
+ # config.profile_examples = 10
41
+
42
+ config.disable_monkey_patching!
43
+
44
+ config.warnings = false
45
+
46
+ if config.files_to_run.one?
47
+ config.default_formatter = 'doc'
48
+ end
49
+
50
+
51
+ config.order = :random
52
+ Kernel.srand config.seed
53
+
54
+ config.after(:suite) do
55
+ FileUtils.rm('tmp/test.db') if File.exist? 'tmp/test.rb'
56
+ end
57
+ end
@@ -0,0 +1,9 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
2
+
3
+ RSpec.describe VictorOps::Client do
4
+ describe "version" do
5
+ it 'should be a string type' do
6
+ expect(VictorOps::Client::VERSION).to be_a(String)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,24 @@
1
+ $:.push File.expand_path("../lib", __FILE__)
2
+ require 'victor_ops/client/version'
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'victor_ops-client'
6
+ s.version = VictorOps::Client::VERSION
7
+ s.date = Time.now.strftime('%Y-%m-%d')
8
+ s.summary = "VictorOps Client"
9
+ s.description = "A gem that will allow for consistent usage of the VictorOps service from within a script or daemon."
10
+ s.authors = ["Derek Smith"]
11
+ s.email = 'derek@clokwork.net'
12
+ s.homepage = 'http://clokwork.net'
13
+
14
+ s.files = `git ls-files`.split("\n").compact
15
+ s.require_paths = ["lib"]
16
+
17
+ s.required_ruby_version = '>= 1.9.3'
18
+ s.add_dependency 'rest-client', '~> 1.8', '>= 1.8.0'
19
+ s.add_dependency 'awesome_print', '~> 1.6', '>= 1.6.1'
20
+ s.add_dependency 'daybreak', '~> 0.3', '>= 0.3.0'
21
+ s.add_development_dependency "rspec", '~> 3.0'
22
+
23
+ s.license = 'MIT'
24
+ end
metadata ADDED
@@ -0,0 +1,142 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: victor_ops-client
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0
5
+ platform: ruby
6
+ authors:
7
+ - Derek Smith
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-04-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rest-client
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.8'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 1.8.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '1.8'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 1.8.0
33
+ - !ruby/object:Gem::Dependency
34
+ name: awesome_print
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '1.6'
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: 1.6.1
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: '1.6'
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: 1.6.1
53
+ - !ruby/object:Gem::Dependency
54
+ name: daybreak
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - "~>"
58
+ - !ruby/object:Gem::Version
59
+ version: '0.3'
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: 0.3.0
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '0.3'
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: 0.3.0
73
+ - !ruby/object:Gem::Dependency
74
+ name: rspec
75
+ requirement: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - "~>"
78
+ - !ruby/object:Gem::Version
79
+ version: '3.0'
80
+ type: :development
81
+ prerelease: false
82
+ version_requirements: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - "~>"
85
+ - !ruby/object:Gem::Version
86
+ version: '3.0'
87
+ description: A gem that will allow for consistent usage of the VictorOps service from
88
+ within a script or daemon.
89
+ email: derek@clokwork.net
90
+ executables: []
91
+ extensions: []
92
+ extra_rdoc_files: []
93
+ files:
94
+ - ".gitignore"
95
+ - ".travis.yml"
96
+ - Gemfile
97
+ - History
98
+ - MIT-LICENSE
99
+ - README.md
100
+ - Rakefile
101
+ - db/.keep
102
+ - examples/test.rb
103
+ - lib/victor_ops/client.rb
104
+ - lib/victor_ops/client/exceptions.rb
105
+ - lib/victor_ops/client/persistence.rb
106
+ - lib/victor_ops/client/version.rb
107
+ - lib/victor_ops/defaults.rb
108
+ - spec/client_spec.rb
109
+ - spec/defaults_spec.rb
110
+ - spec/fixtures/.keep
111
+ - spec/fixtures/victor_ops_failure.json
112
+ - spec/fixtures/victor_ops_success.json
113
+ - spec/persistence_spec.rb
114
+ - spec/spec_helper.rb
115
+ - spec/version_spec.rb
116
+ - tmp/.keep
117
+ - victor_ops-client.gemspec
118
+ homepage: http://clokwork.net
119
+ licenses:
120
+ - MIT
121
+ metadata: {}
122
+ post_install_message:
123
+ rdoc_options: []
124
+ require_paths:
125
+ - lib
126
+ required_ruby_version: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - ">="
129
+ - !ruby/object:Gem::Version
130
+ version: 1.9.3
131
+ required_rubygems_version: !ruby/object:Gem::Requirement
132
+ requirements:
133
+ - - ">="
134
+ - !ruby/object:Gem::Version
135
+ version: '0'
136
+ requirements: []
137
+ rubyforge_project:
138
+ rubygems_version: 2.4.6
139
+ signing_key:
140
+ specification_version: 4
141
+ summary: VictorOps Client
142
+ test_files: []