rapporteur 1.0.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.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ NDgwNmQ2Yjc2Yzc3Y2NhMTk5YmMwMmFjNWNhZTQ3YWY2NGM0OTFjNw==
5
+ data.tar.gz: !binary |-
6
+ NDg0Njg3NTBiZmYyZmM0ODVjOGY0ZTIzYWE5MTcyMmI0M2U4ZjJjOQ==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ NTE4NWFlODVmMjcxZjg3YTExZGIxMDQyNmI1OWM3ZmQxMGU5MzgyMmVjNDlk
10
+ MjMyYzE2NGYzMTQ0YzdjM2Q5ZTNhNmMzNGEyOTUwZDM5NjAyYzU2Y2ExNzY5
11
+ ZjQ5YTlmZWRiNWZhODQ4YjcxNzJkOTlmNWMxOWExODNiMTdiYzQ=
12
+ data.tar.gz: !binary |-
13
+ YjM5OTIzNjM0MDI5ODU1YjA3ZTc2ZDYwM2RlYWIwYTIzODljMmViY2YwNzg5
14
+ YThmMThkMzExMzAxOGZkMWU1YmQxMmE0NTMzNTg4N2E3M2ZlOTMxYTU3OGY5
15
+ MWIwNjUwNTJlODQ2OTAyZGU5NWNjYjBlNjZkMmM1ODMyMDU4Nzg=
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ .rvmrc
2
+ .ruby-version
3
+ .ruby-gemset
4
+ *.gem
5
+ *.rbc
6
+ .bundle
7
+ .config
8
+ .yardoc
9
+ Gemfile.lock
10
+ *.gemfile.lock
11
+ InstalledFiles
12
+ _yardoc
13
+ coverage
14
+ doc/
15
+ lib/bundler/man
16
+ pkg
17
+ rdoc
18
+ spec/reports
19
+ test/tmp
20
+ test/version_tmp
21
+ tmp
22
+ *.sqlite
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/.travis.yml ADDED
@@ -0,0 +1,14 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.2
4
+ - 1.9.3
5
+ gemfile:
6
+ - gemfiles/rails3.1.gemfile
7
+ - gemfiles/rails3.2.gemfile
8
+ notifications:
9
+ email: false
10
+ campfire:
11
+ on_success: change
12
+ on_failure: always
13
+ rooms:
14
+ - secure: "gxEt3SeVn1kup6PfB6hiQu6eWsefmMEdd8U1qPSS6vlRjsM7Xy2IrXdz9gdl\n0nrrRgESvOxT3sqMh4/opH6M1kbtCyl3M0yvjF2QUtjWQ+4BStJGhNyXlDTp\nNAas19fuEUPBNxNqoy7aTVBiFpQRs0NisEZTS3+N3eA2tz757Qk="
data/Appraisals ADDED
@@ -0,0 +1,7 @@
1
+ appraise "rails3.1" do
2
+ gem "railties", "~> 3.1.0"
3
+ end
4
+
5
+ appraise "rails3.2" do
6
+ gem "railties", "~> 3.2.0"
7
+ end
data/CHANGELOG.md ADDED
@@ -0,0 +1,12 @@
1
+ # Rapporteur
2
+
3
+ ## [HEAD][unreleased] / unreleased
4
+
5
+ * No significant changes.
6
+
7
+ ## 1.0.0 / 2013-05-19
8
+
9
+ * Initial public release.
10
+
11
+
12
+ [unreleased]: https://github.com/codeschool/rapporteur/compare/v1.0.0...master
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Envy Labs LLC and Code School LLC
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,219 @@
1
+ # Rapporteur
2
+
3
+ This gem provides a singular, status-checking endpoint to your application. The
4
+ endpoint provides a JSON response with either an HTTP 200 or an HTTP 500
5
+ response, depending on the current application environment.
6
+
7
+ When the environment tests successfully, an HTTP 200 response is returned with
8
+ the current application Git revision and server time:
9
+
10
+ ```json
11
+ {
12
+ "revision": "906731e6467ea381ba5bc70f103b85ed4178fee7",
13
+ "time": "2013-05-19T05:38:46Z"
14
+ }
15
+ ```
16
+
17
+ When an application validation fails, an HTTP 500 response is returned with a
18
+ collection of error messages, similar to the default Rails responders for model
19
+ validations:
20
+
21
+ ```json
22
+ {
23
+ "errors": {
24
+ "base": ["The application database is inaccessible or unavailable"]
25
+ }
26
+ }
27
+ ```
28
+
29
+ ## Installation
30
+
31
+ Supported Ruby versions:
32
+
33
+ * MRI 1.9.2
34
+ * MRI 1.9.3
35
+
36
+ Supported Rails versions:
37
+
38
+ * Rails 3.1.x.
39
+ * Rails 3.2.x.
40
+
41
+ To install, add this line to your application's Gemfile:
42
+
43
+ gem 'rapporteur'
44
+
45
+ And then execute:
46
+
47
+ $ bundle
48
+
49
+ ## Usage
50
+
51
+ Simply adding the gem requirement to your Gemfile is enough to install and
52
+ automatically load and configure the gem. Technically speaking, the gem is a
53
+ Rails Engine, so it auto-initializes with Rails starts up. There is no further
54
+ configuration necessary.
55
+
56
+ By default, there are no application checks that run and the status endpoint
57
+ simply reports the current application revision and time. This is useful for a
58
+ basic connectivity check to be watched by a third party service like Pingdom
59
+ for a very simple, non-critical application.
60
+
61
+ You may optionally use any of the pre-defined checks (such as the ActiveRecord
62
+ connection check) to expand the robustness of the status checks. Adding a check
63
+ will execute that check each time the status endpoint is requested, so be
64
+ somewhat wary of doing _too_ much. See more in the [Adding checks
65
+ section](#adding-checks), below.
66
+
67
+ Further, you can define your own checks which could be custom to your
68
+ application or environment and report their own, unique errors. The only
69
+ requirement is that the check objects are callable (respond to `#call`, like a
70
+ Proc). See more in the [Creating custom checks
71
+ section](#creating-custom-checks), below.
72
+
73
+ ### The endpoint
74
+
75
+ This gem provides a new, single endpoint in your application. Specifically, it
76
+ creates a named `/status.json` route, with the "status" name. It does not match
77
+ on any other format or variation, which isolates the pollution of your
78
+ application routes.
79
+
80
+ If you'd like to link to the status endpoint from within your application (why,
81
+ I couldn't guess), you can use a standard Rails URL helper:
82
+
83
+ ```ruby
84
+ link_to status_path
85
+ ```
86
+
87
+ Were you already using the `/status.json` endpoint or the "status" route name?
88
+ Hmm. Well... you just broke it.
89
+
90
+ ## Customization
91
+
92
+ ### Adding checks
93
+
94
+ This gem ships with the following checks tested and packaged:
95
+
96
+ * **Rapporteur::Checks::ActiveRecordCheck** - Performs a trivial test
97
+ of the current `ActiveRecord::Base.connection` to ensure basic database
98
+ connectivity.
99
+
100
+ To add checks to your application, define the checks you'd like to run in your
101
+ environment or application configuration files or initializers, such as:
102
+
103
+ ```ruby
104
+ # config/initializers/rapporteur.rb
105
+ Rapporteur::Checker.add_check(Rapporteur::Checks::ActiveRecordCheck)
106
+ ```
107
+
108
+ Or, make an environment specific check with:
109
+
110
+ ```ruby
111
+ # config/environments/production.rb
112
+ MyApplication.configure do
113
+ config.to_prepare do
114
+ Rapporteur::Checker.add_check(Rapporteur::Checks::ActiveRecordCheck)
115
+ end
116
+ end
117
+ ```
118
+
119
+ ### Creating custom checks
120
+
121
+ It is simple to add a custom check to the status endpoint. All that is required
122
+ is that you give the checker an object that is callable. In your object, simply
123
+ check for the state of the world that you're interested in, and if you're not
124
+ happy with it, add an error to the given `checker` instance:
125
+
126
+ ```ruby
127
+ # config/initializers/rapporteur.rb
128
+
129
+ my_proc_check = lambda { |checker|
130
+ checker.add_error("You have bad luck!") if rand(10) > 5
131
+ }
132
+
133
+ Rapporteur::Checker.add_check(my_proc_check)
134
+
135
+ class MyClassCheck
136
+ def self.call(checker)
137
+ @@counter ||= 0
138
+ checker.add_error("Stop calling me!!") if @@counter > 50
139
+ end
140
+ end
141
+
142
+ Rapporteur::Checker.add_check(MyClassCheck)
143
+ ```
144
+
145
+ Certainly, the definition and registration of the checks do not need to occur
146
+ within the same file, but you get the idea. Also: Please make your checks more
147
+ useful than those defined above. ;)
148
+
149
+ You could create a checker for your active Redis connection, Memcached
150
+ connections, disk usage percentage, process count, memory usage, or really
151
+ anything you like. Again, because these checks get executed every time the
152
+ status endpoint is called, **be mindful of the tradeoffs when making a check that
153
+ may be resource intensive**.
154
+
155
+ ### Customizing the revision
156
+
157
+ If you need to customize the way in which the current application revision is
158
+ calculated (by default it runs a `git rev-parse HEAD`), you may do so by
159
+ modifying the necessary environment file or creating an initializer in your
160
+ Rails application:
161
+
162
+ ```ruby
163
+ # config/initializers/rapporteur.rb
164
+ Rapporteur::Revision.current = "revision123"
165
+ ```
166
+
167
+ ```ruby
168
+ # config/environments/production.rb
169
+ MyApplication.configure do
170
+ config.to_prepare do
171
+ Rapporteur::Revision.current = "revision123"
172
+ end
173
+ end
174
+ ```
175
+
176
+ You may pass a String or a callable object (Proc) to `.current=` and it will be
177
+ executed and memoized. Useful examples of this are:
178
+
179
+ ```ruby
180
+ # Read a Capistrano REVISION file
181
+ Rapporteur::Revision.current = Rails.root.join("REVISION").read.strip
182
+
183
+ # Force a particular directory and use Git
184
+ Rapporteur::Revision.current = `cd "#{Rails.root}" && git rev-parse HEAD`.strip
185
+
186
+ # Use an ENV variable (Heroku)
187
+ Rapporteur::Revision.current = ENV["REVISION"]
188
+
189
+ # Do some crazy calculation
190
+ Rapporteur::Revision.current = lambda { MyRevisionCalculator.execute! }
191
+ ```
192
+
193
+ ### Customizing the error messages
194
+
195
+ The error messages displayed in the event that application validations fail are
196
+ all collected through I18n. There are default localization strings provided
197
+ with the gem, but you may override them as necessary, simply by redefining them
198
+ in a locales file within your local application.
199
+
200
+ For example, to override the database check failure message:
201
+
202
+ ```yaml
203
+ en:
204
+ activemodel:
205
+ errors:
206
+ models:
207
+ rapporteur/checker:
208
+ attributes:
209
+ base:
210
+ database_unavailable: "Something went wrong"
211
+ ```
212
+
213
+ ## Contributing
214
+
215
+ 1. Fork it
216
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
217
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
218
+ 4. Push to the branch (`git push origin my-new-feature`)
219
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+ require 'appraisal'
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+ task default: :spec
@@ -0,0 +1,10 @@
1
+ class StatusesController < ActionController::Base
2
+ self.responder = Rapporteur::Responder
3
+ respond_to :json
4
+
5
+ def show
6
+ respond_with(Rapporteur::Checker.run, {
7
+ serializer: Rapporteur::Serializer
8
+ })
9
+ end
10
+ end
@@ -0,0 +1,8 @@
1
+ en:
2
+ activemodel:
3
+ errors:
4
+ models:
5
+ rapporteur/checker:
6
+ attributes:
7
+ base:
8
+ database_unavailable: "The application database is inaccessible or unavailable"
data/config/routes.rb ADDED
@@ -0,0 +1,3 @@
1
+ Rails.application.routes.draw do
2
+ get 'status.json', to: 'statuses#show', defaults: {format: 'json'}, as: :status
3
+ end
data/config.ru ADDED
@@ -0,0 +1,7 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+
4
+ Bundler.require :default, :development
5
+
6
+ Combustion.initialize!
7
+ run Combustion::Application
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "railties", "~> 3.1.0"
6
+
7
+ gemspec :path=>"../"
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "railties", "~> 3.2.0"
6
+
7
+ gemspec :path=>"../"
@@ -0,0 +1,111 @@
1
+ require 'singleton'
2
+ require 'set'
3
+
4
+ module Rapporteur
5
+ # The center of the Rapporteur library, Checker manages holding and running
6
+ # the custom checks, holding any application error messages, and provides the
7
+ # controller with that data for rendering.
8
+ #
9
+ class Checker
10
+ include Singleton
11
+ include ActiveModel::Validations
12
+ include ActiveModel::SerializerSupport
13
+
14
+
15
+ # Public: Add a pre-built or custom check to your status endpoint. These
16
+ # checks are used to test the state of the world of the application, and
17
+ # need only respond to `#call`.
18
+ #
19
+ # Once added, the given check will be called and passed an instance of this
20
+ # checker. If everything is good, do nothing! If there is a problem, use
21
+ # `add_error` to add an error message to the checker.
22
+ #
23
+ # Examples
24
+ #
25
+ # Rapporteur::Checker.add_check(lambda { |checker|
26
+ # checker.add_error("Bad luck.") if rand(2) == 1
27
+ # })
28
+ #
29
+ # Returns Rapporteur::Checker.
30
+ # Raises ArgumentError if the given check does not respond to call.
31
+ #
32
+ def self.add_check(object)
33
+ raise ArgumentError, "A check must respond to #call." unless object.respond_to?(:call)
34
+ instance.checks << object
35
+ self
36
+ end
37
+
38
+ # Public: Empties all configured checks from the checker. This may be
39
+ # useful for testing and for cases where you might've built up some basic
40
+ # checks but for one reason or another (environment constraint) need to
41
+ # start from scratch.
42
+ #
43
+ # Returns Rapporteur::Checker.
44
+ #
45
+ def self.clear
46
+ instance.checks.clear
47
+ self
48
+ end
49
+
50
+ # Public: This is the primary execution point for this class. Use run to
51
+ # exercise the configured checker and collect any application errors or
52
+ # data for rendering.
53
+ #
54
+ # Returns a Rapporteur::Checker instance.
55
+ #
56
+ def self.run
57
+ instance.errors.clear
58
+ instance.run
59
+ end
60
+
61
+
62
+ # Public: Add an error message to the checker in order to have it rendered
63
+ # in the status request.
64
+ #
65
+ # It is suggested that you use I18n and locale files for these messages, as
66
+ # is done with the pre-built checks. If you're using I19n, you'll need to
67
+ # define `activemodel.errors.models.rapporteur/checker.attributes.base.<your key>`.
68
+ #
69
+ # Examples
70
+ #
71
+ # checker.add_error("You failed.")
72
+ # checker.add_error(:i18n_key_is_better)
73
+ #
74
+ # Returns the Rapporteur::Checker instance.
75
+ #
76
+ def add_error(message)
77
+ errors.add(:base, message)
78
+ self
79
+ end
80
+
81
+ # Public: Returns the Set of checks currently configured.
82
+ #
83
+ def checks
84
+ @checks ||= Set.new
85
+ end
86
+
87
+ # Public: Returns a String containing the current revision of the
88
+ # application.
89
+ #
90
+ def revision
91
+ Revision.current
92
+ end
93
+
94
+ # Public: Executes the configured checks.
95
+ #
96
+ # Returns the Rapporteur::Checker instance.
97
+ #
98
+ def run
99
+ checks.each do |object|
100
+ object.call(self)
101
+ end
102
+ self
103
+ end
104
+
105
+ # Public: Returns a Time instance containing the current system time.
106
+ #
107
+ def time
108
+ Time.now
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,11 @@
1
+ module Rapporteur
2
+ module Checks
3
+ class ActiveRecordCheck
4
+ def self.call(checker)
5
+ ActiveRecord::Base.connection.execute("SELECT current_time AS time").first.fetch('time')
6
+ rescue
7
+ checker.add_error(:database_unavailable)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,5 @@
1
+ module Rapporteur
2
+ module Checks
3
+ autoload :ActiveRecordCheck, 'rapporteur/checks/active_record_check'
4
+ end
5
+ end
@@ -0,0 +1,4 @@
1
+ module Rapporteur
2
+ class Engine < Rails::Engine
3
+ end
4
+ end
@@ -0,0 +1,32 @@
1
+ module Rapporteur
2
+ # A customization of the default Rails ActionController::Responder.
3
+ # Primarily, this is used to smooth out the differences between Rails
4
+ # responder versions and allow for error messages in GET requests.
5
+ #
6
+ class Responder < ActionController::Responder
7
+ # Internal: Overrides the default behavior by ignoring the HTTP verb and
8
+ # always responding with errors if the rendering resource contains errors.
9
+ #
10
+ def to_format
11
+ if has_errors?
12
+ display_errors
13
+ else
14
+ super
15
+ end
16
+ end
17
+
18
+
19
+ protected
20
+
21
+
22
+ if Rails::VERSION::MAJOR == 3 && Rails::VERSION::MINOR == 1
23
+ def display_errors
24
+ controller.render format => {errors: resource.errors}, status: :internal_server_error
25
+ end
26
+ elsif Rails::VERSION::MAJOR == 3 && Rails::VERSION::MINOR == 2
27
+ def display_errors
28
+ controller.render format => resource_errors, status: :internal_server_error
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,56 @@
1
+ module Rapporteur
2
+ # Manages memoizing and maintaining the current application revision.
3
+ #
4
+ class Revision
5
+ class_attribute :_current
6
+
7
+ # Public: Returns the current revision as a String.
8
+ #
9
+ def self.current
10
+ self._current ||= calculate_current
11
+ end
12
+
13
+ # Public: Forcibly sets the current application revision.
14
+ #
15
+ # revision - Either a String or a callable object (Proc, for example) to
16
+ # use your own environment logic to determine the revision.
17
+ #
18
+ # Examples
19
+ #
20
+ # Rapporteur::Revision.current = ENV['REVISION'].strip
21
+ # Rapporteur::Revision.current = Rails.root.join("REVISION").read.strip
22
+ #
23
+ # Returns the revision given.
24
+ #
25
+ def self.current=(revision)
26
+ self._current = calculate_current(revision)
27
+ end
28
+
29
+ # Internal: The default method of determining the current revision. This
30
+ # assumes a git executable is in the current PATH and that the process
31
+ # context is running the the appropriate git application directory.
32
+ #
33
+ # Returns a String containing the current git revision, hopefully.
34
+ #
35
+ def self.default_revision_source
36
+ `git rev-parse HEAD 2>/dev/null`.strip
37
+ rescue
38
+ end
39
+
40
+ # Internal: Calculates the current revision from the configured revision
41
+ # source.
42
+ #
43
+ def self.calculate_current(revision = default_revision_source)
44
+ case revision
45
+ when String
46
+ revision
47
+ when Proc
48
+ revision.call.to_s
49
+ when NilClass
50
+ "You must provide a Rapporteur::Revision.current= String or Proc"
51
+ else
52
+ raise ArgumentError, "Unknown revision type given: #{revision.inspect}"
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,68 @@
1
+ require 'rapporteur'
2
+
3
+ shared_examples_for 'a successful status response' do
4
+ it 'responds with HTTP 200' do
5
+ expect(subject.response_code).to(eq(200))
6
+ end
7
+
8
+ it 'responds with a JSON content header' do
9
+ expect(subject.content_type).to(eq(Mime::JSON))
10
+ end
11
+
12
+ it 'responds with valid JSON' do
13
+ expect { JSON.parse(subject.body) }.not_to(raise_error)
14
+ end
15
+
16
+ context 'the response payload' do
17
+ subject { get(status_path) ; JSON.parse(response.body) }
18
+
19
+ it 'does not contain errors' do
20
+ expect(subject).not_to(have_key('errors'))
21
+ end
22
+
23
+ it 'contains the current application revision' do
24
+ expect(subject.fetch('revision')).to(match(/^[a-f0-9]{40}$/))
25
+ end
26
+
27
+ it 'contains the current time in ISO8601' do
28
+ time = Time.now
29
+ Time.stub(:now).and_return(time)
30
+ expect(subject.fetch('time')).to(match(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/))
31
+ expect(subject.fetch('time')).to(eq(time.utc.iso8601))
32
+ end
33
+ end
34
+ end
35
+
36
+ shared_examples_for 'an erred status response' do
37
+ it 'responds with HTTP 500' do
38
+ expect(subject.response_code).to(eq(500))
39
+ end
40
+
41
+ it 'responds with a JSON content header' do
42
+ expect(subject.content_type).to(eq(Mime::JSON))
43
+ end
44
+
45
+ it 'responds with valid JSON' do
46
+ expect { JSON.parse(subject.body) }.not_to(raise_error)
47
+ end
48
+
49
+ it 'contains errors' do
50
+ expect(JSON.parse(subject.body)).to(have_key('errors'))
51
+ expect(JSON.parse(subject.body).fetch('errors')).not_to(be_empty)
52
+ end
53
+ end
54
+
55
+ RSpec::Matchers.define :include_status_error_message do |message|
56
+ match do |response|
57
+ @body = JSON.parse(response.body)
58
+ @body.fetch('errors', {}).fetch('base').include?(message)
59
+ end
60
+
61
+ failure_message_for_should do |actual|
62
+ "expected #{@body.inspect} to include a #{message.inspect} error message"
63
+ end
64
+
65
+ failure_message_for_should_not do |actual|
66
+ "expected #{@body.inspect} to not include a #{message.inspect} error message"
67
+ end
68
+ end
@@ -0,0 +1,20 @@
1
+ module Rapporteur
2
+ # An ActiveModel::Serializer used to serialize the checker data for JSON
3
+ # rendering.
4
+ #
5
+ class Serializer < ActiveModel::Serializer
6
+ self.root = false
7
+
8
+ attributes :revision,
9
+ :time
10
+
11
+ # Internal: Converts the checker instance time into UTC to provide a
12
+ # consistent public representation.
13
+ #
14
+ # Returns a Time instance in UTC.
15
+ #
16
+ def time
17
+ object.time.utc
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,3 @@
1
+ module Rapporteur
2
+ VERSION = "1.0.0"
3
+ end
data/lib/rapporteur.rb ADDED
@@ -0,0 +1,15 @@
1
+ require 'active_model_serializers'
2
+
3
+ require "rapporteur/engine" if defined?(Rails)
4
+ require "rapporteur/version"
5
+
6
+ # Rapporteur is a Rails Engine which provides your application with an
7
+ # application status endpoint.
8
+ #
9
+ module Rapporteur
10
+ autoload :Checker, 'rapporteur/checker'
11
+ autoload :Checks, 'rapporteur/checks'
12
+ autoload :Responder, 'rapporteur/responder'
13
+ autoload :Revision, 'rapporteur/revision'
14
+ autoload :Serializer, 'rapporteur/serializer'
15
+ end
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'rapporteur/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "rapporteur"
8
+ spec.version = Rapporteur::VERSION
9
+ spec.authors = ["Envy Labs", "Code School"]
10
+ spec.email = [""]
11
+ spec.description = %q{An engine that provides common status polling endpoint.}
12
+ spec.summary = %q{An engine that provides common status polling endpoint.}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency 'active_model_serializers', '>= 0.8'
22
+ spec.add_dependency 'railties', '~> 3.0'
23
+
24
+ spec.add_development_dependency "appraisal", "~> 0.5"
25
+ spec.add_development_dependency "bundler", "~> 1.3"
26
+ spec.add_development_dependency "combustion", "~> 0.5"
27
+ spec.add_development_dependency "rails", "~> 3.0"
28
+ spec.add_development_dependency "rake"
29
+ spec.add_development_dependency "rspec-rails", "~> 2.0"
30
+ spec.add_development_dependency "sqlite3"
31
+ end
@@ -0,0 +1,3 @@
1
+ test:
2
+ adapter: sqlite3
3
+ database: db/combustion_test.sqlite
@@ -0,0 +1,3 @@
1
+ Rails.application.routes.draw do
2
+ #
3
+ end
@@ -0,0 +1,3 @@
1
+ ActiveRecord::Schema.define do
2
+ #
3
+ end
@@ -0,0 +1 @@
1
+ *.log
File without changes
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'A status request with an ActiveRecordCheck' do
4
+ before do
5
+ Rapporteur::Checker.add_check(Rapporteur::Checks::ActiveRecordCheck)
6
+ end
7
+
8
+ subject { get(status_path) ; response }
9
+
10
+ context 'with an unerring ActiveRecord connection' do
11
+ it_behaves_like 'a successful status response'
12
+ end
13
+
14
+ context 'with a failed ActiveRecord connection' do
15
+ before do
16
+ ActiveRecord::Base.connection.stub(:execute).
17
+ and_raise(ActiveRecord::ConnectionNotEstablished)
18
+ end
19
+
20
+ it_behaves_like 'an erred status response'
21
+
22
+ it 'contains a message regarding the database failure' do
23
+ expect(subject).to include_status_error_message(I18n.t('activemodel.errors.models.rapporteur/checker.attributes.base.database_unavailable'))
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'A status request with no checks' do
4
+ before { Rapporteur::Checker.clear }
5
+
6
+ subject { get(status_path) ; response }
7
+
8
+ it_behaves_like 'a successful status response'
9
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper.rb'
2
+
3
+ describe "status routes" do
4
+ it 'routes /status.json to statuses#show' do
5
+ expect({ get: '/status.json'}).to route_to({
6
+ action: 'show',
7
+ controller: 'statuses',
8
+ format: 'json',
9
+ })
10
+ end
11
+
12
+ it 'does not route /status' do
13
+ expect({ get: '/status'}).to_not be_routable
14
+ end
15
+
16
+ it 'does not route /status.html' do
17
+ expect({ get: '/status.html'}).to_not be_routable
18
+ end
19
+
20
+ it 'does not route /status.xml' do
21
+ expect({ get: '/status.xml'}).to_not be_routable
22
+ end
23
+ end
@@ -0,0 +1,19 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'combustion'
4
+
5
+ ENV["RAILS_ENV"] ||= 'test'
6
+ Combustion.initialize! :action_controller, :active_record
7
+
8
+ require 'rspec/rails'
9
+ require 'rapporteur/rspec'
10
+
11
+ RSpec.configure do |config|
12
+ config.treat_symbols_as_metadata_keys_with_true_values = true
13
+ config.run_all_when_everything_filtered = true
14
+ config.filter_run :focus
15
+
16
+ config.order = 'random'
17
+
18
+ config.before { Rapporteur::Checker.clear }
19
+ end
metadata ADDED
@@ -0,0 +1,215 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rapporteur
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Envy Labs
8
+ - Code School
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-05-19 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: active_model_serializers
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ! '>='
19
+ - !ruby/object:Gem::Version
20
+ version: '0.8'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ! '>='
26
+ - !ruby/object:Gem::Version
27
+ version: '0.8'
28
+ - !ruby/object:Gem::Dependency
29
+ name: railties
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ~>
33
+ - !ruby/object:Gem::Version
34
+ version: '3.0'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ~>
40
+ - !ruby/object:Gem::Version
41
+ version: '3.0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: appraisal
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ~>
47
+ - !ruby/object:Gem::Version
48
+ version: '0.5'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ~>
54
+ - !ruby/object:Gem::Version
55
+ version: '0.5'
56
+ - !ruby/object:Gem::Dependency
57
+ name: bundler
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ~>
61
+ - !ruby/object:Gem::Version
62
+ version: '1.3'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: '1.3'
70
+ - !ruby/object:Gem::Dependency
71
+ name: combustion
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ~>
75
+ - !ruby/object:Gem::Version
76
+ version: '0.5'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ~>
82
+ - !ruby/object:Gem::Version
83
+ version: '0.5'
84
+ - !ruby/object:Gem::Dependency
85
+ name: rails
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ~>
89
+ - !ruby/object:Gem::Version
90
+ version: '3.0'
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ~>
96
+ - !ruby/object:Gem::Version
97
+ version: '3.0'
98
+ - !ruby/object:Gem::Dependency
99
+ name: rake
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ! '>='
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ! '>='
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ - !ruby/object:Gem::Dependency
113
+ name: rspec-rails
114
+ requirement: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ~>
117
+ - !ruby/object:Gem::Version
118
+ version: '2.0'
119
+ type: :development
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ~>
124
+ - !ruby/object:Gem::Version
125
+ version: '2.0'
126
+ - !ruby/object:Gem::Dependency
127
+ name: sqlite3
128
+ requirement: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - ! '>='
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ type: :development
134
+ prerelease: false
135
+ version_requirements: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ! '>='
138
+ - !ruby/object:Gem::Version
139
+ version: '0'
140
+ description: An engine that provides common status polling endpoint.
141
+ email:
142
+ - ''
143
+ executables: []
144
+ extensions: []
145
+ extra_rdoc_files: []
146
+ files:
147
+ - .gitignore
148
+ - .rspec
149
+ - .travis.yml
150
+ - Appraisals
151
+ - CHANGELOG.md
152
+ - Gemfile
153
+ - LICENSE.txt
154
+ - README.md
155
+ - Rakefile
156
+ - app/controllers/statuses_controller.rb
157
+ - config.ru
158
+ - config/locales/en.yml
159
+ - config/routes.rb
160
+ - gemfiles/rails3.1.gemfile
161
+ - gemfiles/rails3.2.gemfile
162
+ - lib/rapporteur.rb
163
+ - lib/rapporteur/checker.rb
164
+ - lib/rapporteur/checks.rb
165
+ - lib/rapporteur/checks/active_record_check.rb
166
+ - lib/rapporteur/engine.rb
167
+ - lib/rapporteur/responder.rb
168
+ - lib/rapporteur/revision.rb
169
+ - lib/rapporteur/rspec.rb
170
+ - lib/rapporteur/serializer.rb
171
+ - lib/rapporteur/version.rb
172
+ - rapporteur.gemspec
173
+ - spec/internal/config/database.yml
174
+ - spec/internal/config/routes.rb
175
+ - spec/internal/db/schema.rb
176
+ - spec/internal/log/.gitignore
177
+ - spec/internal/public/favicon.ico
178
+ - spec/requests/active_record_check_spec.rb
179
+ - spec/requests/no_checks_spec.rb
180
+ - spec/routing/routes_spec.rb
181
+ - spec/spec_helper.rb
182
+ homepage: ''
183
+ licenses:
184
+ - MIT
185
+ metadata: {}
186
+ post_install_message:
187
+ rdoc_options: []
188
+ require_paths:
189
+ - lib
190
+ required_ruby_version: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - ! '>='
193
+ - !ruby/object:Gem::Version
194
+ version: '0'
195
+ required_rubygems_version: !ruby/object:Gem::Requirement
196
+ requirements:
197
+ - - ! '>='
198
+ - !ruby/object:Gem::Version
199
+ version: '0'
200
+ requirements: []
201
+ rubyforge_project:
202
+ rubygems_version: 2.0.3
203
+ signing_key:
204
+ specification_version: 4
205
+ summary: An engine that provides common status polling endpoint.
206
+ test_files:
207
+ - spec/internal/config/database.yml
208
+ - spec/internal/config/routes.rb
209
+ - spec/internal/db/schema.rb
210
+ - spec/internal/log/.gitignore
211
+ - spec/internal/public/favicon.ico
212
+ - spec/requests/active_record_check_spec.rb
213
+ - spec/requests/no_checks_spec.rb
214
+ - spec/routing/routes_spec.rb
215
+ - spec/spec_helper.rb