- Is it up?
- Can it connect to the database(s)?
- Can it connect to the web service(s)?
- Can it do any other actions that may independently break?
- What are the server settings?
- What version of the code is running?
Here's how I've accomplished this on a Ruby on Rails project.
Single Location
First, I created a controller with a single page:
prompt> rails generate controller Admin index
Here is the beginning of the controller class.class AdminController < ApplicationController before_filter :require_admin def index end endAs you can see, I've protected it, so only administrative users can view this page. Here is the views/admin/index.html.haml where I show server state.
This is the status page. %br %h2 Version %pre= @version %h2 Environment %br %b RAILS_ENV: = ENV['RAILS_ENV'] %br %hr %h2 Site Tests .test = button_to "Test DB", {:action=>"test_db"}, :remote=>true, :onClick=>"startTest()" %hr %h2 Test Output #testOutput :javascript function startTest() { $("#testOutput").replaceWith('<div id="testOutput">Loading...</div>'); }
Dependency Tests
I've implemented each test as a separate Ajax call. In the view code above, this everything from "Site Tests" on down. This consists of the buttons (one for each test, just one here), a place to show the output, and the javascript to make this work. For each test, I just add a new button in the .test div. As you can see in the code above, the button makes an Ajax call (:remote=>true) and calls a javascript function to show that the result is loading. It is up to the controller to then update the testOutput div with output status.
In my admin_controller.rb I have a function for each button that looks like:
def test_db standard_test do # insert test code here end endThe helper function standard_test looks like:
def standard_test begin yield @success = true rescue Exception => e @success = false @exception = e end respond_to do |format| format.html { flash[:error] = "This should've been ajax" redirect_to admin_index_path } format.js { render 'test_output', :layout=>false } end endAll it does is executes the test code (via the yield statement) and catches any thrown exceptions. If there is no exception, it considers the test a success. Assuming it was called via an Ajax call, it then renders the javascript template test_output.js.haml which is simply:
!= "$('#testOutput').replaceWith('#{escape_javascript render(:partial=>'test_output')}')"As you can see, this merely replaces the testOutput div with what is rendered by the _test_output.html.haml partial:
#testOutput - if @success %b SUCCESS - else %b ERROR %br %b Error Class: = @exception.class %br %b Error Message: %pre= @exception.message %b Error Stack Trace: %pre - @exception.backtrace.each do |line| = line %b Error Inspect %pre= @exception.inspectOf course, don't forget to make sure your routes are in your config/routes.rb.
get 'admin/index' post 'admin/my_test' # separate route for each testVersion
Including version information is going to be very specific to your environment. We use Mercurial for our version control, and since we have a number of Java project, we use ant for our deployment process. Here is how I connected these together.
In the ant deployment script, I added a target that looks like:
<target name="write.hg.version"> <exec executable="hg" dir="${project}" output="${project}/config/version.txt"> <arg value="summary" /> </exec> </target>All that is left is to get the contents of this version.txt file into the @version variable that is displayed by index.html.haml. This is done by simply having the index method in admin_controller.rb read in the file.
def index name = File.join(RAILS_ROOT, 'config', 'version.txt') if File.exists? name f = File.new(name) @version = f.read else @version = "Unknown version" end endConclusion
This really wasn't too much work, and now I have a single page that I can go to and at a glance see what version of the code was deployed and which rails environment is being used. Adding new tests is just a simple matter of adding a new button to the view, which calls a new test method in the controller. By leveraging the standard_test method, new tests can consist of just the code they are intended to test.