rspec-system 0.0.2 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,3 +1,5 @@
1
1
  Gemfile.lock
2
2
  *.gem
3
3
  .*.swp
4
+ doc/
5
+ .yardoc
data/.travis.yml ADDED
@@ -0,0 +1,13 @@
1
+ language: ruby
2
+ bundler_args: --without development
3
+ script: "rspec"
4
+ rvm:
5
+ - 1.8.7
6
+ - 1.9.3
7
+ - 2.0.0
8
+ - ruby-head
9
+ matrix:
10
+ allow_failures:
11
+ - rvm: ruby-head
12
+ notifications:
13
+ email: false
data/Gemfile CHANGED
@@ -1,3 +1,12 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
+
5
+ group :development, :test do
6
+ gem 'mocha', :require => 'mocha/api'
7
+ end
8
+
9
+ group :development do
10
+ gem 'yard'
11
+ gem 'redcarpet'
12
+ end
data/LICENSE ADDED
@@ -0,0 +1,17 @@
1
+ rspec-system - System testing using RSpec
2
+
3
+ Copyright (C) 2013 Puppet Labs Inc
4
+
5
+ Puppet Labs can be contacted at: info@puppetlabs.com
6
+
7
+ Licensed under the Apache License, Version 2.0 (the "License");
8
+ you may not use this file except in compliance with the License.
9
+ You may obtain a copy of the License at
10
+
11
+ http://www.apache.org/licenses/LICENSE-2.0
12
+
13
+ Unless required by applicable law or agreed to in writing, software
14
+ distributed under the License is distributed on an "AS IS" BASIS,
15
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ See the License for the specific language governing permissions and
17
+ limitations under the License.
data/README.md CHANGED
@@ -1,16 +1,12 @@
1
1
  # rspec-system
2
2
 
3
- System testing with rspec.
3
+ `rspec-system` provides a framework for creating system tests using the `rspec` testing library.
4
4
 
5
- * [Usage](#usage)
6
- * [Setup](#setup)
7
- * [Tests](#tests)
5
+ The goal here is to provide facilities to aid in the launching of tests nodes, copying of test content to such nodes, and executing commands on such nodes to be tested with standard rspec assertions within the standard rspec test format.
8
6
 
9
- ## Usage
7
+ *Note:* This library is fairly alpha at the moment, and the interface may change at without warning. That said, if you're good at ruby and have an opinion, I'd appreciate patches and improvements to move this further torwards stability.
10
8
 
11
- ### Setup
12
-
13
- #### Gem installation
9
+ ### Gem installation
14
10
 
15
11
  The intention is that this gem is used within your project as a development library.
16
12
 
@@ -26,20 +22,96 @@ Then installing with:
26
22
 
27
23
  bundle install
28
24
 
29
- #### Configuration
25
+ ### Writing tests
26
+
27
+ Start by creating a helper file in `spec/spec_helper_system.rb` containing something like the following:
28
+
29
+ require 'rspec-system/spec_helper'
30
+
31
+ RSpec.configure do |c|
32
+ c.system_setup_block = proc do
33
+ include RSpecSystem::Helpers
34
+ # Insert some setup tasks here
35
+ run('main', 'yum install -y ntp')
36
+ end
37
+ end
38
+
39
+ Create the directory `spec/system` in your project, make sure your unit tests go into `spec/unit` or somesuch so you can isolate them easily during test time. Add files with the spec prefix ie. `mytests_spec.rb` and make sure they always include the line `require 'spec_helper_system'` eg.:
40
+
41
+ require 'spec_helper_system'
42
+
43
+ describe 'basics' do
44
+ it 'should cat /etc/resolv.conf' do
45
+ run('main', 'cat /etc/resolv.conf') do |status,stdout,stderr|
46
+ stdout.should =~ /localhost/
47
+ end
48
+ end
49
+ end
50
+
51
+ Also consult the example in `example` in the source of this library for more details.
52
+
53
+ For you reference, here are the list of custom rspec configuration items that can be overriden in your `spec_helper_system.rb` file:
54
+
55
+ * *system_setup_block* - this accepts a proc that is called after node setup, but before every test (ie. before suite). The goal of this option is to provide a good place for node setup independant of tests.
56
+ * *system_tmp* - For some of our activity, we require a temporary file area. By default we just a random temporary path, so you normally do not need to set this.
57
+
58
+ Currently to get the nice formatting rspec-system specific formatter its recommended to use the Rake task, so the following to your `Rakefile`:
59
+
60
+ require 'rspec-system/rake_task'
30
61
 
31
- TODO: for now just look at the `examples` directory.
62
+ That will setup the rake task `rake spec:system`.
32
63
 
33
- ### Tests
64
+ ### Creating a nodeset file
34
65
 
35
- Start by looking at the `examples` directory. I plan on fleshing out this documentation but for now just use the example.
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'.
36
67
 
37
- #### Running tests
68
+ ---
69
+ default_set: 'centos-58-x64'
70
+ sets:
71
+ 'centos-58-x64':
72
+ nodes:
73
+ "main":
74
+ prefab: 'centos-58-x64'
75
+
76
+ The file must adhere to the Kwalify schema supplied in `resources/kwalify-schemas/nodeset_schema.yml`.
77
+
78
+ ### Prefabs
79
+
80
+ Prefabs are 'pre-rolled' virtual images, for now its the only way to do it.
81
+
82
+ The current prefabs are defined in `resources/prefabs.yml`.
83
+
84
+ ### Running tests
38
85
 
39
86
  Run the system tests with:
40
87
 
41
88
  rake spec:system
42
89
 
43
- #### Writing tests
90
+ 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
+
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)
94
+
95
+ So if you wanted to run an alternate nodeset you could use:
96
+
97
+ RSPEC_SET=nodeset2 rake spec:system
98
+
99
+ In Jenkins you should be able to use RSPEC\_SET in a test matrix, thus obtaining quite a nice integration and visual display of nodesets in Jenkins.
100
+
101
+ ### Plugins to rspec-system
102
+
103
+ 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
+
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.
106
+ * 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.
110
+ * helper libraries - libraries that provide test helpers, and setup helpers for testing development on the software in question.
111
+ * 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.
113
+ * mcollective - for launching the basics, activemq, broker clusters. Useful for testing mcollective agents.
114
+ * puppetdb - helpers for setting up puppetdb, probably using the modules.
115
+ * others I'm sure ...
44
116
 
45
- Create the directory `spec/system` in your project. Add files with the spec prefix ie. `mytests_spec.rb`.
117
+ These could be shipped as external gems, and plugged in to the rspec-system framework somehow.
data/lib/rspec-system.rb CHANGED
@@ -5,12 +5,14 @@ module RSpecSystem; end
5
5
  require 'rspec-system/log'
6
6
  require 'rspec-system/helpers'
7
7
  require 'rspec-system/node_set'
8
+ require 'rspec-system/prefab'
9
+ require 'rspec-system/node'
8
10
 
9
11
  RSpec::configure do |c|
10
12
  c.include RSpecSystem::Helpers
11
13
 
12
14
  # This provides a path to save vagrant files
13
15
  c.add_setting :system_tmp
14
- # Node set configuration
15
- c.add_setting :system_nodesets
16
+ # Block to execute for environment setup
17
+ c.add_setting :system_setup_block
16
18
  end
@@ -1,8 +1,175 @@
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.
6
+ #
7
+ # 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
9
+ # if you wish.
10
+ #
11
+ # @example Using run within your tests
12
+ # describe 'test running' do
13
+ # it 'run cat' do
14
+ # run 'cat /etc/resolv.conf' do |status, out, err|
15
+ # status.exitstatus.should == 0
16
+ # stdout.should =~ /localhost/
17
+ # end
18
+ # end
19
+ # end
20
+ # @example Using rcp in your tests
21
+ # describe 'test running' do
22
+ # it 'copy my files' do
23
+ # rcp :sp => 'mydata', :dp => '/srv/data'.should be_true
24
+ # end
25
+ # end
26
+ # @example Using node in your tests
27
+ # describe 'test running' do
28
+ # it 'do something if redhat' do
29
+ # if node.facts[:operatingsystem] == 'RedHat' do
30
+ # run 'cat /etc/redhat-release'
31
+ # end
32
+ # end
33
+ # end
1
34
  module RSpecSystem::Helpers
2
- def run_on(dest, command)
3
- log.info("run_on(#{dest}, #{command}) executed")
4
- result = rspec_system_node_set.run(dest, command)
5
- log.info("run_on(#{dest}, #{command}) finished\n--result--\n#{result}\n--result--\n")
6
- result
35
+ # @!group Actions
36
+
37
+ # Runs a shell command on a test host, returning status, stdout and stderr.
38
+ #
39
+ # When invoked as a block the status,stdout and stderr are yielded to the
40
+ # block as parameters.
41
+ #
42
+ # If you have only provided 1 node in your nodeset, or you have specified a
43
+ # a default you can avoid entering the name of the node if you wish.
44
+ #
45
+ # @api public
46
+ # @param options [Hash, String] options for command execution, if passed a
47
+ # string it will just use that for the command instead as a convenience.
48
+ # @option options [String] :command command to execute. Mandatory.
49
+ # @option options [String] :c alias for :command
50
+ # @option options [RSpecSystem::Node] :node (defaults to what was defined
51
+ # default in your YAML file, otherwise if there is only one node it uses
52
+ # that) specifies node to execute command on.
53
+ # @option options [RSpecSystem::Node] :n alias for :node
54
+ # @yield [status, stdout, stderr] yields status, stdout and stderr when
55
+ # called as a block.
56
+ # @yieldparam status [Process::Status] the status of the executed command
57
+ # @yieldparam stdout [String] the standard out of the command result
58
+ # @yieldparam stderr [String] the standard error of the command result
59
+ # @return [Array<Process::Status,String,String>] returns status, stdout and
60
+ # stderr when called as a simple method.
61
+ def run(options)
62
+ ns = rspec_system_node_set
63
+ dn = ns.default_node
64
+
65
+ # Take options as a string instead
66
+ if options.is_a?(String)
67
+ options = {:c => options}
68
+ end
69
+
70
+ options = {
71
+ :node => options[:n] || dn,
72
+ :n => options[:node] || dn,
73
+ :c => options[:command],
74
+ :command => options[:c],
75
+ }.merge(options)
76
+
77
+ if options[:c].nil?
78
+ raise "Cannot use run with no :command option"
79
+ end
80
+
81
+ log.info("run #{options[:c]} on #{options[:n].name} executed")
82
+ status, stdout, stderr = result = ns.run(options)
83
+ log.info("run results:\n" +
84
+ "-----------------------\n" +
85
+ "Exit Status: #{status.exitstatus}\n" +
86
+ "<stdout>#{stdout}</stdout>\n" +
87
+ "<stderr>#{stderr}</stderr>\n" +
88
+ "-----------------------\n")
89
+
90
+ if block_given?
91
+ yield(*result)
92
+ else
93
+ result
94
+ end
95
+ end
96
+
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.
100
+ #
101
+ # Just specify a source, and a destination path, and go.
102
+ #
103
+ # @example Remote copy /srv/data to remote host
104
+ # rcp(:dest_path => '/srv/data', :source_path => 'mydata')
105
+ # @param options [Hash] options for command execution
106
+ # @option options [String] :source_path source to copy files from (currently
107
+ # only locally)
108
+ # @option options [String] :sp alias for source_path
109
+ # @option options [String] :destination_path destination for copy
110
+ # @option options [String] :dp alias for dest_path
111
+ # @option options [RSpecSystem::Node] :destination_node (default_node) destination node
112
+ # to transfer files to. Optional.
113
+ # @option options [RSpecSystem::Node] :d alias for destination_node
114
+ # @option options [RSpecSystem::Node] :source_node ('') Reserved
115
+ # for future use. Patches welcome.
116
+ # @option options [RSpecSystem::Node] :s alias for source_node
117
+ # @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)
122
+ options = {
123
+ :source_path => options[:sp],
124
+ :destination_path => options[:dp],
125
+ :dp => options[:destination_path],
126
+ :sp => options[:source_path],
127
+ :destination_node => rspec_system_node_set.default_node,
128
+ :d => rspec_system_node_set.default_node,
129
+ :source_node => '',
130
+ :s => '',
131
+ }.merge(options)
132
+
133
+ d = options[:d]
134
+ sp = options[:sp]
135
+ dp = options[:dp]
136
+
137
+ log.info("rcp from #{sp} to #{d.name}:#{dp} executed")
138
+ status, stdout, stderr = results = rspec_system_node_set.rcp(options)
139
+ log.info("rcp results:\n" +
140
+ "-----------------------\n" +
141
+ "Exit Status: #{status.exitstatus}\n" +
142
+ "<stdout>#{stdout}</stdout>\n" +
143
+ "<stderr>#{stderr}</stderr>\n" +
144
+ "-----------------------\n")
145
+
146
+ if status.exitstatus == 1
147
+ return true
148
+ else
149
+ return false
150
+ end
151
+ end
152
+
153
+ # @!group Queries
154
+
155
+ # Returns a particular node object from the current nodeset given a set of
156
+ # criteria.
157
+ #
158
+ # If no options are supplied, it tries to return the default node.
159
+ #
160
+ # @param options [Hash] search criteria
161
+ # @option options [String] :name the canonical name of the node
162
+ # @return [RSpecSystem::Node] node object
163
+ def node(options = {})
164
+ ns = rspec_system_node_set
165
+ options = {
166
+ :name => ns.default_node,
167
+ }.merge(options)
168
+
169
+ if !options[:name].nil?
170
+ return ns.nodes[options[:name]]
171
+ else
172
+ raise "No nodes to return"
173
+ end
7
174
  end
8
175
  end
@@ -0,0 +1,76 @@
1
+ module RSpecSystem
2
+ # This class represents a node in a nodeset
3
+ class Node
4
+ # Static helper for generating a node direct from the hash returned by
5
+ # the nodeset YAML file.
6
+ #
7
+ # @param nodeset [RSpecSystem::Node] nodeset that this node belongs to
8
+ # @param k [String] name of node
9
+ # @param v [Hash<String,String>] hash configuration as given from the nodeset yaml file
10
+ # @return [RSpecSystem::Node] returns a new node object
11
+ def self.node_from_yaml(nodeset, k, v)
12
+ RSpecSystem::Node.new(
13
+ :nodeset => nodeset,
14
+ :name => k,
15
+ :prefab => v['prefab']
16
+ )
17
+ end
18
+
19
+ # Create a new node object.
20
+ #
21
+ # @param options [Hash] options for new node
22
+ # @option options [String] :name name of node. Mandatory.
23
+ # @option options [String] :prefab prefab setting. Mandatory.
24
+ # @option options [RSpecSystem::NodeSet] :nodeset the parent nodeset for
25
+ # this node. Mandatory.
26
+ def initialize(options)
27
+ @name = options[:name]
28
+ prefab = options[:prefab]
29
+ @nodeset = options[:nodeset]
30
+
31
+ if prefab.nil?
32
+ # TODO: do not support not prefabs yet
33
+ raise "No prefab defined, bailing"
34
+ else
35
+ @prefab = RSpecSystem::Prefab.prefab(prefab)
36
+ @facts = @prefab.facts
37
+ @provider_specifics = @prefab.provider_specifics
38
+ end
39
+ end
40
+
41
+ # Returns the name of the node as specified in the nodeset file.
42
+ #
43
+ # @return [String] name of node
44
+ def name
45
+ @name
46
+ end
47
+
48
+ # Returns the prefab object for this node (if any).
49
+ #
50
+ # @return [RSpecSystem::Prefab] the prefab object used to create this node
51
+ def prefab
52
+ @prefab
53
+ end
54
+
55
+ # Retreives facts from the nodeset definition or prefab.
56
+ #
57
+ # @return [Hash] returns a hash of facter facts defined for this node
58
+ def facts
59
+ @facts
60
+ end
61
+
62
+ # Returns the nodeset this node belongs in.
63
+ #
64
+ # @return [RSpecSystem::NodeSet] the nodeset this node belongs to
65
+ def nodeset
66
+ @nodeset
67
+ end
68
+
69
+ # Return provider specific settings
70
+ #
71
+ # @return [Hash] provider specific settings
72
+ def provider_specifics
73
+ @provider_specifics
74
+ end
75
+ end
76
+ end
@@ -1,36 +1,64 @@
1
1
  module RSpecSystem
2
- # Base class for a NodeSet.
2
+ # Base class for a NodeSet driver. If you want to create a new driver, you
3
+ # should sub-class this and override all the methods below.
4
+ #
5
+ # @abstract Subclass and override methods to create a new NodeSet variant.
3
6
  class NodeSet::Base
4
- attr_reader :config, :setname
7
+ attr_reader :config
8
+ attr_reader :setname
9
+ attr_reader :nodes
5
10
 
11
+ # Create new NodeSet, populating necessary data structures.
6
12
  def initialize(setname, config)
7
13
  @setname = setname
8
14
  @config = config
15
+
16
+ @nodes = {}
17
+ config['nodes'].each do |k,v|
18
+ @nodes[k] = RSpecSystem::Node.node_from_yaml(self, k, v)
19
+ end
9
20
  end
10
21
 
11
22
  # Setup the NodeSet by starting all nodes.
12
23
  def setup
24
+ raise "Unimplemented method #setup"
13
25
  end
14
26
 
15
27
  # Shutdown the NodeSet by shutting down or pausing all nodes.
16
28
  def teardown
29
+ raise "Unimplemented method #teardown"
17
30
  end
18
31
 
19
- # Take a snapshot of the NodeSet for rollback later.
20
- def snapshot
32
+ # Run a command on a host in the NodeSet.
33
+ def run(options)
34
+ raise "Unimplemented method #run"
21
35
  end
22
36
 
23
- # Rollback to the snapshot of the NodeSet.
24
- def rollback
25
- end
26
-
27
- # Run a command on a host in the NodeSet.
28
- def run(dest, command)
37
+ # Copy a file to the host in the NodeSet.
38
+ def rcp(options)
39
+ raise "Unimplemented method #rcp"
29
40
  end
30
41
 
31
42
  # Return environment type
32
43
  def env_type
33
44
  self.class::ENV_TYPE
34
45
  end
46
+
47
+ # Return default node
48
+ #
49
+ # @return [RSpecSystem::Node] default node for this nodeset
50
+ def default_node
51
+ dn = config['default_node']
52
+ if dn.nil?
53
+ if nodes.length == 1
54
+ dn = nodes.first[1]
55
+ return dn
56
+ else
57
+ raise "No default node"
58
+ end
59
+ else
60
+ return nodes[dn]
61
+ end
62
+ end
35
63
  end
36
64
  end
@@ -1,4 +1,5 @@
1
1
  require 'fileutils'
2
+ require 'systemu'
2
3
 
3
4
  module RSpecSystem
4
5
  # A NodeSet implementation for Vagrant.
@@ -14,76 +15,130 @@ module RSpecSystem
14
15
 
15
16
  # Setup the NodeSet by starting all nodes.
16
17
  def setup
17
- log.info "Begin setting up vagrant"
18
+ log.info "[Vagrant#setup] Begin setting up vagrant"
18
19
  create_vagrantfile
19
20
 
20
- log.info "Running 'vagrant destroy'"
21
- vagrant("destroy", "--force")
21
+ log.info "[Vagrant#setup] Running 'vagrant destroy'"
22
+ vagrant("destroy --force")
22
23
 
23
- log.info "Running 'vagrant up'"
24
+ log.info "[Vagrant#setup] Running 'vagrant up'"
24
25
  vagrant("up")
25
26
  end
26
27
 
27
28
  # Shutdown the NodeSet by shutting down or pausing all nodes.
28
29
  def teardown
29
- log.info "Running 'vagrant destroy'"
30
- vagrant("destroy", "--force")
30
+ log.info "[Vagrant#teardown] Running 'vagrant destroy'"
31
+ vagrant("destroy --force")
31
32
  end
32
33
 
33
34
  # Run a command on a host in the NodeSet.
34
- def run(dest, command)
35
+ #
36
+ # @param opts [Hash] options
37
+ def run(opts)
38
+ #log.debug("[Vagrant#run] called with #{opts.inspect}")
39
+
40
+ dest = opts[:n].name
41
+ cmd = opts[:c]
42
+
35
43
  result = ""
36
44
  Dir.chdir(@vagrant_path) do
37
- result = `vagrant ssh #{dest} --command 'cd /tmp && #{command}'`
45
+ cmd = "vagrant ssh #{dest} --command \"cd /tmp && sudo -i #{cmd}\""
46
+ log.debug("[vagrant#run] Running command: #{cmd}")
47
+ result = systemu cmd
48
+ log.debug("[Vagrant#run] Finished running command: #{cmd}. Result is #{result}.")
38
49
  end
39
50
  result
40
51
  end
41
52
 
53
+ # Transfer files to a host in the NodeSet.
54
+ #
55
+ # @param opts [Hash] options
56
+ def rcp(opts)
57
+ #log.debug("[Vagrant@rcp] called with #{opts.inspect}")
58
+
59
+ dest = opts[:d].name
60
+ source = opts[:sp]
61
+ dest_path = opts[:dp]
62
+
63
+ # TODO: This is damn ugly, because we ssh in as vagrant, we copy to a
64
+ # temp path then move later. This pattern at the moment only really works
65
+ # on dirs.
66
+ log.info("[Vagrant#rcp] Transferring files from #{source} to #{dest}:#{dest_path}")
67
+
68
+ # TODO: The static temp path here is definately insecure
69
+ cmd = "scp -r -F #{ssh_config} #{source} #{dest}:/tmp/tmpxfer"
70
+ log.debug("[Vagrant#rcp] Running command: #{cmd}")
71
+ systemu cmd
72
+
73
+ # Now we move the file into place
74
+ run(:n => opts[:d], :c => "mv /tmp/tmpxfer #{dest_path}")
75
+ end
76
+
42
77
  # Create the Vagrantfile for the NodeSet.
78
+ #
43
79
  # @api private
44
80
  def create_vagrantfile
45
- log.info "Creating vagrant file here: #{@vagrant_path}"
81
+ log.info "[Vagrant#create_vagrantfile] Creating vagrant file here: #{@vagrant_path}"
46
82
  FileUtils.mkdir_p(@vagrant_path)
47
83
  File.open(File.expand_path(File.join(@vagrant_path, "Vagrantfile")), 'w') do |f|
48
84
  f.write('Vagrant::Config.run do |c|')
49
- @config['nodes'].each do |k,v|
85
+ nodes.each do |k,v|
50
86
  log.debug "Filling in content for #{k}"
51
87
  f.write(<<-EOS)
52
88
  c.vm.define '#{k}' do |vmconf|
53
- #{template_prefabs(v["prefab"])}
89
+ vmconf.vm.host_name = "#{k}"
90
+ #{template_node(v.provider_specifics['vagrant'])}
54
91
  end
55
92
  EOS
56
93
  end
57
94
  f.write('end')
58
95
  end
59
- log.debug "Finished creating vagrant file"
96
+ log.debug "[Vagrant#create_vagrantfile] Finished creating vagrant file"
60
97
  end
61
98
 
62
- # Provide Vagrantfile templates for prefabs.
99
+ # Here we get vagrant to drop the ssh_config its using so we can monopolize
100
+ # it for transfers and custom stuff. We drop it into a single file, and
101
+ # since its indexed based on our own node names its quite ideal.
102
+ #
63
103
  # @api private
64
- def template_prefabs(prefab)
65
- case prefab
66
- when 'centos-58-x64'
67
- <<-EOS
68
- vmconf.vm.box = 'centos-58-x64'
69
- vmconf.vm.box_url = 'http://puppet-vagrant-boxes.puppetlabs.com/centos-58-x64.box'
70
- EOS
71
- when 'debian-606-x64'
72
- <<-EOS
73
- vmconf.vm.box = 'debian-606-x64'
74
- vmconf.vm.box_url = 'http://puppet-vagrant-boxes.puppetlabs.com/debian-606-x64.box'
75
- EOS
76
- else
77
- raise 'Unknown prefab'
104
+ def ssh_config
105
+ ssh_config_path = File.expand_path(File.join(@vagrant_path, "ssh_config"))
106
+ begin
107
+ File.unlink(ssh_config_path)
108
+ rescue Errno::ENOENT
109
+ end
110
+ self.nodes.each do |k,v|
111
+ Dir.chdir(@vagrant_path) do
112
+ result = systemu("vagrant ssh-config #{k} >> #{ssh_config_path}")
113
+ puts result.inspect
114
+ end
78
115
  end
116
+ ssh_config_path
117
+ end
118
+
119
+ # Provide Vagrantfile templates from node definition.
120
+ #
121
+ # @api private
122
+ # @param settings [Hash] provider specific settings for vagrant
123
+ def template_node(settings)
124
+ template = <<-EOS
125
+ vmconf.vm.box = '#{settings['box']}'
126
+ vmconf.vm.box_url = '#{settings['box_url']}'
127
+ EOS
79
128
  end
80
129
 
81
130
  # Execute vagrant command in vagrant_path
131
+ #
82
132
  # @api private
83
- def vagrant(*args)
133
+ # @param args [String] args to vagrant
134
+ # @todo This seems a little too specific these days, might want to
135
+ # generalize. It doesn't use systemu, because we want to see the output
136
+ # immediately, but still - maybe we can make systemu do that.
137
+ def vagrant(args)
84
138
  Dir.chdir(@vagrant_path) do
85
- system("vagrant", *args)
139
+ system("vagrant #{args}")
86
140
  end
141
+ nil
87
142
  end
88
143
  end
89
144
  end
@@ -0,0 +1,28 @@
1
+ module RSpecSystem
2
+ class Prefab
3
+ attr_reader :name
4
+ attr_reader :description
5
+ attr_reader :facts
6
+ attr_reader :provider_specifics
7
+
8
+ # Return prefab object based on name
9
+ def self.prefab(name)
10
+ prefabs = YAML.load_file(File.join(File.dirname(__FILE__), '..', '..', 'resources', 'prefabs.yml'))
11
+ raise "No such prefab" unless pf = prefabs[name]
12
+
13
+ RSpecSystem::Prefab.new(
14
+ :name => name,
15
+ :description => pf['description'],
16
+ :facts => pf['facts'],
17
+ :provider_specifics => pf['provider_specifics']
18
+ )
19
+ end
20
+
21
+ def initialize(options = {})
22
+ @name = options[:name]
23
+ @description = options[:description]
24
+ @facts = options[:facts]
25
+ @provider_specifics = options[:provider_specifics]
26
+ end
27
+ end
28
+ end
@@ -7,7 +7,7 @@ require 'rspec/core/rake_task'
7
7
  require 'rspec-system/formatter'
8
8
 
9
9
  RSpec::Core::RakeTask.new(:spec_system) do |c|
10
- c.pattern = "spec/system/**/test1_spec.rb"
10
+ c.pattern = "spec/system/**/*_spec.rb"
11
11
  c.rspec_opts = %w[--require rspec-system/formatter --format=RSpecSystem::Formatter]
12
12
  end
13
13
 
@@ -25,18 +25,41 @@ RSpec.configure do |c|
25
25
  RSpecSystem::NodeSet.create(setname, config, rspec_virtual_env)
26
26
  end
27
27
 
28
- c.system_tmp = Dir.tmpdir
29
- c.before :suite do
28
+ def start_nodes
29
+ ns = rspec_system_node_set
30
+
30
31
  log.info "START RSPEC-SYSTEM SETUP"
31
- log.info "Setname is: " + rspec_system_node_set.setname
32
- log.info "Configuration is: " + rspec_system_node_set.config.pretty_inspect
33
- log.info "Virtual Environment type is: #{rspec_system_node_set.env_type}"
32
+ log.info "Setname is: " + ns.setname
33
+ log.info "Configuration is: " + ns.config.pretty_inspect
34
+ log.info "Virtual Environment type is: #{ns.env_type}"
35
+ log.info "Default node is: #{ns.default_node.name}"
34
36
 
35
- rspec_system_node_set.setup
37
+ ns.setup
36
38
  end
37
39
 
38
- c.after :suite do
40
+ def stop_nodes
39
41
  log.info 'FINALIZE RSPEC-SYSTEM SETUP'
40
42
  rspec_system_node_set.teardown
41
43
  end
44
+
45
+ def call_custom_setup_block
46
+ # Run test specific setup routines
47
+ if pr = RSpec.configuration.system_setup_block then
48
+ log.info "Running custom setup block"
49
+ pr.call
50
+ log.info "Finished running custom setup block"
51
+ end
52
+ end
53
+
54
+ # Default the system_tmp dir to something random
55
+ c.system_tmp = Dir.tmpdir
56
+
57
+ c.before :suite do
58
+ start_nodes
59
+ call_custom_setup_block
60
+ end
61
+
62
+ c.after :suite do
63
+ stop_nodes
64
+ end
42
65
  end
@@ -0,0 +1,17 @@
1
+ type: map
2
+ mapping:
3
+ =:
4
+ type: map
5
+ mapping:
6
+ description: { type: str }
7
+ facts:
8
+ type: map
9
+ mapping:
10
+ =: { type: str }
11
+ provider_specifics:
12
+ type: map
13
+ mapping:
14
+ =:
15
+ type: map
16
+ mapping:
17
+ =: { type: str}
@@ -0,0 +1,43 @@
1
+ ---
2
+ 'centos-58-x64':
3
+ description: "Vagrant images obtained from http://puppet-vagrant-boxes.puppetlabs.com"
4
+ facts:
5
+ architecture: x86_64
6
+ facterversion: "1.6.17"
7
+ kernel: Linux
8
+ kernelmajversion: "2.6"
9
+ kernelrelease: "2.6.18-308.el5"
10
+ kernelversion: "2.6.18"
11
+ lsbdistcodename: Final
12
+ lsbdistdescription: "CentOS release 5.8 (Final)"
13
+ lsbdistid: CentOS
14
+ lsbdistrelease: "5.8"
15
+ lsbmajdistrelease: "5"
16
+ lsbrelease: ":core-4.0-amd64:core-4.0-ia32:core-4.0-noarch:graphics-4.0-amd64:graphics-4.0-ia32:graphics-4.0-noarch:printing-4.0-amd64:printing-4.0-ia32:printing-4.0-noarch"
17
+ operatingsystem: CentOS
18
+ operatingsystemrelease: "5.8"
19
+ osfamily: RedHat
20
+ rubyversion: "1.9.2"
21
+ provider_specifics:
22
+ vagrant:
23
+ box: 'centos-58-x64'
24
+ box_url: 'http://puppet-vagrant-boxes.puppetlabs.com/centos-58-x64.box'
25
+ 'debian-606-x64':
26
+ description: "Vagrant images obtained from http://puppet-vagrant-boxes.puppetlabs.com"
27
+ facts:
28
+ architecture: amd64
29
+ facterversion: "1.6.17"
30
+ kernel: Linux
31
+ kernelmajversion: "2.6"
32
+ kernelversion: "2.6.32"
33
+ lsbdistcodename: squeeze
34
+ lsbdistdescription: "Debian GNU/Linux 6.0.6 (squeeze)"
35
+ lsbdistid: Debian
36
+ lsbdistrelease: "6.0.6"
37
+ operatingsystem: Debian
38
+ osfamily: Debian
39
+ rubyversion: "1.8.7"
40
+ provider_specifics:
41
+ vagrant:
42
+ box: 'debian-606-x64'
43
+ box_url: 'http://puppet-vagrant-boxes.puppetlabs.com/debian-606-x64.box'
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.0.2"
5
+ s.version = "0.1.0"
6
6
  s.authors = ["Ken Barber"]
7
7
  s.email = ["ken@bob.sh"]
8
8
  s.homepage = "https://github.com/kbarber/rspec-system"
@@ -15,9 +15,8 @@ Gem::Specification.new do |s|
15
15
  s.require_paths = ["lib"]
16
16
 
17
17
  # Dependencies
18
- s.required_ruby_version = '>= 1.9.3'
18
+ s.required_ruby_version = '>= 1.8.7'
19
19
  s.add_runtime_dependency "rspec"
20
20
  s.add_runtime_dependency "kwalify"
21
- s.add_development_dependency "simplecov"
22
- s.add_development_dependency "mocha"
21
+ s.add_runtime_dependency "systemu"
23
22
  end
data/spec/spec_helper.rb CHANGED
@@ -16,8 +16,11 @@ end
16
16
  def fixture_path
17
17
  Pathname.new(File.expand_path(File.join(__FILE__, '..', 'fixtures')))
18
18
  end
19
+ def resources_path
20
+ Pathname.new(File.expand_path(File.join(__FILE__, '..', '..', 'resources')))
21
+ end
19
22
  def schema_path
20
- Pathname.new(File.expand_path(File.join(__FILE__, '..', '..', 'resources', 'kwalify-schemas')))
23
+ resources_path + 'kwalify-schemas'
21
24
  end
22
25
 
23
26
  RSpec.configure do |config|
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+ require 'kwalify'
3
+
4
+ describe 'prefabs_schema' do
5
+ let(:schema) do
6
+ YAML.load_file(schema_path + 'prefabs_schema.yml')
7
+ end
8
+ let(:validator) do
9
+ validator = Kwalify::Validator.new(schema)
10
+ end
11
+ let(:parser) do
12
+ parser = Kwalify::Yaml::Parser.new(validator)
13
+ end
14
+
15
+ it "should not return an error for prefabs.yml" do
16
+ ydoc = parser.parse_file(resources_path + 'prefabs.yml')
17
+ errors = parser.errors
18
+ if errors && !errors.empty?
19
+ errors.each do |e|
20
+ puts "line=#{e.linenum}, path=#{e.path}, mesg=#{e.message}"
21
+ end
22
+ end
23
+ errors.should == []
24
+ end
25
+ end
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.0.2
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-03-23 00:00:00.000000000 Z
12
+ date: 2013-03-30 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
@@ -44,30 +44,14 @@ dependencies:
44
44
  - !ruby/object:Gem::Version
45
45
  version: '0'
46
46
  - !ruby/object:Gem::Dependency
47
- name: simplecov
47
+ name: systemu
48
48
  requirement: !ruby/object:Gem::Requirement
49
49
  none: false
50
50
  requirements:
51
51
  - - ! '>='
52
52
  - !ruby/object:Gem::Version
53
53
  version: '0'
54
- type: :development
55
- prerelease: false
56
- version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
- requirements:
59
- - - ! '>='
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- - !ruby/object:Gem::Dependency
63
- name: mocha
64
- requirement: !ruby/object:Gem::Requirement
65
- none: false
66
- requirements:
67
- - - ! '>='
68
- - !ruby/object:Gem::Version
69
- version: '0'
70
- type: :development
54
+ type: :runtime
71
55
  prerelease: false
72
56
  version_requirements: !ruby/object:Gem::Requirement
73
57
  none: false
@@ -84,7 +68,9 @@ extra_rdoc_files: []
84
68
  files:
85
69
  - .gitignore
86
70
  - .ruby-version
71
+ - .travis.yml
87
72
  - Gemfile
73
+ - LICENSE
88
74
  - README.md
89
75
  - examples/.gitignore
90
76
  - examples/.nodeset.yml
@@ -99,17 +85,22 @@ files:
99
85
  - lib/rspec-system/formatter.rb
100
86
  - lib/rspec-system/helpers.rb
101
87
  - lib/rspec-system/log.rb
88
+ - lib/rspec-system/node.rb
102
89
  - lib/rspec-system/node_set.rb
103
90
  - lib/rspec-system/node_set/base.rb
104
91
  - lib/rspec-system/node_set/vagrant.rb
92
+ - lib/rspec-system/prefab.rb
105
93
  - lib/rspec-system/rake_task.rb
106
94
  - lib/rspec-system/spec_helper.rb
107
95
  - resources/kwalify-schemas/nodeset_schema.yml
96
+ - resources/kwalify-schemas/prefabs_schema.yml
97
+ - resources/prefabs.yml
108
98
  - rspec-system.gemspec
109
99
  - spec/fixtures/nodeset_example1.yml
110
100
  - spec/fixtures/nodeset_example2.yml
111
101
  - spec/spec_helper.rb
112
102
  - spec/unit/kwalify-schemas/nodeset_schema_spec.rb
103
+ - spec/unit/kwalify-schemas/prefabs_schema_spec.rb
113
104
  homepage: https://github.com/kbarber/rspec-system
114
105
  licenses: []
115
106
  post_install_message:
@@ -121,7 +112,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
121
112
  requirements:
122
113
  - - ! '>='
123
114
  - !ruby/object:Gem::Version
124
- version: 1.9.3
115
+ version: 1.8.7
125
116
  required_rubygems_version: !ruby/object:Gem::Requirement
126
117
  none: false
127
118
  requirements:
@@ -136,3 +127,5 @@ specification_version: 3
136
127
  summary: System testing with rspec
137
128
  test_files:
138
129
  - spec/unit/kwalify-schemas/nodeset_schema_spec.rb
130
+ - spec/unit/kwalify-schemas/prefabs_schema_spec.rb
131
+ has_rdoc: