serverspec-extended-types 0.0.1

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,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ YjhlYTA0NzY0NDE2NGRlOTJkMTcwNGQ3NTcwOTI3NTQwZWQ4OTE0ZQ==
5
+ data.tar.gz: !binary |-
6
+ MDNiOTI1NDg4NzRjY2RhNGQ0YjRjNmQ4OGY2ZTNlMmI4MmFkMjFlMQ==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ NThiNGVmZTM5NWY5Y2EyMDNjMzg3ZmVkNWVjN2RhYTZhMzQwMmMzNzQxOGFi
10
+ OGQwNDQ1ZTMyNWY5MGFiNTU0MWE5NWVkZDk1OWUzNTNjMDRiNDNkMDU1MjBi
11
+ Njc5YWJkNjg3MzlmNWVjYjQzZTQ1Nzc0MjI3ZTgwZTc2ODVkNDQ=
12
+ data.tar.gz: !binary |-
13
+ MDJkMjhlOWUyMDg3ZTczZTA4M2Q5ZGVjOGE5Y2Y0NzJiODNjYjE1M2NiMDI3
14
+ ZDY3ODA4NzlkNzVmOTU2ZDVmNjAxZjg1OTUwYzVhOGU5ZWM0Yzk2MmIwODdk
15
+ MWFkMjE3NjRhYzljOGE4MTdhZjYwNzhhOTIyMzNjMDE5ODYyZjE=
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
@@ -0,0 +1,13 @@
1
+ ---
2
+ language: ruby
3
+ before_install:
4
+ - gem install bundler
5
+ install: bundle install
6
+ script: bundle exec rake test
7
+ notifications:
8
+ email: true
9
+ rvm:
10
+ - 2.0.0
11
+ env:
12
+ global:
13
+ - NOKOGIRI_USE_SYSTEM_LIBRARIES=true
@@ -0,0 +1 @@
1
+ --private
@@ -0,0 +1,5 @@
1
+ # serverspec-extended-types, changelog
2
+
3
+ ## 0.0.1 2015-03-14 Jason Antman <jason@jasonantman.com>
4
+
5
+ * Initial release with bitlbee, http_get and virtualenv types
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in serverspec-extended-types.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Jason Antman
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.
@@ -0,0 +1,249 @@
1
+ # ServerspecExtendedTypes
2
+
3
+ [![Build Status](https://travis-ci.org/jantman/serverspec-extended-types.svg?branch=master)](https://travis-ci.org/jantman/serverspec-extended-types)
4
+ [![Code Coverage](https://codecov.io/github/jantman/serverspec-extended-types/coverage.svg?branch=master)](https://codecov.io/github/jantman/serverspec-extended-types?branch=master)
5
+ [![Code Climate](https://codeclimate.com/github/jantman/serverspec-extended-types/badges/gpa.svg)](https://codeclimate.com/github/jantman/serverspec-extended-types)
6
+ [![Gem Version](https://img.shields.io/gem/v/serverspec-extended-types.svg)](https://rubygems.org/gems/serverspec-extended-types)
7
+ [![Total Downloads](https://img.shields.io/gem/dt/serverspec-extended-types.svg)](https://rubygems.org/gems/serverspec-extended-types)
8
+ [![Github Issues](https://img.shields.io/github/issues/jantman/serverspec-extended-types.svg)](https://github.com/jantman/serverspec-extended-types/issues)
9
+ [![Project Status: Active - The project has reached a stable, usable state and is being actively developed.](http://www.repostatus.org/badges/0.1.0/active.svg)](http://www.repostatus.org/#active)
10
+
11
+ serverspec-extended-types provides some purpose-specific types to be used with [serverspec](http://serverspec.org/) 2.x for
12
+ testing various things on a host, as well as some types for high-level integration tests that make actual requests against
13
+ services on the host.
14
+
15
+ Current types include:
16
+
17
+ * A ``virtualenv`` type to make expectations about a Python Virtualenv, its ``pip`` and ``python`` versions, and packages
18
+ installed in it. This also works for system-wide Python if ``pip`` is installed.
19
+ * A ``http_get`` type to perform an HTTP GET request (specifying a port number, the ``Host:`` header to set, and the path
20
+ to request) and make expectations about whether the request times out, its status code, headers, and response body.
21
+ * A ``bitlbee`` type to actually connect via IRC to a running [bitlbee](http://www.bitlbee.org/) IRC gateway and authenticate
22
+ to it, and make expectations that the connection and authentication worked, and what version of Bitlbee is running.
23
+
24
+ This is in no way associated with or endorsed by the SeverSpec project or its developers. (When I proposed that they include
25
+ a HTTP request type, I was told that was "using [serverspec] wrong", and the GitHub issue was deleted). I imagine that,
26
+ at the least, they'd tell me that (1) these should be in SpecInfra, and (2) these aren't "proper" things for ServerSpec
27
+ to test. That being said, these are useful to me, for my purposes. I hope they're also useful to someone else.
28
+
29
+ ## Installation
30
+
31
+ Add this line to your application's Gemfile:
32
+
33
+ gem 'serverspec-extended-types'
34
+
35
+ And then execute:
36
+
37
+ $ bundle
38
+
39
+ Or install it yourself as:
40
+
41
+ $ gem install serverspec-extended-types
42
+
43
+ ### Requirements
44
+
45
+ * [serverspec](https://rubygems.org/gems/serverspec) 2.x
46
+ * [specinfra](https://rubygems.org/gems/specinfra) 2.x
47
+
48
+ ## Usage
49
+
50
+ In your spec_helper, add a line like:
51
+
52
+ require 'serverspec_extended_types'
53
+
54
+ Then use the various types that this gem provides:
55
+
56
+ ## Types
57
+
58
+ ### bitlbee
59
+
60
+ The bitlbee type allows testing connectivity to a [bitlbee](http://www.bitlbee.org/) IRC gateway server.
61
+
62
+ describe bitlbee(port, nick, password, use_ssl=false) do
63
+ # matchers here
64
+ end
65
+
66
+ All server communication happens during instantiation of the type; when ``describe bitlbee()`` is executed,
67
+ the type will attempt to connect to the server (with a timeout of 10 seconds) and authenticate as
68
+ the specified user, and store a number of state variables for later use by the various matchers.
69
+
70
+ This type supports SSL, but connects to the server without verifying certificates.
71
+
72
+ #### Parameters:
73
+
74
+ * __port__ - integer port number to connect to
75
+ * __nick__ - nick/username to login as
76
+ * __password__ - the password for nick
77
+ * __use_ssl__ - Boolean, whether or not to use SSL; defaults to false
78
+
79
+ #### Matchers
80
+
81
+ ##### connectable?
82
+
83
+ True if the test was able to successfully connect and authenticate, false otherwise.
84
+
85
+ describe bitlbee(port, nick, password) do
86
+ it { should be_connectable }
87
+ end
88
+
89
+ ##### timed_out?
90
+
91
+ True if the connection is aborted by a timeout, false otherwise.
92
+
93
+ describe bitlbee(port, nick, password) do
94
+ it { should_not be_timed_out }
95
+ end
96
+
97
+ ##### version
98
+
99
+ Returns the Bitlbee version String.
100
+
101
+ describe bitlbee(port, nick, password) do
102
+ its(:version) { should match /3\.\d+\.\d+ Linux/ }
103
+ end
104
+
105
+ ### http_get
106
+
107
+ The http_get type performs an HTTP GET from the local (rspec runner) system, against
108
+ the IP address that serverspec is running against (``ENV[TARGET_HOST]``), with a
109
+ specified ``Host`` header value. The request is wrapped in a configurable-length timeout.
110
+
111
+ describe http_get(port, host_header, path, timeout_sec=10)
112
+ # matchers here
113
+ end
114
+
115
+ All server communication happens during instantiation of the type; when ``describe http_get()`` is executed,
116
+ the type will attempt to issue the GET request with a default timeout of 10 seconds, and store a number of
117
+ state variables for later use by the various matchers.
118
+
119
+ #### Parameters
120
+
121
+ * __port__ - the port to make the HTTP request to
122
+ * __host_header__ - the ``Host`` header value to provide in the request
123
+ * __path__ - the path to request from the server
124
+ * __timeout_sec__ - timeout in seconds before canceling the request (Int; default 10)
125
+
126
+ #### Matchers
127
+
128
+ ##### body
129
+
130
+ Returns the String body content of the HTTP response.
131
+
132
+ describe http_get(80, 'myhostname', '/') do
133
+ its(:body) { should match /<html>/ }
134
+ end
135
+
136
+ ##### headers
137
+
138
+ Returns the HTTP response headers as a hash.
139
+
140
+ describe http_get(80, 'myhostname', '/') do
141
+ its(:headers) { should include('HeaderName' => /value regex/) }
142
+ end
143
+
144
+ ##### status
145
+
146
+ Returns the HTTP status code, or 0 if timed out.
147
+
148
+ describe http_get(80, 'myhostname', '/') do
149
+ its(:status) { should eq 200 }
150
+ end
151
+
152
+ ##### timed_out?
153
+
154
+ True if the request timed out, false otherwise.
155
+
156
+ describe http_get(80, 'myhostname', '/') do
157
+ it { should_not be_timed_out }
158
+ end
159
+
160
+ ### virtualenv
161
+
162
+ The virtualenv type has various matchers for testing the state and content of a
163
+ Python [virtualenv](https://virtualenv.pypa.io/en/latest/). It executes commands
164
+ via the builtin serverspec/specinfra command execution (i.e. uses the same backend
165
+ code that the built-in ``command`` and ``file`` types use).
166
+
167
+ describe virtualenv('/path/to/venv') do
168
+ # matchers here
169
+ end
170
+
171
+ Unlike the ``http_get`` and ``bitlbee`` types, execution of the ``virtualenv`` type
172
+ commands is triggered by the matchers rather than the ``describe`` clause.
173
+
174
+ #### Parameters
175
+
176
+ * __name__ - the absolute path to the root of the virtualenv on the filesystem
177
+
178
+ #### Matchers
179
+
180
+ ##### pip_freeze
181
+
182
+ Return a hash of all packages present in `pip freeze` output for the venv
183
+
184
+ Note that any editable packages (`-e something`) are returned as hash keys
185
+ with an empty value.
186
+
187
+ describe virtualenv('/path/to/venv') do
188
+ its(:pip_freeze) { should include('wsgiref' => '0.1.2') }
189
+ its(:pip_freeze) { should include('requests') }
190
+ its(:pip_freeze) { should include('pytest' => /^2\.6/) }
191
+ its(:pip_freeze) { should include('-e git+git@github.com:jantman/someproject.git@1d8a380e3af9d081081d7ef685979200a7db4130#egg=someproject') }
192
+ end
193
+
194
+ ##### pip_version
195
+
196
+ Return the version of pip installed in the virtualenv
197
+
198
+ describe virtualenv('/path/to/venv') do
199
+ its(:pip_version) { should match /^6\.0\.6$/ }
200
+ end
201
+
202
+ ##### python_version
203
+
204
+ Return the version of python installed in the virtualenv
205
+
206
+ describe virtualenv('/path/to/venv') do
207
+ its(:python_version) { should match /^2\.7\.9$/ }
208
+ end
209
+
210
+ ##### virtualenv?
211
+
212
+ Test whether this appears to be a working venv
213
+
214
+ describe virtualenv('/path/to/venv') do
215
+ it { should be_virtualenv }
216
+ end
217
+
218
+ Tests performed:
219
+
220
+ * venv_path/bin/pip executable by root?
221
+ * venv_path/bin/python executable by root?
222
+ * venv_path/bin/activate executable by root?
223
+ * 'export VIRTUAL_ENV' in venv_path/bin/activate?
224
+
225
+ ## Contributing
226
+
227
+ 1. Fork it ( https://github.com/jantman/serverspec-extended-types/fork )
228
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
229
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
230
+ 4. Push to the branch (`git push origin my-new-feature`)
231
+ 5. Create a new Pull Request
232
+
233
+ ## Testing
234
+
235
+ Spec tests are done automatically via Travis CI. They're run using Bundler and rspec.
236
+
237
+ For manual testing:
238
+
239
+ bundle install
240
+ bundle exec rake test
241
+
242
+ ## Releasing
243
+
244
+ 1. Ensure all tests are passing, coverage is acceptable, etc.
245
+ 2. Increment the version number in ``lib/serverspec_extended_types/version.rb``
246
+ 3. Update CHANGES.md
247
+ 4. Push those changes to origin.
248
+ 5. ``bundle exec rake build``
249
+ 6. ``bundle exec rake release``
@@ -0,0 +1,53 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rubygems'
3
+ require 'bundler/setup'
4
+ require 'rspec/core/rake_task'
5
+ require 'yardstick/rake/measurement'
6
+ require 'yardstick/rake/verify'
7
+ Bundler::GemHelper.install_tasks
8
+
9
+ RSpec::Core::RakeTask.new(:spec) do |t|
10
+ t.pattern = 'spec/**/*_spec.rb'
11
+ end
12
+
13
+ task :default => [:help]
14
+
15
+ desc "Display the list of available rake tasks"
16
+ task :help do
17
+ system("rake -T")
18
+ end
19
+
20
+ Yardstick::Rake::Measurement.new(:yardstick_measure) do |measurement|
21
+ measurement.output = 'measurement/report.txt'
22
+ end
23
+
24
+ Yardstick::Rake::Verify.new do |verify|
25
+ verify.threshold = 100
26
+ end
27
+
28
+ desc "Run all documentation checks"
29
+ task :checkdocs do
30
+ begin
31
+ Rake::Task['verify_measurements'].invoke()
32
+ rescue => e
33
+ # if that failed, print the report with details
34
+ puts "#{e.class}: #{e.message}"
35
+ Rake::Task['yardstick_measure'].invoke()
36
+ f = File.open('measurement/report.txt', 'r') do |f|
37
+ f.each_line do |line|
38
+ puts line
39
+ end
40
+ end
41
+ exit!(1)
42
+ end
43
+ end
44
+
45
+ YARD::Rake::YardocTask.new do |t|
46
+ t.files = ['lib/**/*.rb']
47
+ end
48
+
49
+ desc "run all CI tests"
50
+ task :test do
51
+ Rake::Task['spec'].invoke()
52
+ Rake::Task['checkdocs'].invoke()
53
+ end
@@ -0,0 +1,4 @@
1
+ require "serverspec_extended_types/version"
2
+ require 'serverspec_extended_types/bitlbee'
3
+ require 'serverspec_extended_types/http_get'
4
+ require 'serverspec_extended_types/virtualenv'
@@ -0,0 +1,204 @@
1
+ ##############################################################################
2
+ # serverspec-extended-types - bitlbee
3
+ #
4
+ # <https://github.com/jantman/serverspec-extended-types>
5
+ #
6
+ # Copyright (C) 2015 Jason Antman <jason@jasonantman.com>
7
+ #
8
+ # Licensed under the MIT License - see LICENSE.txt
9
+ #
10
+ ##############################################################################
11
+ #
12
+ # Many thanks to the blog posts that helped me with this:
13
+ # <http://ghost.ponpokopon.me/add-custom-matcher-of-serverspec/>
14
+ # <http://arlimus.github.io/articles/custom.resource.types.in.serverspec/>
15
+ #
16
+ ##############################################################################
17
+ require 'socket'
18
+ require 'openssl'
19
+ require 'timeout'
20
+ require 'serverspec'
21
+ require 'serverspec/type/base'
22
+
23
+ module Serverspec
24
+ module Type
25
+
26
+ class Bitlbee < Base
27
+
28
+ # Bitlbee constructor
29
+ #
30
+ # Connects to Bitlbee on the host specified by ENV['TARGET_HOST']
31
+ #
32
+ # @api public
33
+ #
34
+ # @example Constructor
35
+ # describe bitlbee(6697, 'nick', 'password') do
36
+ # # tests here
37
+ # end
38
+ #
39
+ # @param port [Integer] the port to connect to
40
+ # @param nick [String] the nick to connect as
41
+ # @param password [String] the password for nick
42
+ # @param use_ssl [Boolean] whether to connect with SSL
43
+ def initialize(port, nick, password, use_ssl=false)
44
+ @port = port
45
+ @host = ENV['TARGET_HOST']
46
+ @nick = nick
47
+ @use_ssl = use_ssl
48
+ @password = password
49
+ @connected_status = false
50
+ @version_str = ""
51
+ @timed_out_status = false
52
+ @started = false
53
+ end
54
+
55
+ # Begin timeout-wrapped connection
56
+ #
57
+ # This just calls {#connect} within a 10-second {Timeout::timeout} wrapper,
58
+ # and handles both timeout and {Errno::ECONNREFUSED}.
59
+ #
60
+ # @api private
61
+ # @return [nil]
62
+ def start
63
+ @started = true
64
+ begin
65
+ Timeout::timeout(10) do
66
+ @use_ssl ? ( connect_ssl ) : ( connect )
67
+ end
68
+ rescue Timeout::Error
69
+ @timed_out_status = true
70
+ rescue Errno::ECONNREFUSED
71
+ @connected_status = false
72
+ end
73
+ end
74
+
75
+ # connection to the IRC server (without SSL)
76
+ #
77
+ # @api private
78
+ # @return [nil]
79
+ def connect
80
+ @socket = TCPSocket.open(@host, @port)
81
+ communicate
82
+ @socket.puts("QUIT :\"outta here\"\n")
83
+ @socket.close
84
+ end
85
+
86
+ # Open SSL connection to the IRC server
87
+ #
88
+ # @api private
89
+ # @return [nil]
90
+ def connect_ssl
91
+ sock = TCPSocket.open(@host, @port)
92
+ ctx = OpenSSL::SSL::SSLContext.new
93
+ ctx.set_params(verify_mode: OpenSSL::SSL::VERIFY_NONE)
94
+ @socket = OpenSSL::SSL::SSLSocket.new(sock, ctx).tap do |socket|
95
+ socket.sync_close = true
96
+ socket.connect
97
+ end
98
+ communicate
99
+ @socket.puts("QUIT :\"outta here\"\n")
100
+ @socket.close
101
+ end
102
+
103
+ # Login to IRC and get version, over @socket
104
+ #
105
+ # @api private
106
+ # @return [nil]
107
+ def communicate
108
+ password = @password
109
+ nick = @nick
110
+ @socket.puts("PASS #{password}\n")
111
+ @socket.puts("NICK #{nick}\n")
112
+ @socket.puts("USER #{nick} #{nick} servername :TestUser\n")
113
+ while buf = (@socket.readpartial(1024) rescue nil )
114
+ @connected_status = true
115
+ (data||="") << buf
116
+ if data =~ /Welcome to the/
117
+ @socket.puts("MODE #{nick} +i\n")
118
+ data = ""
119
+ elsif data =~ /If you've never/
120
+ @socket.puts("PRIVMSG &bitlbee :identify #{password}\n")
121
+ data = ""
122
+ elsif data =~ /PING (\S+)/
123
+ @socket.puts(":#{$1} PONG #{$1} :#{$1}\n")
124
+ data = ""
125
+ elsif data =~ /MODE #{nick} :\+i/
126
+ break
127
+ end
128
+ end
129
+ @socket.puts("PRIVMSG root :\001VERSION\001\n")
130
+ while buf = (@socket.readpartial(1024) rescue nil )
131
+ (data||="") << buf
132
+ if data =~ /VERSION (.+)/
133
+ @version_str = $1
134
+ break
135
+ end
136
+ end
137
+ end
138
+
139
+ # Check whether the connection timed out
140
+ #
141
+ # @example serverspec test
142
+ # describe bitlbee(6697, 'myuser', 'mypass') do
143
+ # it { should_not be_timed_out }
144
+ # end
145
+ #
146
+ # @api public
147
+ # @return [Boolean]
148
+ def timed_out?
149
+ start if not @started
150
+ @timed_out_status
151
+ end
152
+
153
+ # Check whether we can successfully connect
154
+ #
155
+ # @example serverspec test
156
+ # describe bitlbee(6697, 'myuser', 'mypass') do
157
+ # it { should be_connectable }
158
+ # end
159
+ #
160
+ # @api public
161
+ # @return [Boolean]
162
+ def connectable?
163
+ start if not @started
164
+ @connected_status
165
+ end
166
+
167
+ # Return the version string from Bitlbee
168
+ #
169
+ # @example
170
+ # describe bitlbee(6697, 'myuser', 'mypass') do
171
+ # its(:version) { should match /foo/ }
172
+ # end
173
+ #
174
+ # @api public
175
+ # @return [String]
176
+ def version
177
+ start if not @started
178
+ @version_str
179
+ end
180
+
181
+ end
182
+
183
+ # Serverspec Type method for Bitlbee
184
+ #
185
+ # @example
186
+ # describe bitlbee(6697, 'myuser', 'mypass') do
187
+ # # tests here
188
+ # end
189
+ #
190
+ # @api public
191
+ #
192
+ # @param port [Integer] the port to connect to
193
+ # @param nick [String] the nick to connect as
194
+ # @param password [String] the password for nick
195
+ # @param use_ssl [Boolean] whether to connect with SSL
196
+ #
197
+ # @return {Serverspec::Type::Bitlbee} instance
198
+ def bitlbee(port, nick, password, use_ssl=false)
199
+ Bitlbee.new(port, nick, password, use_ssl)
200
+ end
201
+ end
202
+ end
203
+
204
+ include Serverspec::Type