ServerspecExtendedTypes
serverspec-extended-types provides some purpose-specific types to be used with serverspec 2.x for
testing various things on a host, as well as some types for high-level integration tests that make actual requests against
services on the host.
Current types include:
- A
virtualenv
type to make expectations about a Python Virtualenv, its pip
and python
versions, and packages
installed in it. This also works for system-wide Python if pip
is installed. - A
http_get
type to perform an HTTP GET request (specifying a port number, the Host:
header to set, and the path
to request) and make expectations about whether the request times out, its status code, headers, response body, and
JSON content (if the response body is parsable as JSON). - A
bitlbee
type to actually connect via IRC to a running bitlbee IRC gateway and authenticate
to it, and make expectations that the connection and authentication worked, and what version of Bitlbee is running.
This is in no way associated with or endorsed by the SeverSpec project or its developers. (When I proposed that they include
a HTTP request type, I was told that was "using [serverspec] wrong", and the GitHub issue was deleted). I imagine that,
at the least, they'd tell me that (1) these should be in SpecInfra, and (2) these aren't "proper" things for ServerSpec
to test. That being said, these are useful to me, for my purposes. I hope they're also useful to someone else.
Installation
Add this line to your application's Gemfile:
gem 'serverspec-extended-types'
And then execute:
$ bundle
Or install it yourself as:
$ gem install serverspec-extended-types
Requirements
Usage
In your spec_helper, add a line like:
require 'serverspec_extended_types'
Then use the various types that this gem provides:
Types
bitlbee
The bitlbee type allows testing connectivity to a bitlbee IRC gateway server.
describe bitlbee(port, nick, password, use_ssl=false) do
# matchers here
end
All server communication happens during instantiation of the type; when describe bitlbee()
is executed,
the type will attempt to connect to the server (with a timeout of 10 seconds) and authenticate as
the specified user, and store a number of state variables for later use by the various matchers.
This type supports SSL, but connects to the server without verifying certificates.
Parameters:
- port - integer port number to connect to
- nick - nick/username to login as
- password - the password for nick
- use_ssl - Boolean, whether or not to use SSL; defaults to false
Matchers
connectable?
True if the test was able to successfully connect and authenticate, false otherwise.
describe bitlbee(port, nick, password) do
it { should be_connectable }
end
timed_out?
True if the connection is aborted by a timeout, false otherwise.
describe bitlbee(port, nick, password) do
it { should_not be_timed_out }
end
version
Returns the Bitlbee version String.
describe bitlbee(port, nick, password) do
its(:version) { should match /3\.\d+\.\d+ Linux/ }
end
http_get
The http_get type performs an HTTP GET from the local (rspec runner) system, against
the IP address that serverspec is running against (ENV[TARGET_HOST]
), with a
specified Host
header value. The request is wrapped in a configurable-length timeout.
describe http_get(port, host_header, path, timeout_sec=10, protocol='http', bypass_ssl_verify=false)
# matchers here
end
All server communication happens during instantiation of the type; when describe http_get()
is executed,
the type will attempt to issue the GET request with a default timeout of 10 seconds, and store a number of
state variables for later use by the various matchers.
Parameters
- port - the port to make the HTTP request to
- host_header - the
Host
header value to provide in the request - path - the path to request from the server
- timeout_sec - timeout in seconds before canceling the request (Int; default 10)
- protocol - protocol to be used (default to
http
, can be http
) - bypass_ssl_verify - bypass SSL verification (default to
false
to keep good security. Set it to true
for self-signed certificates only!)
Matchers
body
Returns the String body content of the HTTP response.
describe http_get(80, 'myhostname', '/') do
its(:body) { should match /<html>/ }
end
Returns the HTTP response headers as a hash.
describe http_get(80, 'myhostname', '/') do
its(:headers) { should include('HeaderName' => /value regex/) }
end
json
If the response body is deserializable as JSON, contains the JSON hash,
otherwise an empty hash.
describe http_get(80, 'myhostname', '/') do
its(:json) { should include('Key' => /value regex/) }
end
status
Returns the HTTP status code, or 0 if timed out.
describe http_get(80, 'myhostname', '/') do
its(:status) { should eq 200 }
end
timed_out?
True if the request timed out, false otherwise.
describe http_get(80, 'myhostname', '/') do
it { should_not be_timed_out }
end
redirected?
True if the request was redirected, false otherwise.
describe http_get(80, 'myhostname', '/') do
it { should be_redirected }
end
redirected_to?
True if the request was redirected to the specified location, false otherwise.
describe http_get(80, 'myhostname', '/') do
it { should be_redirected_to 'https://myhostname/newpath' }
end
describe http_get(80, 'myhostname', '/') do
it { should be_redirected_to 'http://mynewhost/' }
end
virtualenv
The virtualenv type has various matchers for testing the state and content of a
Python virtualenv. It executes commands
via the builtin serverspec/specinfra command execution (i.e. uses the same backend
code that the built-in command
and file
types use).
describe virtualenv('/path/to/venv') do
# matchers here
end
Unlike the http_get
and bitlbee
types, execution of the virtualenv
type
commands is triggered by the matchers rather than the describe
clause.
Parameters
- name - the absolute path to the root of the virtualenv on the filesystem
Matchers
pip_freeze
Return a hash of all packages present in pip freeze
output for the venv
Note that any editable packages (-e something
) are returned as hash keys
with an empty value.
describe virtualenv('/path/to/venv') do
its(:pip_freeze) { should include('wsgiref' => '0.1.2') }
its(:pip_freeze) { should include('requests') }
its(:pip_freeze) { should include('pytest' => /^2\.6/) }
its(:pip_freeze) { should include('-e git+git@github.com:jantman/someproject.git@1d8a380e3af9d081081d7ef685979200a7db4130#egg=someproject') }
end
pip_version
Return the version of pip installed in the virtualenv
describe virtualenv('/path/to/venv') do
its(:pip_version) { should match /^6\.0\.6$/ }
end
python_version
Return the version of python installed in the virtualenv
describe virtualenv('/path/to/venv') do
its(:python_version) { should match /^2\.7\.9$/ }
end
virtualenv?
Test whether this appears to be a working venv
describe virtualenv('/path/to/venv') do
it { should be_virtualenv }
end
Tests performed:
- venv_path/bin/pip executable by owner?
- venv_path/bin/python executable by owner?
- venv_path/bin/activate readable by owner?
- 'export VIRTUAL_ENV' in venv_path/bin/activate?
Contributing
- Fork it ( https://github.com/jantman/serverspec-extended-types/fork )
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create a new Pull Request
Testing
Spec tests are done automatically via Travis CI. They're run using Bundler and rspec.
For manual testing:
bundle install
bundle exec rake test
Releasing
- Ensure all tests are passing, coverage is acceptable, etc.
- Increment the version number in
lib/serverspec_extended_types/version.rb
- Update CHANGES.md
- Push those changes to origin.
bundle exec rake build
bundle exec rake release