boxci 0.0.30

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