rspec-system 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -32,7 +32,7 @@ Start by creating a helper file in `spec/spec_helper_system.rb` containing somet
32
32
  c.system_setup_block = proc do
33
33
  include RSpecSystem::Helpers
34
34
  # Insert some setup tasks here
35
- run('main', 'yum install -y ntp')
35
+ system_run('yum install -y ntp')
36
36
  end
37
37
  end
38
38
 
@@ -42,8 +42,8 @@ Create the directory `spec/system` in your project, make sure your unit tests go
42
42
 
43
43
  describe 'basics' do
44
44
  it 'should cat /etc/resolv.conf' do
45
- run('main', 'cat /etc/resolv.conf') do |status,stdout,stderr|
46
- stdout.should =~ /localhost/
45
+ system_run('cat /etc/resolv.conf') do |s,o,e|
46
+ o.should =~ /localhost/
47
47
  end
48
48
  end
49
49
  end
@@ -63,23 +63,38 @@ That will setup the rake task `rake spec:system`.
63
63
 
64
64
  ### Creating a nodeset file
65
65
 
66
- A nodeset file outlines all the node configurations for your tests. The concept here is to define one or more 'nodesets' each nodeset containing one or more 'nodes'.
66
+ A nodeset file outlines all the node configurations for your tests. The concept here is to define one or more 'nodesets' each nodeset containing one or more 'nodes'. Create the file in your projects root directory as `.nodeset.yml`.
67
67
 
68
68
  ---
69
69
  default_set: 'centos-58-x64'
70
70
  sets:
71
71
  'centos-58-x64':
72
72
  nodes:
73
- "main":
73
+ 'main.vm':
74
74
  prefab: 'centos-58-x64'
75
+ 'debian-606-x64':
76
+ nodes:
77
+ 'main.vm':
78
+ prefab: 'debian-606-x64'
75
79
 
76
80
  The file must adhere to the Kwalify schema supplied in `resources/kwalify-schemas/nodeset_schema.yml`.
77
81
 
82
+ * `sets`: Each set contains a series of nodes, and is given a unique name. You can create sets with only 1 node if you like.
83
+ * `sets -> [setname] -> nodes`: Node definitions for a set. Each node needs a unique name so you can address each one individualy if you like.
84
+ * `sets -> [setname] -> nodes -> [name] -> prefab`: This relates to the prefabricated node template you wish to use. Currently this is the only way to launch a node. Look in `resources/prefabs.yml` for more details.
85
+ * `default_set`: this is the default set to run if none are provided with `rake spec:system`. This should be the most common platform normally.
86
+
78
87
  ### Prefabs
79
88
 
80
- Prefabs are 'pre-rolled' virtual images, for now its the only way to do it.
89
+ Prefabs are 'pre-rolled' virtual images, for now its the only way to specify a template. In the future we will probably allow you to specify your own prefab file, and override prefab settings in a nodeset file as well.
90
+
91
+ The current built-in prefabs are defined in `resources/prefabs.yml`. The current set are based on boxes hosted on <http://puppet-vagrant-boxes.puppetlabs.com> as they have been built by myself and are generally trusted and have a reproducable build cycle (they aren't just 'golden images'). In the future I'll probably expand that list, but attempt to stick to boxes that we have control over.
92
+
93
+ Prefabs are designed to be generic across different hosting environments. For example, you should be able to use a prefab string and launch an EC2 or Vagrant image and find that the images are identical (or as much as possible). The goal should be that local Vagrant users should find their own local tests pass, and when submitting code this should not change for EC2.
94
+
95
+ For this reason there are various `provider_specific` settings that apply to different provider types. For now though, only `vagrant` specific settings are provided.
81
96
 
82
- The current prefabs are defined in `resources/prefabs.yml`.
97
+ `facts` in the prefab are literally dumps of `facter -p` on the host stored in the prefab file so you can look them up without addressing the machine. These are accessed using the `system_node#facts` method on the helper results and can be used in conditional logic during test runs and setup tasks. Not all the facts are supplied, only the more interesting ones.
83
98
 
84
99
  ### Running tests
85
100
 
@@ -89,8 +104,8 @@ Run the system tests with:
89
104
 
90
105
  Instead of switches, we use a number of environment variables to modify the behaviour of running tests. This is more inline with the way testing frameworks like Jenkins work, and should be pretty easy for command line users as well:
91
106
 
92
- * *RSPEC_VIRTUAL_ENV* - the type of virtual environment to run (currently `vagrant` is the only option)
93
- * *RSPEC_SET* - the set to use when running tests (defaults to the `default_set` setting in the projects `.nodeset.yml` file)
107
+ * *RSPEC_VIRTUAL_ENV* - the type of virtual environment to run (currently `vagrant` is the only option). I'm undecided about this variable, so assume it might change in the future.
108
+ * *RSPEC_SET* - the set to use when running tests (defaults to the `default_set` setting in the projects `.nodeset.yml` file). This string must align with the entries under `sets` in your `.nodeset.yml`.
94
109
 
95
110
  So if you wanted to run an alternate nodeset you could use:
96
111
 
@@ -102,16 +117,17 @@ In Jenkins you should be able to use RSPEC\_SET in a test matrix, thus obtaining
102
117
 
103
118
  I want to start an eco-system of plugins for rspec-system, but do it in a sane way. Right now I see the following potential plugin types, if you think you can help please do:
104
119
 
105
- * nodes providers - that is, abstractions around other virtualisation tools. Right now a NodeSet is tied to a virtual type, but I think this isn't granual enough.
120
+ * node providers - that is, abstractions around other virtualisation, cloud or system tools. Right now a NodeSet is tied to a virtual type, but I think this isn't granual enough. Some ideas for future providers are:
106
121
  * blimpy - for firing up EC2 and OpenStack nodes, useful for Jenkins integration
107
- * vmware - for those who have VMWare virtual 'clouds' or boxen
108
- * razor - for launching hardware nodes.
109
- * manual - not everything has to be 'launched' I can see a need for defining a static configuration for older machines that can't be poked and peeked.
122
+ * vmware vsphere - for those who have VMWare vSphere deployed already, this would be an awesome bonus.
123
+ * razor - for launching bare metail nodes for testing purposes. Could be really useful to have baremetal tests for software that needs it like `facter`.
124
+ * manual - not everything has to be 'launched' I can see a need for defining a static configuration for older machines that can't be poked and peeked. Of course, we might need to add cleanup tasks for this case.
110
125
  * helper libraries - libraries that provide test helpers, and setup helpers for testing development on the software in question.
111
126
  * distro - helpers that wrap common linux distro tasks, like package installation.
112
- * puppet - helpers around installing different versions of puppet, PE as well - firing up masters. Perfect for testing modules I think.
127
+ * puppet - helpers around installing different versions of puppet, PE as well - firing up masters. Perfect for testing modules I think. Puppet could be used a provisioner for setting up tests, as using shell commands for this purpose is a bit rough, not very idepotent and is re-inventing the wheel.
113
128
  * mcollective - for launching the basics, activemq, broker clusters. Useful for testing mcollective agents.
114
- * puppetdb - helpers for setting up puppetdb, probably using the modules.
129
+ * puppetdb - helpers for setting up puppetdb, probably using the modules we already have.
130
+ * other config management tools - for the purposes of testing modules against them, or using them for test setup provisioners like I've mentioned before with Puppet.
115
131
  * others I'm sure ...
116
132
 
117
133
  These could be shipped as external gems, and plugged in to the rspec-system framework somehow.
@@ -1,6 +1,16 @@
1
1
  require "rspec/core/formatters/base_text_formatter"
2
2
 
3
3
  module RSpecSystem
4
+ # This custom formatter is designed for rspec-system test presentation
5
+ #
6
+ # Because rspec-system tests are often wordier and require lots of diagnostic
7
+ # information to be enabled for future debugging, the traditional document
8
+ # and progress formatters just simply aren't sufficient.
9
+ #
10
+ # This formatter instead treats each test as a document section, splitting
11
+ # up the output with obvious breaks so the user can clearly see when a test
12
+ # has started and finished. It also attempts to use color for visibility
13
+ # as well as listing test case information in a more verbose way.
4
14
  class Formatter < RSpec::Core::Formatters::BaseTextFormatter
5
15
  def initialize(output)
6
16
  super(output)
@@ -1,47 +1,86 @@
1
1
  # This module contains the main rspec helpers that are to be used within
2
- # rspec-system tests.
3
- #
4
- # The methods here-in are accessible within your rspec tests and can also
5
- # be used within your setup blocks as well.
2
+ # rspec-system tests. These are the meat-and-potatoes of your system tests,
3
+ # and in theory there shouldn't be anything you can't do without the helpers
4
+ # here.
6
5
  #
7
6
  # These helpers in particular are core to the framework. You can however
8
- # combined these helpers to create your own more powerful helpers in rspec
7
+ # combine these helpers to create your own more powerful helpers in rspec
9
8
  # if you wish.
10
9
  #
10
+ # The helpers themselves are split into two main groups, Queries:
11
+ #
12
+ # * +system_node+ - queries and returns node information
13
+ #
14
+ # And Actions:
15
+ #
16
+ # * +system_run+ - runs a command on a node
17
+ # * +system_rcp+ - remote copies to a node
18
+ #
11
19
  # @example Using run within your tests
12
20
  # describe 'test running' do
13
21
  # it 'run cat' do
14
- # run 'cat /etc/resolv.conf' do |status, out, err|
15
- # status.exitstatus.should == 0
16
- # stdout.should =~ /localhost/
22
+ # system_run 'cat /etc/resolv.conf' do |s, o, e|
23
+ # s.exitstatus.should == 0
24
+ # o.should =~ /localhost/
17
25
  # end
18
26
  # end
19
27
  # end
20
28
  # @example Using rcp in your tests
21
29
  # describe 'test running' do
22
30
  # it 'copy my files' do
23
- # rcp :sp => 'mydata', :dp => '/srv/data'.should be_true
31
+ # system_rcp :sp => 'mydata', :dp => '/srv/data'.should be_true
24
32
  # end
25
33
  # end
26
34
  # @example Using node in your tests
27
35
  # describe 'test running' do
28
36
  # it 'do something if redhat' do
29
- # if node.facts[:operatingsystem] == 'RedHat' do
30
- # run 'cat /etc/redhat-release'
37
+ # if system_node.facts['operatingsystem'] == 'RedHat' do
38
+ # system_run 'cat /etc/redhat-release'
39
+ # end
40
+ # end
41
+ # end
42
+ # @example Make your own helper
43
+ # describe 'my own helper' do
44
+ # def install_puppet
45
+ # facts = system_node.facts
46
+ #
47
+ # # Grab PL repository and install PL copy of puppet
48
+ # if facts['osfamily'] == 'RedHat'
49
+ # system_run('rpm -ivh http://yum.puppetlabs.com/el/5/products/i386/puppetlabs-release-5-6.noarch.rpm')
50
+ # system_run('yum install -y puppet')
51
+ # elsif facts['osfamily'] == 'Debian'
52
+ # system_run("wget http://apt.puppetlabs.com/puppetlabs-release-#{facts['lsbdistcodename']}.deb")
53
+ # system_run("dpkg -i puppetlabs-release-#{facts['lsbdistcodename']}.deb")
54
+ # system_run('apt-get update')
55
+ # system_run('apt-get install -y puppet')
56
+ # end
57
+ # end
58
+ #
59
+ # it 'test installing latest puppet' do
60
+ # install_puppet
61
+ # system_run('puppet apply --version') do |s, o, e|
62
+ # s.exitstatus == 0
63
+ # o.should =~ /3.1/
64
+ # e.should == ''
31
65
  # end
32
66
  # end
33
67
  # end
34
68
  module RSpecSystem::Helpers
35
69
  # @!group Actions
36
70
 
37
- # Runs a shell command on a test host, returning status, stdout and stderr.
71
+ # Runs a shell command on a test host.
38
72
  #
39
73
  # When invoked as a block the status,stdout and stderr are yielded to the
40
- # block as parameters.
74
+ # block as parameters. If not these three variables are returned to the
75
+ # caller.
41
76
  #
42
77
  # If you have only provided 1 node in your nodeset, or you have specified a
43
78
  # a default you can avoid entering the name of the node if you wish.
44
79
  #
80
+ # The underlying implementation is actually performed by the particular
81
+ # node provider, however this abstraction should mean you shouldn't need
82
+ # to worry about that.
83
+ #
45
84
  # @api public
46
85
  # @param options [Hash, String] options for command execution, if passed a
47
86
  # string it will just use that for the command instead as a convenience.
@@ -58,15 +97,17 @@ module RSpecSystem::Helpers
58
97
  # @yieldparam stderr [String] the standard error of the command result
59
98
  # @return [Array<Process::Status,String,String>] returns status, stdout and
60
99
  # stderr when called as a simple method.
61
- def run(options)
100
+ def system_run(options)
62
101
  ns = rspec_system_node_set
63
102
  dn = ns.default_node
64
103
 
65
- # Take options as a string instead
104
+ # If options is a string, turn the string into a command in the normal
105
+ # options hash.
66
106
  if options.is_a?(String)
67
107
  options = {:c => options}
68
108
  end
69
109
 
110
+ # Defaults etc.
70
111
  options = {
71
112
  :node => options[:n] || dn,
72
113
  :n => options[:node] || dn,
@@ -75,12 +116,12 @@ module RSpecSystem::Helpers
75
116
  }.merge(options)
76
117
 
77
118
  if options[:c].nil?
78
- raise "Cannot use run with no :command option"
119
+ raise "Cannot use system_run with no :command option"
79
120
  end
80
121
 
81
- log.info("run #{options[:c]} on #{options[:n].name} executed")
122
+ log.info("system_run #{options[:c]} on #{options[:n].name} executed")
82
123
  status, stdout, stderr = result = ns.run(options)
83
- log.info("run results:\n" +
124
+ log.info("system_run results:\n" +
84
125
  "-----------------------\n" +
85
126
  "Exit Status: #{status.exitstatus}\n" +
86
127
  "<stdout>#{stdout}</stdout>\n" +
@@ -94,14 +135,15 @@ module RSpecSystem::Helpers
94
135
  end
95
136
  end
96
137
 
97
- # Remotely copy files to a test node. This will use the underlying nodes
98
- # rcp mechanism to do the transfer for you, so you generally shouldn't
99
- # need to consider the implementation.
138
+ # Remotely copy files to a test node
139
+ #
140
+ # Just specify a source path, destination path, and optionally a destination
141
+ # node (if the default isn't enough) and go.
100
142
  #
101
- # Just specify a source, and a destination path, and go.
143
+ # The underlying implementation is actually performed by the particular
144
+ # node provider, however this abstraction should mean you shouldn't need
145
+ # to worry about that.
102
146
  #
103
- # @example Remote copy /srv/data to remote host
104
- # rcp(:dest_path => '/srv/data', :source_path => 'mydata')
105
147
  # @param options [Hash] options for command execution
106
148
  # @option options [String] :source_path source to copy files from (currently
107
149
  # only locally)
@@ -115,10 +157,7 @@ module RSpecSystem::Helpers
115
157
  # for future use. Patches welcome.
116
158
  # @option options [RSpecSystem::Node] :s alias for source_node
117
159
  # @return [Bool] returns true if successful
118
- # @todo Need to create some helpers for validating input and creating default,
119
- # aliases and bloody yarddocs from some other magic format. Ideas?
120
- # @todo Support system to system copy using source_node option.
121
- def rcp(options)
160
+ def system_rcp(options)
122
161
  options = {
123
162
  :source_path => options[:sp],
124
163
  :destination_path => options[:dp],
@@ -126,15 +165,15 @@ module RSpecSystem::Helpers
126
165
  :sp => options[:source_path],
127
166
  :destination_node => rspec_system_node_set.default_node,
128
167
  :d => rspec_system_node_set.default_node,
129
- :source_node => '',
130
- :s => '',
168
+ :source_node => nil,
169
+ :s => nil,
131
170
  }.merge(options)
132
171
 
133
172
  d = options[:d]
134
173
  sp = options[:sp]
135
174
  dp = options[:dp]
136
175
 
137
- log.info("rcp from #{sp} to #{d.name}:#{dp} executed")
176
+ log.info("system_rcp from #{sp} to #{d.name}:#{dp} executed")
138
177
  status, stdout, stderr = results = rspec_system_node_set.rcp(options)
139
178
  log.info("rcp results:\n" +
140
179
  "-----------------------\n" +
@@ -160,16 +199,18 @@ module RSpecSystem::Helpers
160
199
  # @param options [Hash] search criteria
161
200
  # @option options [String] :name the canonical name of the node
162
201
  # @return [RSpecSystem::Node] node object
163
- def node(options = {})
202
+ def system_node(options = {})
164
203
  ns = rspec_system_node_set
165
204
  options = {
166
- :name => ns.default_node,
205
+ :name => ns.default_node.name,
167
206
  }.merge(options)
168
207
 
169
- if !options[:name].nil?
170
- return ns.nodes[options[:name]]
208
+ name = options[:name]
209
+
210
+ if name.nil?
211
+ raise "No nodes search specified, and no default"
171
212
  else
172
- raise "No nodes to return"
213
+ return ns.nodes[name]
173
214
  end
174
215
  end
175
216
  end
@@ -1,6 +1,10 @@
1
1
  require 'logger'
2
2
 
3
+ # This log overlay module, provides access to the +log+ method.
3
4
  module RSpecSystem::Log
5
+ # Return the default Logger object.
6
+ #
7
+ # @return [Logger] default logger object
4
8
  def log
5
9
  return @logger if @logger
6
10
  @logger = ::Logger.new(STDOUT)
data/rspec-system.gemspec CHANGED
@@ -2,7 +2,7 @@
2
2
  Gem::Specification.new do |s|
3
3
  # Metadata
4
4
  s.name = "rspec-system"
5
- s.version = "0.1.1"
5
+ s.version = "0.1.2"
6
6
  s.authors = ["Ken Barber"]
7
7
  s.email = ["ken@bob.sh"]
8
8
  s.homepage = "https://github.com/kbarber/rspec-system"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspec-system
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors: