boxci 0.0.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +19 -0
  3. data/.ruby-version +1 -0
  4. data/CHANGELOG.md +146 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +118 -0
  8. data/Rakefile +13 -0
  9. data/bin/boxci +6 -0
  10. data/boxci.gemspec +28 -0
  11. data/lib/boxci/builder.rb +29 -0
  12. data/lib/boxci/cli.rb +70 -0
  13. data/lib/boxci/config_permutation.rb +15 -0
  14. data/lib/boxci/config_permutation_component.rb +11 -0
  15. data/lib/boxci/config_permutation_component_factory.rb +7 -0
  16. data/lib/boxci/config_permutation_components/rbenv.rb +13 -0
  17. data/lib/boxci/dependency_checker.rb +55 -0
  18. data/lib/boxci/global_config.rb +26 -0
  19. data/lib/boxci/initializer.rb +41 -0
  20. data/lib/boxci/language.rb +35 -0
  21. data/lib/boxci/language_factory.rb +7 -0
  22. data/lib/boxci/languages/ruby.rb +31 -0
  23. data/lib/boxci/project_config.rb +96 -0
  24. data/lib/boxci/provider.rb +35 -0
  25. data/lib/boxci/provider_config.rb +23 -0
  26. data/lib/boxci/provider_factory.rb +7 -0
  27. data/lib/boxci/providers/aws.rb +27 -0
  28. data/lib/boxci/providers/openstack.rb +27 -0
  29. data/lib/boxci/providers/virtualbox.rb +24 -0
  30. data/lib/boxci/templates/Vagrantfile +41 -0
  31. data/lib/boxci/templates/boxci/global_config.yml.tt +1 -0
  32. data/lib/boxci/templates/dot_boxci.yml.tt +11 -0
  33. data/lib/boxci/templates/languages/ruby/main.pp +27 -0
  34. data/lib/boxci/templates/providers/aws/Vagrantfile.erb +45 -0
  35. data/lib/boxci/templates/providers/aws.yml.tt +5 -0
  36. data/lib/boxci/templates/providers/openstack/Vagrantfile.erb +37 -0
  37. data/lib/boxci/templates/providers/openstack.yml.tt +16 -0
  38. data/lib/boxci/templates/providers/virtualbox/Vagrantfile.erb +47 -0
  39. data/lib/boxci/templates/providers/virtualbox.yml.tt +2 -0
  40. data/lib/boxci/templates/puppet/manifests/.empty_directory +0 -0
  41. data/lib/boxci/templates/puppet/modules/.empty_directory +0 -0
  42. data/lib/boxci/test_runner.rb +134 -0
  43. data/lib/boxci/tester.rb +287 -0
  44. data/lib/boxci/version.rb +3 -0
  45. data/lib/boxci.rb +71 -0
  46. data/spec/lib/boxci/builder_spec.rb +86 -0
  47. data/spec/lib/boxci/config_permutation_component_factory_spec.rb +17 -0
  48. data/spec/lib/boxci/config_permutation_component_spec.rb +19 -0
  49. data/spec/lib/boxci/config_permutation_components/rbenv_spec.rb +12 -0
  50. data/spec/lib/boxci/config_permutation_spec.rb +27 -0
  51. data/spec/lib/boxci/dependency_checker_spec.rb +215 -0
  52. data/spec/lib/boxci/global_config_spec.rb +34 -0
  53. data/spec/lib/boxci/initializer_spec.rb +117 -0
  54. data/spec/lib/boxci/language_factory_spec.rb +17 -0
  55. data/spec/lib/boxci/language_spec.rb +31 -0
  56. data/spec/lib/boxci/project_config_spec.rb +218 -0
  57. data/spec/lib/boxci/provider_config_spec.rb +39 -0
  58. data/spec/lib/boxci/provider_factory_spec.rb +17 -0
  59. data/spec/lib/boxci/provider_spec.rb +30 -0
  60. data/spec/lib/boxci/tester_spec.rb +15 -0
  61. data/spec/lib/boxci_spec.rb +176 -0
  62. data/spec/spec_helper.rb +11 -0
  63. metadata +213 -0
@@ -0,0 +1,287 @@
1
+ require "yaml"
2
+ require "net/ssh"
3
+ require "net/scp"
4
+
5
+ module Boxci
6
+ class Tester
7
+ include Thor::Base
8
+ include Thor::Actions
9
+
10
+ def self.exit_on_failure?
11
+ true
12
+ end
13
+
14
+ source_root(File.dirname(__FILE__))
15
+
16
+ def test(options)
17
+ File.open('/tmp/boxci.log', 'w') do |f|
18
+ f.write('')
19
+ end
20
+
21
+ # NOTE: The Signal.trap('SIGTERM') is required for Bamboo's "Stop
22
+ # Build" functionality because Bamboo basically sends a SIGTERM to
23
+ # Boxci and then immediately closes its stdout and stderr pipes
24
+ # before Boxci has had a chance to cleanup. Therefore, it causes
25
+ # Errno::EPIPE exceptions to be raised. It does seem that in general
26
+ # the use of SIGTERM is correct however one would hope that stdout and
27
+ # stderr pipes would stay open until Boxci exits, but sadly they
28
+ # do not.
29
+ Signal.trap('SIGTERM') do
30
+ File.open('/tmp/boxci.log', 'a+') { |f| f.write("Got SIGTERM, going to cleanup...\n") }
31
+
32
+ begin
33
+ cleanup
34
+ rescue Errno::EPIPE => e
35
+ File.open('/tmp/boxci.log', 'a+') { |f| f.write("SIGTERM handler swallowed Errno::EPIPE exception\n") }
36
+ rescue => e
37
+ File.open('/tmp/boxci.log', 'a+') do |f|
38
+ f.write("SIGTERM handler caught exception")
39
+ f.write("#{e.class}\n")
40
+ f.write("#{e.message}\n")
41
+ f.write("#{e.backtrace.join("\n")}\n")
42
+ end
43
+ raise e
44
+ end
45
+
46
+ File.open('/tmp/boxci.log', 'a+') { |f| f.write("Finished cleanup process from SIGTERM\n") }
47
+ exit 255
48
+ end
49
+
50
+ Signal.trap('SIGINT') do
51
+ cleanup
52
+ exit 255
53
+ end
54
+
55
+ # TODO: I don't believe this is necessary as I think Ruby's default
56
+ # handler for SIGPIPE is to ignore it. I need to test this though to
57
+ # verify.
58
+ Signal.trap('SIGPIPE', 'SIG_IGN')
59
+
60
+ @tester_exit_code = 0
61
+ # depencency_checker = Boxci::DependencyChecker.new
62
+ # depencency_checker.verify_all
63
+ initial_config(options)
64
+
65
+ create_project_folder
66
+ create_project_archive
67
+ write_vagrant_file
68
+ write_test_runner
69
+ if @provider_object.requires_plugin?
70
+ install_vagrant_plugin
71
+ add_provider_box
72
+ end
73
+ spin_up_box
74
+ setup_ssh_config
75
+ install_puppet_on_box
76
+ provision_box
77
+ create_artifact_directory
78
+ upload_test_runner
79
+ run_tests
80
+ download_artifacts
81
+ say "Finished!", :green
82
+ rescue Errno::EPIPE => e
83
+ File.open('/tmp/boxci.log', 'a+') do |f|
84
+ f.write("test() method swallowed Errno::EPIPE exception\n")
85
+ end
86
+ rescue => e
87
+ File.open('/tmp/boxci.log', 'a+') do |f|
88
+ f.write("test() method caught exception")
89
+ f.write("#{e.class}\n")
90
+ f.write("#{e.message}\n")
91
+ f.write("#{e.backtrace.join("\n")}\n")
92
+ end
93
+ raise e
94
+ ensure
95
+ cleanup
96
+ exit @tester_exit_code
97
+ end
98
+
99
+ def initial_config(options)
100
+ @gem_path = File.expand_path(File.dirname(__FILE__) + "/../..")
101
+ @puppet_path = File.join(Boxci.project_path, "puppet")
102
+ @project_uid = "#{rand(1000..9000)}-#{rand(1000..9000)}-#{rand(1000..9000)}-#{rand(1000..9000)}"
103
+ @project_workspace_folder = File.join(File.expand_path(ENV['HOME']), '.boxci', @project_uid)
104
+ @options = options
105
+ @provider_config = Boxci.provider_config(provider)
106
+ @project_config = Boxci.project_config
107
+ @provider_object = Boxci::ProviderFactory.build(provider)
108
+ end
109
+
110
+ def provider
111
+ @options["provider"]
112
+ end
113
+
114
+ def verbose?
115
+ @options["verbose"] == true
116
+ end
117
+
118
+ def create_project_folder
119
+ empty_directory @project_workspace_folder, :verbose => verbose?
120
+ end
121
+
122
+ def create_project_archive
123
+ inside Boxci.project_path do
124
+ run "git checkout #{@options["revision"]}", :verbose => verbose?
125
+ run "git submodule update --init", :verbose => verbose?
126
+ run "tar cf #{File.join(@project_workspace_folder, "project.tar")} --exclude .git --exclude \"*.log\" --exclude node_modules .", :verbose => verbose?
127
+ end
128
+ end
129
+
130
+ def write_vagrant_file
131
+ erb_template = File.join("templates", "providers", provider, "Vagrantfile.erb")
132
+ destination = File.join(@project_workspace_folder, "Vagrantfile")
133
+
134
+ template erb_template, destination, :verbose => verbose?
135
+ end
136
+
137
+ def write_test_runner
138
+ destination = File.join(@project_workspace_folder, "test_runner.sh")
139
+ test_runner = Boxci::TestRunner.new(Boxci::LanguageFactory.build(Boxci.project_config.language))
140
+ File.open(destination, 'w+') do |f|
141
+ f.write(test_runner.generate_script)
142
+ end
143
+ end
144
+
145
+ def install_vagrant_plugin
146
+ inside @project_workspace_folder do
147
+ plugin = @provider_object.plugin
148
+ # check for vagrant plugin
149
+ if !system("vagrant plugin list | grep -q #{plugin}")
150
+ # if vagrant plugin is missing
151
+ say "You are missing the Vagrant plugin for #{provider}", :yellow
152
+ # ask user if it's ok to install for them
153
+ if yes?("Would you like to install it now?")
154
+ run "vagrant plugin install #{plugin}", :verbose => verbose?
155
+ end
156
+ else # if vagrant plugin is found
157
+ say "Provider plugin #{plugin} found", :green
158
+ end
159
+ end
160
+ end
161
+
162
+ def add_provider_box
163
+ dummy_box_url = @provider_object.dummy_box_url
164
+ if dummy_box_url
165
+ if run "curl --output /dev/null --silent --head --fail #{dummy_box_url}"
166
+ say "Using specified VM Box URL", :green
167
+ else
168
+ say "Could not resolve the Box URL: #{dummy_box_url}", :red
169
+ end
170
+ else
171
+ inside @project_workspace_folder do
172
+ # check for box
173
+ if !system("vagrant box list | grep dummy | grep -q \"(#{provider})\"")
174
+ # if box is missing
175
+ say "No box found for #{provider}, installing now...", :blue
176
+ run "vagrant box add dummy #{dummy_box_url}", :verbose => verbose?
177
+ else # if vagrant plugin is found
178
+ say "Provider box found", :green
179
+ end
180
+ end
181
+ end
182
+ end
183
+
184
+ def spin_up_box
185
+ inside @project_workspace_folder do
186
+ run "vagrant up --no-provision --provider #{provider}", :verbose => verbose?
187
+ end
188
+ end
189
+
190
+ def setup_ssh_config
191
+ inside @project_workspace_folder do
192
+ run "vagrant ssh-config > ssh-config.local", :verbose => verbose?
193
+ end
194
+ end
195
+
196
+ def install_puppet_on_box
197
+ say "Opening SSH tunnel into the box...", :blue if verbose?
198
+ Net::SSH.start("default", nil, {:config => File.join(@project_workspace_folder, "ssh-config.local")}) do |ssh|
199
+ puppet = ssh.exec! "which puppet"
200
+ unless puppet
201
+ say "Running: sudo apt-get --yes update", :blue if verbose?
202
+ ssh.exec! "sudo apt-get --yes update"
203
+ say "Running: sudo apt-get --yes install puppet", :blue if verbose?
204
+ ssh.exec! "sudo apt-get --yes install puppet"
205
+ end
206
+ end
207
+ end
208
+
209
+ def provision_box
210
+ say "Provisioning the box with puppet...", :blue if verbose?
211
+ inside @project_workspace_folder do
212
+ run "vagrant provision", :verbose => verbose?
213
+ end
214
+ end
215
+
216
+ def create_artifact_directory
217
+ say "Creating the artifact directory on the box...", :blue if verbose?
218
+ Net::SSH.start("default", nil, {:config => File.join(@project_workspace_folder, "ssh-config.local")}) do |ssh|
219
+ ssh.exec! "mkdir -p #{@project_config.artifact_path}"
220
+ end
221
+ end
222
+
223
+ def upload_test_runner
224
+ Net::SSH.start("default", nil, {:config => File.join(@project_workspace_folder, "ssh-config.local")}) do |ssh|
225
+ say "Uploading test_runner.sh to the box...", :blue if verbose?
226
+ ssh.scp.upload! File.join(@project_workspace_folder, "test_runner.sh"), "/vagrant/test_runner.sh"
227
+ say "Running: chmod a+x /vagrant/test_runner.sh", :blue if verbose?
228
+ puts ssh.exec! "chmod a+x /vagrant/test_runner.sh"
229
+ end
230
+ end
231
+
232
+ def run_tests
233
+ exit_code = nil
234
+ exit_signal = nil
235
+ Net::SSH.start("default", nil, {:config => File.join(@project_workspace_folder, "ssh-config.local")}) do |session|
236
+ say "Running the test steps on the box...", :blue if verbose?
237
+ session.open_channel do |channel|
238
+ channel.on_data do |ch, data|
239
+ $stdout.write(data)
240
+ end
241
+
242
+ channel.on_extended_data do |ch, type, data|
243
+ $stderr.write(data)
244
+ end
245
+
246
+ channel.on_request("exit-status") do |ch, data|
247
+ exit_code = data.read_long
248
+ @tester_exit_code = exit_code
249
+ end
250
+
251
+ channel.exec "/vagrant/test_runner.sh"
252
+ end
253
+ session.loop
254
+ end
255
+ end
256
+
257
+ def download_artifacts
258
+ Net::SSH.start("default", nil, {:config => File.join(@project_workspace_folder, "ssh-config.local")}) do |ssh|
259
+ say "Downloading the reports...", :blue if verbose?
260
+ puts ssh.exec! "cd #{@project_config.artifact_path} && tar cf /tmp/boxci_artifacts.tar ."
261
+ ssh.scp.download! "/tmp/boxci_artifacts.tar", '.'
262
+ end
263
+ end
264
+
265
+ def cleanup
266
+ if @project_workspace_folder && File.directory?(@project_workspace_folder)
267
+ # NOTE: The begin rescue for Errno::EPIPE and the &>>
268
+ # /tmp/boxci.log in the backtick execution ARE required for
269
+ # Bamboo's "Stop Build" functionality because Bamboo basically sends
270
+ # a SIGTERM to Boxci and then immediately closes its stdout and
271
+ # stderr pipes before Boxci has had a chance to cleanup. Therefore,
272
+ # it causes Errno::EPIPE exceptions to be raised.
273
+ begin
274
+ say "Cleaning up...", :blue
275
+ rescue Errno::EPIPE => e
276
+ File.open('/tmp/boxci.log', 'a+') { |f| f.write("Cleaning up...\n") }
277
+ end
278
+ inside @project_workspace_folder do
279
+ `vagrant destroy -f >> /tmp/boxci.log 2>&1`
280
+ # run "vagrant destroy -f", :verbose => verbose?, :capture => true
281
+ end
282
+ `rm -rf #{@project_workspace_folder} >> /tmp/boxci.log 2>&1`
283
+ # remove_dir @project_workspace_folder, :verbose => verbose?, :capture => true
284
+ end
285
+ end
286
+ end
287
+ end
@@ -0,0 +1,3 @@
1
+ module Boxci
2
+ VERSION = "0.0.30"
3
+ end
data/lib/boxci.rb ADDED
@@ -0,0 +1,71 @@
1
+ require 'boxci/version'
2
+ require 'boxci/project_config'
3
+ require 'boxci/global_config'
4
+ require 'boxci/provider_config'
5
+ require 'boxci/initializer'
6
+ require 'boxci/builder'
7
+ require 'boxci/dependency_checker'
8
+ require 'boxci/tester'
9
+ require 'boxci/language_factory'
10
+ require 'boxci/language'
11
+ require 'boxci/languages/ruby'
12
+ require 'boxci/provider_factory'
13
+ require 'boxci/provider'
14
+ require 'boxci/providers/virtualbox'
15
+ require 'boxci/providers/aws'
16
+ require 'boxci/providers/openstack'
17
+ require 'boxci/config_permutation'
18
+ require 'boxci/config_permutation_component'
19
+ require 'boxci/config_permutation_component_factory'
20
+ require 'boxci/config_permutation_components/rbenv'
21
+ require 'boxci/test_runner'
22
+
23
+ module Boxci
24
+ class MissingDependency < StandardError; end
25
+ class PureVirtualMethod < StandardError; end
26
+
27
+ def self.project_config
28
+ if @project_config
29
+ return @project_config
30
+ else
31
+ @project_config = Boxci::ProjectConfig.new
32
+ @project_config.load
33
+ return @project_config
34
+ end
35
+ end
36
+
37
+ def self.global_config
38
+ if @global_config
39
+ return @global_config
40
+ else
41
+ @global_config = Boxci::GlobalConfig.new
42
+ @global_config.load
43
+ return @global_config
44
+ end
45
+ end
46
+
47
+ def self.provider_config(provider)
48
+ if @provider_config
49
+ return @provider_config
50
+ else
51
+ @provider_config = Boxci::ProviderConfig.new(provider)
52
+ @provider_config.load
53
+ return @provider_config
54
+ end
55
+ end
56
+
57
+ def self.default_provider
58
+ if global_config.default_provider
59
+ return global_config.default_provider
60
+ else
61
+ return ::Boxci::CLI::DEFAULT_PROVIDER
62
+ end
63
+ end
64
+
65
+ def self.project_path
66
+ @project_path ||= File.expand_path(%x(pwd)).strip
67
+ end
68
+ end
69
+
70
+ # TODO: Restructure to prevent this from needing to be here.
71
+ require 'boxci/cli'
@@ -0,0 +1,86 @@
1
+ require "spec_helper"
2
+
3
+ describe Boxci::Builder do
4
+ describe "#build" do
5
+ it "generates project Vagrantfile" do
6
+ allow(subject).to receive(:generate_starter_puppet_manifest)
7
+ expect(subject).to receive(:generate_project_vagrantfile)
8
+ subject.build
9
+ end
10
+
11
+ it "generates starter Puppet manifiest" do
12
+ allow(subject).to receive(:generate_project_vagrantfile)
13
+ expect(subject).to receive(:generate_starter_puppet_manifest)
14
+ subject.build
15
+ end
16
+ end
17
+
18
+ describe "#generate_project_vagrantfile" do
19
+ let(:project_path) { "/some/path" }
20
+ let(:dependency_checker) { double(Boxci::DependencyChecker, :verify_boxci_config => nil) }
21
+
22
+ it "verifies the boxci config file is present" do
23
+ allow(subject).to receive(:template)
24
+ allow(Boxci).to receive(:project_config)
25
+ allow(Boxci::DependencyChecker).to receive(:new).and_return(dependency_checker)
26
+ expect(dependency_checker).to receive(:verify_boxci_config)
27
+ subject.generate_project_vagrantfile
28
+ end
29
+
30
+ it "gets boxci project config hash" do
31
+ allow(subject).to receive(:template)
32
+ allow(Boxci::DependencyChecker).to receive(:new).and_return(dependency_checker)
33
+ expect(Boxci).to receive(:project_config)
34
+ subject.generate_project_vagrantfile
35
+ end
36
+
37
+ it "assigns the boxci project config to instance variable" do
38
+ allow(subject).to receive(:template)
39
+ allow(Boxci::DependencyChecker).to receive(:new).and_return(dependency_checker)
40
+ project_config_double = double
41
+ allow(Boxci).to receive(:project_config).and_return(project_config_double)
42
+ subject.generate_project_vagrantfile
43
+ expect(subject.instance_variable_get(:@project_config)).to eq(project_config_double)
44
+ end
45
+
46
+ it "copies the Vagrantfile template for the specified language to the user's home directory" do
47
+ allow(Boxci).to receive(:project_config)
48
+ allow(Boxci::DependencyChecker).to receive(:new).and_return(dependency_checker)
49
+ expect(subject).to receive(:template).with("templates/Vagrantfile", File.join(Boxci.project_path, "Vagrantfile"))
50
+ subject.generate_project_vagrantfile
51
+ end
52
+ end
53
+
54
+ describe "#generate_starter_puppet_manifiest" do
55
+ let(:project_path) { "/some/path" }
56
+
57
+ before do
58
+ allow(Boxci).to receive(:project_path).and_return(project_path)
59
+ allow(Boxci).to receive(:project_config).and_return(double(:language => 'ruby'))
60
+ end
61
+
62
+ it "copies the template to the repo" do
63
+ language_factory_double = double(:generate_starter_puppet_manifest => nil)
64
+ allow(Boxci::LanguageFactory).to receive(:build).and_return(language_factory_double)
65
+ expect(subject).to receive(:directory).with("templates/puppet", File.join(Boxci.project_path, "puppet"))
66
+ subject.generate_starter_puppet_manifest
67
+ end
68
+
69
+ it "builds a boxci language object" do
70
+ allow(subject).to receive(:directory)
71
+ language_double = double
72
+ project_config_double = double(:language => language_double)
73
+ allow(Boxci).to receive(:project_config).and_return(project_config_double)
74
+ expect(Boxci::LanguageFactory).to receive(:build).with(language_double).and_return(double.as_null_object)
75
+ subject.generate_starter_puppet_manifest
76
+ end
77
+
78
+ it "generates the language specific starter puppet manifest" do
79
+ allow(subject).to receive(:directory)
80
+ language_obj_double = double
81
+ allow(Boxci::LanguageFactory).to receive(:build).and_return(language_obj_double)
82
+ expect(language_obj_double).to receive(:generate_starter_puppet_manifest)
83
+ subject.generate_starter_puppet_manifest
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ describe Boxci::ConfigPermutationComponentFactory do
4
+ describe ".build" do
5
+ it "gets the constant for the config permutation component class" do
6
+ expect(Boxci::ConfigPermutationComponents).to receive(:const_get).with('Rbenv').and_return(double.as_null_object)
7
+ subject.build('rbenv', 'foo')
8
+ end
9
+
10
+ it "constructs a new instance of the config permutation component const it previously grabbed" do
11
+ comp = double
12
+ allow(Boxci::ConfigPermutationComponents).to receive(:const_get).with('Rbenv').and_return(comp)
13
+ expect(comp).to receive(:new)
14
+ subject.build('rbenv', 'foo')
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ describe Boxci::ConfigPermutationComponent do
4
+ subject { Boxci::ConfigPermutationComponent }
5
+
6
+ describe '#initialize' do
7
+ it 'assigns the given value to an instance variable' do
8
+ config_permutation_component = subject.new('foeue')
9
+ expect(config_permutation_component.instance_variable_get(:@val)).to eq('foeue')
10
+ end
11
+ end
12
+
13
+ describe '#switch_to_script' do
14
+ it 'raises exception stating it is pure virtual method' do
15
+ config_permutation_component = subject.new('foeue')
16
+ expect { config_permutation_component.switch_to_script }.to raise_error(Boxci::PureVirtualMethod)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+
3
+ describe Boxci::ConfigPermutationComponents::Rbenv do
4
+ subject { Boxci::ConfigPermutationComponents::Rbenv }
5
+
6
+ describe '#switch_to_script' do
7
+ it 'generates bash script to switch ruby verisons with rbenv' do
8
+ comp = subject.new('2.1.0')
9
+ expect(comp.switch_to_script).to eq("echo \"Switching to ruby 2.1.0\"\nrbenv local 2.1.0\necho \"Swithed to ruby `ruby --version`\"\n")
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ describe Boxci::ConfigPermutation do
4
+ describe "#initialize" do
5
+ it "constructs an instance of a Boxci::ConfigPermutation given an array of config permutation components" do
6
+ config_permutation_components = [double, double, double]
7
+ config_permutation = Boxci::ConfigPermutation.new(config_permutation_components)
8
+ end
9
+
10
+ it "assigns the given components array to an instance variable" do
11
+ config_permutation_components = [double, double, double]
12
+ config_permutation = Boxci::ConfigPermutation.new(config_permutation_components)
13
+ expect(config_permutation.instance_variable_get(:@components)).to eq(config_permutation_components)
14
+ end
15
+ end
16
+
17
+ describe "#switch_to_script" do
18
+ it "grabs the switch to scripts of each of the components and joins them together with newlines" do
19
+ comp1 = double(:switch_to_script => 'a')
20
+ comp2 = double(:switch_to_script => 'b')
21
+ comp3 = double(:switch_to_script => 'c')
22
+ config_permutation_components = [comp1, comp2, comp3]
23
+ config_permutation = Boxci::ConfigPermutation.new(config_permutation_components)
24
+ expect(config_permutation.switch_to_script).to eq("a\nb\nc")
25
+ end
26
+ end
27
+ end