jamie 0.1.0.alpha17 → 0.1.0.alpha18

Sign up to get free protection for your applications and to get access to all the features.
data/.travis.yml CHANGED
@@ -1,3 +1,9 @@
1
1
  language: ruby
2
2
  rvm:
3
3
  - 1.9.3
4
+ notifications:
5
+ irc:
6
+ channels:
7
+ - "irc.freenode.org#jamie-ci"
8
+ use_notice: true
9
+ skip_join: true
data/Gemfile CHANGED
@@ -2,6 +2,12 @@ source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
4
 
5
+ group :development do
6
+ gem 'rb-inotify', :require => false
7
+ gem 'rb-fsevent', :require => false
8
+ gem 'rb-fchange', :require => false
9
+ end
10
+
5
11
  group :test do
6
12
  gem 'rake', '~> 0.9'
7
13
  gem 'pry'
data/Guardfile ADDED
@@ -0,0 +1,5 @@
1
+ guard 'minitest' do
2
+ watch(%r|^spec/(.*)_spec\.rb|)
3
+ watch(%r|^lib/(.*)([^/]+)\.rb|) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
4
+ watch(%r|^spec/spec_helper\.rb|) { "spec" }
5
+ end
data/README.md CHANGED
@@ -5,28 +5,16 @@
5
5
 
6
6
  A Chef convergence integration test harness.
7
7
 
8
- ## Installation
8
+ ## A Note
9
9
 
10
- Add this line to your application's Gemfile:
10
+ This project is currently in rapid development which means frequent releases,
11
+ potential for massive refactorings (that could be API breaking), and minimal
12
+ to no documentation. This will change as the project transitions to be used in
13
+ production environments.
11
14
 
12
- gem 'jamie'
15
+ Despite the warnings above, if you are still interested, please get in touch
16
+ via freenode/IRC (#jamie),
17
+ Twitter ([@fnichol](https://twitter.com/fnichol)),
18
+ or Email ([fnichol@nichol.ca](mailto:fnichol@nichol.ca)).
13
19
 
14
- And then execute:
15
-
16
- $ bundle
17
-
18
- Or install it yourself as:
19
-
20
- $ gem install jamie
21
-
22
- ## Usage
23
-
24
- TODO: Write usage instructions here
25
-
26
- ## Contributing
27
-
28
- 1. Fork it
29
- 2. Create your feature branch (`git checkout -b my-new-feature`)
30
- 3. Commit your changes (`git commit -am 'Add some feature'`)
31
- 4. Push to the branch (`git push origin my-new-feature`)
32
- 5. Create new Pull Request
20
+ For everyone else, watch [this space](https://github.com/jamie-ci/jamie).
data/Rakefile CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'bundler/gem_tasks'
2
2
  require 'cane/rake_task'
3
+ require 'rake/testtask'
3
4
  require 'tailor/rake_task'
4
5
 
5
6
  desc "Run cane to check quality metrics"
@@ -21,7 +22,16 @@ Tailor::RakeTask.new
21
22
 
22
23
  desc "Display LOC stats"
23
24
  task :stats do
25
+ puts "\n## Production Code Stats"
24
26
  sh "countloc -r lib/jamie lib/jamie.rb"
27
+ puts "\n## Test Code Stats"
28
+ sh "countloc -r spec"
25
29
  end
26
30
 
27
- task :default => [ :cane, :tailor ]
31
+ Rake::TestTask.new do |t|
32
+ t.libs.push "lib"
33
+ t.test_files = FileList['spec/**/*_spec.rb']
34
+ t.verbose = true
35
+ end
36
+
37
+ task :default => [ :test, :cane, :tailor, :stats ]
data/bin/jamie CHANGED
@@ -6,6 +6,7 @@
6
6
  Signal.trap("INT") { exit 1 }
7
7
 
8
8
  $:.unshift File.join(File.dirname(__FILE__), %w{.. lib})
9
+ require 'rubygems'
9
10
  require 'jamie/cli'
10
11
 
11
12
  Jamie::CLI.start
data/jamie.gemspec CHANGED
@@ -10,21 +10,28 @@ Gem::Specification.new do |gem|
10
10
  gem.email = ["fnichol@nichol.ca"]
11
11
  gem.description = %q{A Chef convergence integration test harness}
12
12
  gem.summary = gem.description
13
- gem.homepage = ""
13
+ gem.homepage = "https://github.com/jamie-ci/jamie"
14
14
 
15
15
  gem.files = `git ls-files`.split($/)
16
16
  gem.executables = %w(jamie)
17
17
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
18
  gem.require_paths = ["lib"]
19
19
 
20
+ gem.required_ruby_version = ">= 1.9.1"
21
+
20
22
  gem.add_dependency 'thor'
21
23
  gem.add_dependency 'net-ssh'
22
24
  gem.add_dependency 'net-scp'
23
25
  gem.add_dependency 'mixlib-shellout'
24
26
 
27
+ gem.add_development_dependency 'minitest'
28
+ gem.add_development_dependency 'fakefs'
29
+ gem.add_development_dependency 'guard-minitest'
30
+
25
31
  gem.add_development_dependency 'yard'
26
32
  gem.add_development_dependency 'maruku'
27
33
  gem.add_development_dependency 'cane'
28
34
  gem.add_development_dependency 'tailor'
35
+ gem.add_development_dependency 'simplecov'
29
36
  gem.add_development_dependency 'countloc'
30
37
  end
data/lib/jamie/cli.rb CHANGED
@@ -1,4 +1,20 @@
1
1
  # -*- encoding: utf-8 -*-
2
+ #
3
+ # Author:: Fletcher Nichol (<fnichol@nichol.ca>)
4
+ #
5
+ # Copyright (C) 2012, Fletcher Nichol
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.
2
18
 
3
19
  require 'ostruct'
4
20
  require 'thor'
@@ -8,6 +24,8 @@ require 'jamie'
8
24
  module Jamie
9
25
 
10
26
  # The command line runner for Jamie.
27
+ #
28
+ # @author Fletcher Nichol <fnichol@nichol.ca>
11
29
  class CLI < Thor
12
30
 
13
31
  include Thor::Actions
@@ -157,6 +175,8 @@ module Jamie
157
175
 
158
176
  # A project initialization generator, to help prepare a cookbook project for
159
177
  # testing with Jamie.
178
+ #
179
+ # @author Fletcher Nichol <fnichol@nichol.ca>
160
180
  class InitGenerator < Thor
161
181
 
162
182
  include Thor::Actions
@@ -275,6 +295,8 @@ module Jamie
275
295
  end
276
296
 
277
297
  # A generator to create a new Jamie driver plugin.
298
+ #
299
+ # @author Fletcher Nichol <fnichol@nichol.ca>
278
300
  class NewPluginGenerator < Thor
279
301
 
280
302
  include Thor::Actions
@@ -406,6 +428,8 @@ module Jamie
406
428
  end
407
429
 
408
430
  # Renders an ERB template with a hash of template variables.
431
+ #
432
+ # @author Fletcher Nichol <fnichol@nichol.ca>
409
433
  class TemplateRenderer < OpenStruct
410
434
 
411
435
  def self.render(template, data = {})
@@ -23,6 +23,8 @@ module Jamie
23
23
  module Driver
24
24
 
25
25
  # Dummy driver for Jamie.
26
+ #
27
+ # @author Fletcher Nichol <fnichol@nichol.ca>
26
28
  class Dummy < Jamie::Driver::Base
27
29
 
28
30
  def create(instance, state)
@@ -1,4 +1,20 @@
1
1
  # -*- encoding: utf-8 -*-
2
+ #
3
+ # Author:: Fletcher Nichol (<fnichol@nichol.ca>)
4
+ #
5
+ # Copyright (C) 2012, Fletcher Nichol
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.
2
18
 
3
19
  require 'rake/tasklib'
4
20
 
@@ -7,6 +23,8 @@ require 'jamie'
7
23
  module Jamie
8
24
 
9
25
  # Jamie Rake task generator.
26
+ #
27
+ # @author Fletcher Nichol <fnichol@nichol.ca>
10
28
  class RakeTasks < ::Rake::TaskLib
11
29
 
12
30
  # Creates Jamie Rake tasks and allows the callee to configure it.
@@ -26,7 +44,7 @@ module Jamie
26
44
  namespace "jamie" do
27
45
  config.instances.each do |instance|
28
46
  desc "Run #{instance.name} test instance"
29
- task instance.name { instance.test }
47
+ task instance.name { instance.test(:always) }
30
48
  end
31
49
 
32
50
  desc "Run all test instances"
@@ -1,4 +1,20 @@
1
1
  # -*- encoding: utf-8 -*-
2
+ #
3
+ # Author:: Fletcher Nichol (<fnichol@nichol.ca>)
4
+ #
5
+ # Copyright (C) 2012, Fletcher Nichol
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.
2
18
 
3
19
  require 'thor'
4
20
 
@@ -7,6 +23,8 @@ require 'jamie'
7
23
  module Jamie
8
24
 
9
25
  # Jamie Thor task generator.
26
+ #
27
+ # @author Fletcher Nichol <fnichol@nichol.ca>
10
28
  class ThorTasks < Thor
11
29
 
12
30
  namespace :jamie
@@ -29,7 +47,7 @@ module Jamie
29
47
  config.instances.each do |instance|
30
48
  self.class.desc instance.name, "Run #{instance.name} test instance"
31
49
  self.class.send(:define_method, instance.name.gsub(/-/, '_')) do
32
- instance.test
50
+ instance.test(:always)
33
51
  end
34
52
  end
35
53
 
data/lib/jamie/version.rb CHANGED
@@ -1,6 +1,22 @@
1
1
  # -*- encoding: utf-8 -*-
2
+ #
3
+ # Author:: Fletcher Nichol (<fnichol@nichol.ca>)
4
+ #
5
+ # Copyright (C) 2012, Fletcher Nichol
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.
2
18
 
3
19
  module Jamie
4
20
 
5
- VERSION = "0.1.0.alpha17"
21
+ VERSION = "0.1.0.alpha18"
6
22
  end
data/lib/jamie.rb CHANGED
@@ -1,4 +1,20 @@
1
1
  # -*- encoding: utf-8 -*-
2
+ #
3
+ # Author:: Fletcher Nichol (<fnichol@nichol.ca>)
4
+ #
5
+ # Copyright (C) 2012, Fletcher Nichol
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.
2
18
 
3
19
  require 'base64'
4
20
  require 'delegate'
@@ -29,6 +45,8 @@ module Jamie
29
45
 
30
46
  # Base configuration class for Jamie. This class exposes configuration such
31
47
  # as the location of the Jamie YAML file, instances, log_levels, etc.
48
+ #
49
+ # @author Fletcher Nichol <fnichol@nichol.ca>
32
50
  class Config
33
51
 
34
52
  attr_writer :yaml_file
@@ -97,6 +115,8 @@ module Jamie
97
115
  # Delegate class which adds the ability to find single and multiple
98
116
  # objects by their #name in an Array. Hey, it's better than monkey-patching
99
117
  # Array, right?
118
+ #
119
+ # @author Fletcher Nichol <fnichol@nichol.ca>
100
120
  class Collection < SimpleDelegator
101
121
 
102
122
  # Returns a single object by its name, or nil if none are found.
@@ -141,6 +161,7 @@ module Jamie
141
161
 
142
162
  def new_platform(hash)
143
163
  mpc = merge_platform_config(hash)
164
+ mpc['driver_config'] ||= Hash.new
144
165
  mpc['driver_config']['jamie_root'] = File.dirname(yaml_file)
145
166
  mpc['driver'] = new_driver(mpc['driver_plugin'], mpc['driver_config'])
146
167
  Platform.new(mpc)
@@ -220,6 +241,8 @@ module Jamie
220
241
 
221
242
  # A Chef run_list and attribute hash that will be used in a convergence
222
243
  # integration.
244
+ #
245
+ # @author Fletcher Nichol <fnichol@nichol.ca>
223
246
  class Suite
224
247
 
225
248
  # @return [String] logical name of this suite
@@ -261,7 +284,7 @@ module Jamie
261
284
 
262
285
  def validate_options(opts)
263
286
  %w(name run_list).each do |k|
264
- raise ArgumentError, "Attribute '#{attr}' is required." if opts[k].nil?
287
+ raise ArgumentError, "Attribute '#{k}' is required." if opts[k].nil?
265
288
  end
266
289
  end
267
290
  end
@@ -269,6 +292,8 @@ module Jamie
269
292
  # A target operating system environment in which convergence integration
270
293
  # will take place. This may represent a specific operating system, version,
271
294
  # and machine architecture.
295
+ #
296
+ # @author Fletcher Nichol <fnichol@nichol.ca>
272
297
  class Platform
273
298
 
274
299
  # @return [String] logical name of this platform
@@ -307,7 +332,7 @@ module Jamie
307
332
 
308
333
  def validate_options(opts)
309
334
  %w(name driver).each do |k|
310
- raise ArgumentError, "Attribute '#{attr}' is required." if opts[k].nil?
335
+ raise ArgumentError, "Attribute '#{k}' is required." if opts[k].nil?
311
336
  end
312
337
  end
313
338
  end
@@ -315,6 +340,8 @@ module Jamie
315
340
  # An instance of a suite running on a platform. A created instance may be a
316
341
  # local virtual machine, cloud instance, container, or even a bare metal
317
342
  # server, which is determined by the platform's driver.
343
+ #
344
+ # @author Fletcher Nichol <fnichol@nichol.ca>
318
345
  class Instance
319
346
 
320
347
  # @return [Suite] the test suite configuration
@@ -331,6 +358,8 @@ module Jamie
331
358
  # @param suite [Suite] a suite
332
359
  # @param platform [Platform] a platform
333
360
  def initialize(suite, platform)
361
+ validate_options(suite, platform)
362
+
334
363
  @suite = suite
335
364
  @platform = platform
336
365
  @jr = Jr.new(@suite.name)
@@ -440,6 +469,11 @@ module Jamie
440
469
 
441
470
  private
442
471
 
472
+ def validate_options(suite, platform)
473
+ raise ArgumentError, "Attribute 'suite' is required." if suite.nil?
474
+ raise ArgumentError, "Attribute 'platform' is required." if platform.nil?
475
+ end
476
+
443
477
  def transition_to(desired)
444
478
  FSM.actions(last_action, desired).each do |transition|
445
479
  send("#{transition}_action")
@@ -517,6 +551,8 @@ module Jamie
517
551
 
518
552
  # The simplest finite state machine pseudo-implementation needed to manage
519
553
  # an Instance.
554
+ #
555
+ # @author Fletcher Nichol <fnichol@nichol.ca>
520
556
  class FSM
521
557
 
522
558
  # Returns an Array of all transitions to bring an Instance from its last
@@ -555,6 +591,8 @@ module Jamie
555
591
  # Command string generator to interface with Jamie Runner (jr). The
556
592
  # commands that are generated are safe to pass to an SSH command or as an
557
593
  # unix command argument (escaped in single quotes).
594
+ #
595
+ # @author Fletcher Nichol <fnichol@nichol.ca>
558
596
  class Jr
559
597
 
560
598
  # Constructs a new jr command generator, given a suite name.
@@ -711,6 +749,8 @@ module Jamie
711
749
 
712
750
  # Mixin that wraps a command shell out invocation, providing a #run_command
713
751
  # method.
752
+ #
753
+ # @author Fletcher Nichol <fnichol@nichol.ca>
714
754
  module ShellOut
715
755
 
716
756
  # Wrapped exception for any interally raised shell out commands.
@@ -764,6 +804,8 @@ module Jamie
764
804
  # Base class for a driver. A driver is responsible for carrying out the
765
805
  # lifecycle activities of an instance, such as creating, converging, and
766
806
  # destroying an instance.
807
+ #
808
+ # @author Fletcher Nichol <fnichol@nichol.ca>
767
809
  class Base
768
810
 
769
811
  include ShellOut
@@ -842,6 +884,8 @@ module Jamie
842
884
  # A subclass must implement the following methods:
843
885
  # * #create(instance, state)
844
886
  # * #destroy(instance, state)
887
+ #
888
+ # @author Fletcher Nichol <fnichol@nichol.ca>
845
889
  class SSHBase < Base
846
890
 
847
891
  def create(instance, state)
@@ -973,6 +1017,8 @@ module Jamie
973
1017
 
974
1018
  # Uploads Chef asset files such as dna.json, data bags, and cookbooks to an
975
1019
  # instance over SSH.
1020
+ #
1021
+ # @author Fletcher Nichol <fnichol@nichol.ca>
976
1022
  class ChefDataUploader
977
1023
 
978
1024
  include ShellOut
@@ -0,0 +1,486 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # Author:: Fletcher Nichol (<fnichol@nichol.ca>)
4
+ #
5
+ # Copyright (C) 2012, Fletcher Nichol
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.
18
+
19
+ require 'simplecov'
20
+ SimpleCov.adapters.define 'gem' do
21
+ command_name 'Specs'
22
+
23
+ add_filter '/spec/'
24
+ add_filter '/lib/vendor/'
25
+
26
+ add_group 'Libraries', '/lib/'
27
+ end
28
+ SimpleCov.start 'gem'
29
+
30
+ require 'fakefs/spec_helpers'
31
+ require 'minitest/autorun'
32
+
33
+ require 'jamie'
34
+
35
+ # Nasty hack to redefine IO.read in terms of File#read for fakefs
36
+ class IO
37
+ def self.read(*args)
38
+ File.open(args[0], "rb") { |f| f.read(args[1]) }
39
+ end
40
+ end
41
+
42
+ describe Jamie::Config do
43
+ include FakeFS::SpecHelpers
44
+
45
+ let(:config) { Jamie::Config.new("/tmp/.jamie.yml") }
46
+
47
+ describe "#platforms" do
48
+
49
+ it "returns platforms loaded from a jamie.yml" do
50
+ stub_yaml!({'platforms' => [
51
+ { 'name' => 'one', 'driver_plugin' => 'dummy' },
52
+ { 'name' => 'two', 'driver_plugin' => 'dummy' },
53
+ ]})
54
+ config.platforms.size.must_equal 2
55
+ config.platforms[0].name.must_equal 'one'
56
+ config.platforms[1].name.must_equal 'two'
57
+ end
58
+
59
+ it "returns an empty Array if no platforms are given" do
60
+ stub_yaml!({})
61
+ config.platforms.must_equal []
62
+ end
63
+
64
+ it "returns a platform containing a driver instance" do
65
+ stub_yaml!({'platforms' => [
66
+ { 'name' => 'platform', 'driver_plugin' => 'dummy' }
67
+ ]})
68
+ config.platforms.first.driver.must_be_instance_of Jamie::Driver::Dummy
69
+ end
70
+
71
+ it "returns a platform with a driver initialized with jamie_root" do
72
+ stub_yaml!({'platforms' => [
73
+ { 'name' => 'platform', 'driver_plugin' => 'dummy' }
74
+ ]})
75
+ config.platforms.first.driver['jamie_root'].must_equal "/tmp"
76
+ end
77
+
78
+ it "returns a platform with a driver initialized with passed in config" do
79
+ stub_yaml!({'platforms' => [
80
+ { 'name' => 'platform', 'driver_plugin' => 'dummy',
81
+ 'driver_config' => { 'foo' => 'bar' }
82
+ }
83
+ ]})
84
+ config.platforms.first.driver['foo'].must_equal "bar"
85
+ end
86
+ end
87
+
88
+ describe "#suites" do
89
+
90
+ it "returns suites loaded from a jamie.yml" do
91
+ stub_yaml!({'suites' => [
92
+ { 'name' => 'one', 'run_list' => [] },
93
+ { 'name' => 'two', 'run_list' => [] },
94
+ ]})
95
+ config.suites.size.must_equal 2
96
+ config.suites[0].name.must_equal 'one'
97
+ config.suites[1].name.must_equal 'two'
98
+ end
99
+
100
+ it "returns an empty Array if no suites are given" do
101
+ stub_yaml!({})
102
+ config.suites.must_equal []
103
+ end
104
+
105
+ it "returns a suite with nil for data_bags_path by default" do
106
+ stub_yaml!({'suites' => [ { 'name' => 'one', 'run_list' => [] } ]})
107
+ config.suites.first.data_bags_path.must_be_nil
108
+ end
109
+
110
+ it "retuns a suite with a common data_bags_path set" do
111
+ stub_yaml!({'suites' => [ { 'name' => 'one', 'run_list' => [] } ]})
112
+ config.test_base_path = "/tmp/base"
113
+ FileUtils.mkdir_p "/tmp/base/data_bags"
114
+ config.suites.first.data_bags_path.must_equal "/tmp/base/data_bags"
115
+ end
116
+
117
+ it "retuns a suite with a suite-specific data_bags_path set" do
118
+ stub_yaml!({'suites' => [ { 'name' => 'cool', 'run_list' => [] } ]})
119
+ config.test_base_path = "/tmp/base"
120
+ FileUtils.mkdir_p "/tmp/base/cool/data_bags"
121
+ config.suites.first.data_bags_path.must_equal "/tmp/base/cool/data_bags"
122
+ end
123
+
124
+ it "returns a suite with nil for roles_path by default" do
125
+ stub_yaml!({'suites' => [ { 'name' => 'one', 'run_list' => [] } ]})
126
+ config.suites.first.roles_path.must_be_nil
127
+ end
128
+
129
+ it "returns a suite with a common roles_path set" do
130
+ stub_yaml!({'suites' => [ { 'name' => 'one', 'run_list' => [] } ]})
131
+ config.test_base_path = "/tmp/base"
132
+ FileUtils.mkdir_p "/tmp/base/roles"
133
+ config.suites.first.roles_path.must_equal "/tmp/base/roles"
134
+ end
135
+
136
+ it "returns a suite with a suite-specific roles_path set" do
137
+ stub_yaml!({'suites' => [ { 'name' => 'mysuite', 'run_list' => [] } ]})
138
+ config.test_base_path = "/tmp/base"
139
+ FileUtils.mkdir_p "/tmp/base/mysuite/roles"
140
+ config.suites.first.roles_path.must_equal "/tmp/base/mysuite/roles"
141
+ end
142
+ end
143
+
144
+ describe "#instances" do
145
+
146
+ it "returns instances loaded from a jamie.yml" do
147
+ stub_yaml!({
148
+ 'platforms' => [
149
+ { 'name' => 'p1', 'driver_plugin' => 'dummy' },
150
+ { 'name' => 'p2', 'driver_plugin' => 'dummy' },
151
+ ],
152
+ 'suites' => [
153
+ { 'name' => 's1', 'run_list' => [] },
154
+ { 'name' => 's2', 'run_list' => [] },
155
+ ]
156
+ })
157
+ config.instances.size.must_equal 4
158
+ config.instances.map { |i| i.name }.must_equal %w{s1-p1 s1-p2 s2-p1 s2-p2}
159
+ end
160
+ end
161
+
162
+ describe "jamie.local.yml" do
163
+
164
+ it "merges in configuration with jamie.yml" do
165
+ stub_yaml!(".jamie.yml", {
166
+ 'platforms' => [ { 'name' => 'p1', 'driver_plugin' => 'dummy' } ]
167
+ })
168
+ stub_yaml!(".jamie.local.yml", {
169
+ 'driver_config' => { 'foo' => 'bar' }
170
+ })
171
+ config.platforms.first.driver['foo'].must_equal 'bar'
172
+ end
173
+
174
+ it "merges over configuration in jamie.yml" do
175
+ stub_yaml!(".jamie.yml", {
176
+ 'driver_config' => { 'foo' => 'nope' },
177
+ 'platforms' => [ { 'name' => 'p1', 'driver_plugin' => 'dummy' } ]
178
+ })
179
+ stub_yaml!(".jamie.local.yml", {
180
+ 'driver_config' => { 'foo' => 'bar' }
181
+ })
182
+ config.platforms.first.driver['foo'].must_equal 'bar'
183
+ end
184
+ end
185
+
186
+ describe "erb filtering" do
187
+
188
+ it "evaluates jamie.yml through erb before loading" do
189
+ FileUtils.mkdir_p "/tmp"
190
+ File.open("/tmp/.jamie.yml", "wb") do |f|
191
+ f.write <<-YAML.gsub(/^ {10}/, '')
192
+ ---
193
+ driver_plugin: dummy
194
+ platforms:
195
+ - name: <%= "AHH".downcase + "choo" %>
196
+ YAML
197
+ end
198
+ config.platforms.first.name.must_equal "ahhchoo"
199
+ end
200
+
201
+ it "evaluates jamie.local.yml through erb before loading" do
202
+ stub_yaml!({
203
+ 'platforms' => [ { 'name' => 'p1', 'driver_plugin' => 'dummy' } ]
204
+ })
205
+ FileUtils.mkdir_p "/tmp"
206
+ File.open("/tmp/.jamie.local.yml", "wb") do |f|
207
+ f.write <<-YAML.gsub(/^ {10}/, '')
208
+ ---
209
+ driver_config:
210
+ <% %w{noodle mushroom}.each do |kind| %>
211
+ <%= kind %>: soup
212
+ <% end %>
213
+ YAML
214
+ end
215
+ config.platforms.first.driver['noodle'].must_equal "soup"
216
+ config.platforms.first.driver['mushroom'].must_equal "soup"
217
+ end
218
+ end
219
+
220
+ describe "#log_level" do
221
+
222
+ it "returns a default log_level of info" do
223
+ config.log_level.must_equal :info
224
+ end
225
+
226
+ it "returns an overridden log_level" do
227
+ config.log_level = :error
228
+ config.log_level.must_equal :error
229
+ end
230
+ end
231
+
232
+ private
233
+
234
+ def stub_yaml!(name = ".jamie.yml", hash)
235
+ FileUtils.mkdir_p "/tmp"
236
+ File.open("/tmp/#{name}", "wb") { |f| f.write(hash.to_yaml) }
237
+ end
238
+ end
239
+
240
+ describe Jamie::Config::Collection do
241
+
242
+ let(:collection) do
243
+ Jamie::Config::Collection.new([
244
+ obj('one'), obj('two', 'a'), obj('two', 'b'), obj('three')
245
+ ])
246
+ end
247
+
248
+ it "transparently wraps an Array" do
249
+ collection.must_be_instance_of Array
250
+ end
251
+
252
+ describe "#get" do
253
+
254
+ it "returns a single object by its name" do
255
+ collection.get('three').must_equal obj('three')
256
+ end
257
+
258
+ it "returns the first occurance of an object by its name" do
259
+ collection.get('two').must_equal obj('two', 'a')
260
+ end
261
+
262
+ it "returns nil if an object cannot be found by its name" do
263
+ collection.get('nope').must_be_nil
264
+ end
265
+ end
266
+
267
+ describe "#get_all" do
268
+
269
+ it "returns a Collection of objects whose name matches the regex" do
270
+ result = collection.get_all(/(one|three)/)
271
+ result.size.must_equal 2
272
+ result[0].must_equal obj('one')
273
+ result[1].must_equal obj('three')
274
+ result.get_all(/one/).size.must_equal 1
275
+ end
276
+
277
+ it "returns an empty Collection if on matches are found" do
278
+ result = collection.get_all(/noppa/)
279
+ result.must_equal []
280
+ result.get("nahuh").must_be_nil
281
+ end
282
+ end
283
+
284
+ describe "#as_name" do
285
+
286
+ it "returns an Array of names as strings" do
287
+ collection.as_names.must_equal %w{one two two three}
288
+ end
289
+ end
290
+
291
+ private
292
+
293
+ def obj(name, extra = nil)
294
+ OpenStruct.new(:name => name, :extra => extra)
295
+ end
296
+ end
297
+
298
+ describe Jamie::Suite do
299
+
300
+ let(:opts) do ; { 'name' => 'suitezy', 'run_list' => [ 'doowah' ] } ; end
301
+ let(:suite) { Jamie::Suite.new(opts) }
302
+
303
+ it "raises an ArgumentError if name is missing" do
304
+ opts.delete('name')
305
+ proc { Jamie::Suite.new(opts) }.must_raise ArgumentError
306
+ end
307
+
308
+ it "raises an ArgumentError if run_list is missing" do
309
+ opts.delete('run_list')
310
+ proc { Jamie::Suite.new(opts) }.must_raise ArgumentError
311
+ end
312
+
313
+ it "returns an empty Hash given no attributes" do
314
+ suite.attributes.must_equal Hash.new
315
+ end
316
+
317
+ it "returns nil given no data_bags_path" do
318
+ suite.data_bags_path.must_be_nil
319
+ end
320
+
321
+ it "returns nil given no roles_path" do
322
+ suite.roles_path.must_be_nil
323
+ end
324
+
325
+ it "returns attributes from constructor" do
326
+ opts.merge!({ 'attributes' => { 'a' => 'b' }, 'data_bags_path' => 'crazy',
327
+ 'roles_path' => 'town' })
328
+ suite.name.must_equal 'suitezy'
329
+ suite.run_list.must_equal [ 'doowah' ]
330
+ suite.attributes.must_equal({ 'a' => 'b' })
331
+ suite.data_bags_path.must_equal 'crazy'
332
+ suite.roles_path.must_equal 'town'
333
+ end
334
+ end
335
+
336
+ describe Jamie::Platform do
337
+
338
+ let(:opts) do ; { 'name' => 'plata', 'driver' => 'imadriver' } ; end
339
+ let(:platform) { Jamie::Platform.new(opts) }
340
+
341
+ it "raises an ArgumentError if name is missing" do
342
+ opts.delete('name')
343
+ proc { Jamie::Platform.new(opts) }.must_raise ArgumentError
344
+ end
345
+
346
+ it "raises an ArgumentError if driver is missing" do
347
+ opts.delete('driver')
348
+ proc { Jamie::Platform.new(opts) }.must_raise ArgumentError
349
+ end
350
+
351
+ it "returns an empty Array given no run_list" do
352
+ platform.run_list.must_equal []
353
+ end
354
+
355
+ it "returns an empty Hash given no attributes" do
356
+ platform.attributes.must_equal Hash.new
357
+ end
358
+
359
+ it "returns attributes from constructor" do
360
+ opts.merge!({ 'run_list' => [ 'a', 'b' ], 'attributes' => { 'c' => 'd' }})
361
+ platform.name.must_equal 'plata'
362
+ platform.driver.must_equal 'imadriver'
363
+ platform.run_list.must_equal [ 'a', 'b' ]
364
+ platform.attributes.must_equal({ 'c' => 'd' })
365
+ end
366
+ end
367
+
368
+ describe Jamie::Instance do
369
+
370
+ let(:suite) do
371
+ Jamie::Suite.new({ 'name' => 'suite',
372
+ 'run_list' => 'suite_list', 'attributes' => { 's' => 'ss' } })
373
+ end
374
+
375
+ let(:platform) do
376
+ Jamie::Platform.new({ 'name' => 'platform', 'driver' => 'driver',
377
+ 'run_list' => 'platform_list', 'attributes' => { 'p' => 'pp' } })
378
+ end
379
+
380
+ let(:instance) { Jamie::Instance.new(suite, platform) }
381
+
382
+ it "raises an ArgumentError if suite is missing" do
383
+ proc { Jamie::Instance.new(nil, platform) }.must_raise ArgumentError
384
+ end
385
+
386
+ it "raises an ArgumentError if platform is missing" do
387
+ proc { Jamie::Instance.new(suite, nil) }.must_raise ArgumentError
388
+ end
389
+
390
+ it "returns suite" do
391
+ instance.suite.must_equal suite
392
+ end
393
+
394
+ it "returns platform" do
395
+ instance.platform.must_equal platform
396
+ end
397
+
398
+ it "returns an instance of Jr" do
399
+ instance.jr.must_be_instance_of Jamie::Jr
400
+ end
401
+
402
+ describe "#name" do
403
+
404
+ def combo(suite_name, platform_name)
405
+ Jamie::Instance.new(
406
+ Jamie::Suite.new({ 'name' => suite_name, 'run_list' => [] }),
407
+ Jamie::Platform.new({ 'name' => platform_name, 'driver' => 'd' })
408
+ )
409
+ end
410
+
411
+ it "combines the suite and platform names with a dash" do
412
+ combo('suite', 'platform').name.must_equal "suite-platform"
413
+ end
414
+
415
+ it "squashes periods" do
416
+ combo('suite.ness', 'platform').name.must_equal "suiteness-platform"
417
+ combo('suite', 'platform.s').name.must_equal "suite-platforms"
418
+ combo('s.s.', '.p.p').name.must_equal "ss-pp"
419
+ end
420
+
421
+ it "transforms underscores to dashes" do
422
+ combo('suite_ness', 'platform').name.must_equal "suite-ness-platform"
423
+ combo('suite', 'platform-s').name.must_equal "suite-platform-s"
424
+ combo('_s__s_', 'pp_').name.must_equal "-s--s--pp-"
425
+ end
426
+ end
427
+
428
+ describe "#run_list" do
429
+
430
+ def combo(suite_list, platform_list)
431
+ Jamie::Instance.new(
432
+ Jamie::Suite.new({ 'name' => 'suite', 'run_list' => suite_list }),
433
+ Jamie::Platform.new({ 'name' => 'platform', 'driver' => 'd',
434
+ 'run_list' => platform_list })
435
+ )
436
+ end
437
+
438
+ it "combines the platform then suite run_lists" do
439
+ combo(%w{s1 s2}, %w{p1 p2}).run_list.must_equal %w{p1 p2 s1 s2}
440
+ end
441
+
442
+ it "uses the suite run_list only when platform run_list is empty" do
443
+ combo(%w{sa sb}, nil).run_list.must_equal %w{sa sb}
444
+ end
445
+
446
+ it "returns an emtpy Array if both run_lists are empty" do
447
+ combo([], nil).run_list.must_equal []
448
+ end
449
+ end
450
+
451
+ describe "#attributes" do
452
+
453
+ def combo(suite_attrs, platform_attrs)
454
+ Jamie::Instance.new(
455
+ Jamie::Suite.new({ 'name' => 'suite', 'run_list' => [],
456
+ 'attributes' => suite_attrs }),
457
+ Jamie::Platform.new({ 'name' => 'platform', 'driver' => 'd',
458
+ 'attributes' => platform_attrs })
459
+ )
460
+ end
461
+
462
+ it "merges suite and platform hashes together" do
463
+ combo(
464
+ { 'suite' => { 's1' => 'sv1' } },
465
+ { 'suite' => { 'p1' => 'pv1' }, 'platform' => 'pp' }
466
+ ).attributes.must_equal({
467
+ 'suite' => { 's1' => 'sv1', 'p1' => 'pv1' },
468
+ 'platform' => 'pp'
469
+ })
470
+ end
471
+
472
+ it "merges suite values over platform values" do
473
+ combo(
474
+ { 'common' => { 'c1' => 'xxx' } },
475
+ { 'common' => { 'c1' => 'cv1', 'c2' => 'cv2' } },
476
+ ).attributes.must_equal({
477
+ 'common' => { 'c1' => 'xxx', 'c2' => 'cv2' }
478
+ })
479
+ end
480
+ end
481
+
482
+ it "#dna combines attributes with the run_list" do
483
+ instance.dna.must_equal({ 's' => 'ss', 'p' => 'pp',
484
+ 'run_list' => [ 'platform_list', 'suite_list' ] })
485
+ end
486
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jamie
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0.alpha17
4
+ version: 0.1.0.alpha18
5
5
  prerelease: 6
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: 2012-12-27 00:00:00.000000000 Z
12
+ date: 2012-12-30 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: thor
@@ -75,6 +75,54 @@ dependencies:
75
75
  - - ! '>='
76
76
  - !ruby/object:Gem::Version
77
77
  version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: minitest
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: fakefs
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ - !ruby/object:Gem::Dependency
111
+ name: guard-minitest
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
78
126
  - !ruby/object:Gem::Dependency
79
127
  name: yard
80
128
  requirement: !ruby/object:Gem::Requirement
@@ -139,6 +187,22 @@ dependencies:
139
187
  - - ! '>='
140
188
  - !ruby/object:Gem::Version
141
189
  version: '0'
190
+ - !ruby/object:Gem::Dependency
191
+ name: simplecov
192
+ requirement: !ruby/object:Gem::Requirement
193
+ none: false
194
+ requirements:
195
+ - - ! '>='
196
+ - !ruby/object:Gem::Version
197
+ version: '0'
198
+ type: :development
199
+ prerelease: false
200
+ version_requirements: !ruby/object:Gem::Requirement
201
+ none: false
202
+ requirements:
203
+ - - ! '>='
204
+ - !ruby/object:Gem::Version
205
+ version: '0'
142
206
  - !ruby/object:Gem::Dependency
143
207
  name: countloc
144
208
  requirement: !ruby/object:Gem::Requirement
@@ -167,6 +231,7 @@ files:
167
231
  - .travis.yml
168
232
  - .yardopts
169
233
  - Gemfile
234
+ - Guardfile
170
235
  - LICENSE
171
236
  - README.md
172
237
  - Rakefile
@@ -179,6 +244,7 @@ files:
179
244
  - lib/jamie/thor_tasks.rb
180
245
  - lib/jamie/version.rb
181
246
  - lib/vendor/hash_recursive_merge.rb
247
+ - spec/jamie_spec.rb
182
248
  - templates/plugin/driver.rb.erb
183
249
  - templates/plugin/license_apachev2.erb
184
250
  - templates/plugin/license_gplv2.erb
@@ -186,7 +252,7 @@ files:
186
252
  - templates/plugin/license_mit.erb
187
253
  - templates/plugin/license_reserved.erb
188
254
  - templates/plugin/version.rb.erb
189
- homepage: ''
255
+ homepage: https://github.com/jamie-ci/jamie
190
256
  licenses: []
191
257
  post_install_message:
192
258
  rdoc_options: []
@@ -197,10 +263,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
197
263
  requirements:
198
264
  - - ! '>='
199
265
  - !ruby/object:Gem::Version
200
- version: '0'
201
- segments:
202
- - 0
203
- hash: -4096747563693358273
266
+ version: 1.9.1
204
267
  required_rubygems_version: !ruby/object:Gem::Requirement
205
268
  none: false
206
269
  requirements:
@@ -213,5 +276,6 @@ rubygems_version: 1.8.24
213
276
  signing_key:
214
277
  specification_version: 3
215
278
  summary: A Chef convergence integration test harness
216
- test_files: []
279
+ test_files:
280
+ - spec/jamie_spec.rb
217
281
  has_rdoc: