serverspec-extended-types 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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