vanagon 0.7.1 → 0.8.0
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.
- checksums.yaml +4 -4
- data/lib/git/basic_submodules.rb +53 -0
- data/lib/vanagon/component.rb +19 -13
- data/lib/vanagon/component/dsl.rb +6 -5
- data/lib/vanagon/component/source.rb +80 -53
- data/lib/vanagon/component/source/git.rb +129 -20
- data/lib/vanagon/component/source/http.rb +41 -73
- data/lib/vanagon/component/source/local.rb +105 -62
- data/lib/vanagon/platform/deb.rb +8 -0
- data/lib/vanagon/platform/rpm.rb +4 -0
- data/lib/vanagon/project/dsl.rb +3 -1
- data/lib/vanagon/utilities.rb +11 -54
- data/spec/fixtures/files/fake_file_ext.7z +0 -0
- data/spec/fixtures/files/fake_file_ext.bz +0 -0
- data/spec/fixtures/files/fake_file_ext.bz2 +0 -0
- data/spec/fixtures/files/fake_file_ext.cpio +0 -0
- data/spec/fixtures/files/fake_file_ext.gz +0 -0
- data/spec/fixtures/files/fake_file_ext.rar +0 -0
- data/spec/fixtures/files/fake_file_ext.tar +0 -0
- data/spec/fixtures/files/fake_file_ext.tar.bz2 +0 -0
- data/spec/fixtures/files/fake_file_ext.tar.xz +0 -0
- data/spec/fixtures/files/fake_file_ext.tbz +0 -0
- data/spec/fixtures/files/fake_file_ext.tbz2 +0 -0
- data/spec/fixtures/files/fake_file_ext.txz +0 -0
- data/spec/fixtures/files/fake_file_ext.xz +0 -0
- data/spec/fixtures/files/fake_file_ext.z +0 -0
- data/spec/lib/vanagon/component/source/git_spec.rb +25 -17
- data/spec/lib/vanagon/component/source/http_spec.rb +2 -24
- data/spec/lib/vanagon/component/source/{localsource_spec.rb → local_spec.rb} +8 -8
- data/spec/lib/vanagon/component/source_spec.rb +150 -67
- data/spec/lib/vanagon/platform_spec.rb +40 -21
- data/spec/lib/vanagon/project/dsl_spec.rb +28 -3
- data/spec/lib/vanagon/utilities_spec.rb +0 -44
- metadata +28 -13
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -1,33 +1,41 @@
|
|
1
1
|
require 'vanagon/component/source/git'
|
2
2
|
|
3
3
|
describe "Vanagon::Component::Source::Git" do
|
4
|
-
let
|
5
|
-
let
|
6
|
-
let
|
4
|
+
let(:klass) { Vanagon::Component::Source::Git }
|
5
|
+
let(:url) { 'git://github.com/puppetlabs/facter' }
|
6
|
+
let(:ref_tag) { 'refs/tags/2.2.0' }
|
7
|
+
let(:bad_sha) { 'FEEDBEEF' }
|
8
|
+
let(:workdir) { ENV["TMPDIR"] || "/tmp" }
|
9
|
+
|
10
|
+
after(:each) { %x(rm -rf #{workdir}/facter) }
|
11
|
+
|
12
|
+
describe "#initialize" do
|
13
|
+
it "raises error on initialization with an invalid repo" do
|
14
|
+
# this test has a spelling error for the git repo
|
15
|
+
# * this is on purpose *
|
16
|
+
expect { klass.new("#{url}l.git", ref: ref_tag, workdir: workdir) }
|
17
|
+
.to raise_error Vanagon::InvalidRepo
|
18
|
+
end
|
19
|
+
end
|
7
20
|
|
8
21
|
describe "#dirname" do
|
9
|
-
after(:each) { %x(rm -rf #{workdir}/facter) }
|
10
22
|
it "returns the name of the repo" do
|
11
|
-
git_source =
|
12
|
-
expect(git_source.dirname)
|
23
|
+
git_source = klass.new(url, ref: ref_tag, workdir: workdir)
|
24
|
+
expect(git_source.dirname)
|
25
|
+
.to eq('facter')
|
13
26
|
end
|
14
27
|
|
15
28
|
it "returns the name of the repo and strips .git" do
|
16
|
-
git_source =
|
17
|
-
expect(git_source.dirname)
|
29
|
+
git_source = klass.new("#{url}.git", ref: ref_tag, workdir: workdir)
|
30
|
+
expect(git_source.dirname)
|
31
|
+
.to eq('facter')
|
18
32
|
end
|
19
33
|
end
|
20
34
|
|
21
35
|
describe "#fetch" do
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
git_source = Vanagon::Component::Source::Git.new("#{url}l.git", ref, workdir)
|
26
|
-
expect { git_source.fetch }.to raise_error(RuntimeError, "git clone #{url}l.git failed")
|
27
|
-
end
|
28
|
-
it "raises error on checkout failure" do
|
29
|
-
git_source = Vanagon::Component::Source::Git.new("#{url}", "999.9.9", workdir)
|
30
|
-
expect { git_source.fetch }.to raise_error(RuntimeError, "git checkout 999.9.9 failed")
|
36
|
+
it "raises an error on checkout failure with a bad SHA" do
|
37
|
+
expect { klass.new("#{url}", ref: bad_sha, workdir: workdir).fetch }
|
38
|
+
.to raise_error Vanagon::CheckoutFailed
|
31
39
|
end
|
32
40
|
end
|
33
41
|
end
|
@@ -14,39 +14,17 @@ describe "Vanagon::Component::Source::Http" do
|
|
14
14
|
|
15
15
|
describe "#dirname" do
|
16
16
|
it "returns the name of the tarball, minus extension for archives" do
|
17
|
-
http_source = Vanagon::Component::Source::Http.new(tar_url, md5sum, workdir)
|
17
|
+
http_source = Vanagon::Component::Source::Http.new(tar_url, sum: md5sum, workdir: workdir)
|
18
18
|
expect(http_source).to receive(:download).and_return(tar_filename)
|
19
19
|
http_source.fetch
|
20
20
|
expect(http_source.dirname).to eq(tar_dirname)
|
21
21
|
end
|
22
22
|
|
23
23
|
it "returns the current directory for non-archive files" do
|
24
|
-
http_source = Vanagon::Component::Source::Http.new(plaintext_url, md5sum, workdir)
|
24
|
+
http_source = Vanagon::Component::Source::Http.new(plaintext_url, sum: md5sum, workdir: workdir)
|
25
25
|
expect(http_source).to receive(:download).and_return(plaintext_filename)
|
26
26
|
http_source.fetch
|
27
27
|
expect(http_source.dirname).to eq(plaintext_dirname)
|
28
28
|
end
|
29
29
|
end
|
30
|
-
|
31
|
-
describe "#get_extension" do
|
32
|
-
it "returns the extension for valid extensions" do
|
33
|
-
Vanagon::Component::Source::Http::ARCHIVE_EXTENSIONS.each do |ext|
|
34
|
-
filename = "#{file_base}#{ext}"
|
35
|
-
url = File.join(base_url, filename)
|
36
|
-
http_source = Vanagon::Component::Source::Http.new(url, md5sum, workdir)
|
37
|
-
expect(http_source).to receive(:download).and_return(filename)
|
38
|
-
http_source.fetch
|
39
|
-
expect(http_source.get_extension).to eq(ext)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
it "is able to download non archive extensions" do
|
44
|
-
["gpg.txt", "foo.service", "configi.json", "config.repo.txt", "noextensionfile"].each do |filename|
|
45
|
-
url = File.join(base_url, filename)
|
46
|
-
http_source = Vanagon::Component::Source::Http.new(url, md5sum, workdir)
|
47
|
-
expect(http_source).to receive(:download).and_return(filename)
|
48
|
-
http_source.fetch
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
30
|
end
|
@@ -8,7 +8,7 @@ describe "Vanagon::Component::Source::File" do
|
|
8
8
|
|
9
9
|
describe "#fetch" do
|
10
10
|
it "puts the source file in to the workdir" do
|
11
|
-
file = Vanagon::Component::Source::Local.new(plaintext_filename, workdir)
|
11
|
+
file = Vanagon::Component::Source::Local.new(plaintext_filename, workdir: workdir)
|
12
12
|
file.fetch
|
13
13
|
expect(File).to exist("#{workdir}/fake_file.txt")
|
14
14
|
end
|
@@ -16,26 +16,26 @@ describe "Vanagon::Component::Source::File" do
|
|
16
16
|
|
17
17
|
describe "#dirname" do
|
18
18
|
it "returns the name of the tarball, minus extension for archives" do
|
19
|
-
file = Vanagon::Component::Source::Local.new(tar_filename, workdir)
|
19
|
+
file = Vanagon::Component::Source::Local.new(tar_filename, workdir: workdir)
|
20
20
|
file.fetch
|
21
21
|
expect(file.dirname).to eq("fake_dir")
|
22
22
|
end
|
23
23
|
|
24
24
|
it "returns the current directory for non-archive files" do
|
25
|
-
file = Vanagon::Component::Source::Local.new(plaintext_filename, workdir)
|
25
|
+
file = Vanagon::Component::Source::Local.new(plaintext_filename, workdir: workdir)
|
26
26
|
file.fetch
|
27
27
|
expect(file.dirname).to eq("./")
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
-
describe "#
|
31
|
+
describe "#extension" do
|
32
32
|
it "returns the extension for valid extensions" do
|
33
|
-
Vanagon::Component::Source::Local
|
33
|
+
Vanagon::Component::Source::Local.archive_extensions.each do |ext|
|
34
34
|
filename = "#{file_base}#{ext}"
|
35
|
-
file = Vanagon::Component::Source::Local.new(filename, workdir)
|
35
|
+
file = Vanagon::Component::Source::Local.new(filename, workdir: workdir)
|
36
36
|
file.fetch
|
37
|
-
expect(file.
|
37
|
+
expect(file.extension).to eq(ext)
|
38
38
|
end
|
39
39
|
end
|
40
40
|
end
|
41
|
-
end
|
41
|
+
end
|
@@ -1,99 +1,182 @@
|
|
1
1
|
require 'vanagon/component/source'
|
2
2
|
|
3
3
|
describe "Vanagon::Component::Source" do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
let
|
10
|
-
let
|
11
|
-
|
12
|
-
let
|
13
|
-
let
|
14
|
-
let
|
15
|
-
let
|
16
|
-
|
17
|
-
let
|
18
|
-
let
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
end
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
end
|
36
|
-
|
37
|
-
it "
|
38
|
-
expect
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
4
|
+
let(:klass) { Vanagon::Component::Source }
|
5
|
+
before(:each) { klass.rewrite_rules.clear }
|
6
|
+
|
7
|
+
describe ".source" do
|
8
|
+
let(:unrecognized_uri) { "abcd://things" }
|
9
|
+
let(:unrecognized_scheme) { "abcd" }
|
10
|
+
let(:invalid_scheme) { "abcd|things" }
|
11
|
+
|
12
|
+
let(:public_git) { "git://github.com/abcd/things" }
|
13
|
+
let(:private_git) { "git@github.com:abcd/things" }
|
14
|
+
let(:http_git) { "http://github.com/abcd/things" }
|
15
|
+
let(:https_git) { "https://github.com/abcd/things" }
|
16
|
+
|
17
|
+
let(:http_url) { "http://abcd/things" }
|
18
|
+
let(:https_url) { "https://abcd/things" }
|
19
|
+
|
20
|
+
let(:file_url) { "file://things" }
|
21
|
+
|
22
|
+
let(:ref) { "cafebeef" }
|
23
|
+
let(:sum) { "abcd1234" }
|
24
|
+
let(:workdir) { "/tmp" }
|
25
|
+
|
26
|
+
let(:original_git_url) { "git://things.and.stuff/foo-bar.git" }
|
27
|
+
let(:rewritten_git_url) { "git://things.end.stuff/foo-ber.git" }
|
28
|
+
|
29
|
+
let(:original_http_url) { "http://things.and.stuff/foo.tar.gz" }
|
30
|
+
let(:rewritten_http_url) { "http://buildsources.delivery.puppetlabs.net/foo.tar.gz" }
|
31
|
+
|
32
|
+
it "fails on unrecognized URI schemes" do
|
33
|
+
expect { klass.source(unrecognized_uri, workdir: workdir) }
|
34
|
+
.to raise_error(Vanagon::Error)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "fails on invalid URIs" do
|
38
|
+
expect { klass.source(invalid_scheme, workdir: workdir) }
|
39
|
+
.to raise_error(URI::InvalidURIError)
|
40
|
+
end
|
41
|
+
|
42
|
+
context "takes a Git repo" do
|
43
|
+
before do
|
44
|
+
allow_any_instance_of(Vanagon::Component::Source::Git)
|
45
|
+
.to receive(:valid_remote?)
|
46
|
+
.and_return(true)
|
47
|
+
|
48
|
+
allow(Vanagon::Component::Source::Git)
|
49
|
+
.to receive(:valid_remote?)
|
50
|
+
.and_return(true)
|
51
|
+
end
|
52
|
+
|
53
|
+
it "returns a Git object for git@ triplet repositories" do
|
54
|
+
expect(klass.source(private_git, ref: ref, workdir: workdir).class)
|
55
|
+
.to eq Vanagon::Component::Source::Git
|
56
|
+
end
|
57
|
+
|
58
|
+
it "returns a Git object for git:// repositories" do
|
59
|
+
expect(klass.source(public_git, ref: ref, workdir: workdir).class)
|
60
|
+
.to eq Vanagon::Component::Source::Git
|
61
|
+
end
|
62
|
+
|
63
|
+
it "returns a Git object for http:// repositories" do
|
64
|
+
expect(klass.source(http_git, ref: ref, workdir: workdir).class)
|
65
|
+
.to eq Vanagon::Component::Source::Git
|
66
|
+
end
|
67
|
+
|
68
|
+
it "returns a Git object for https:// repositories" do
|
69
|
+
expect(klass.source(https_git, ref: ref, workdir: workdir).class)
|
70
|
+
.to eq Vanagon::Component::Source::Git
|
71
|
+
end
|
72
|
+
|
73
|
+
it "rewrites git:// URLs" do
|
74
|
+
proc_rule = Proc.new { |url| url.gsub('a', 'e') }
|
75
|
+
klass.register_rewrite_rule('git', proc_rule)
|
76
|
+
# Vanagon::Component::Source::Git#url returns a URI object
|
77
|
+
# so to check its value, we cast it to a simple string. It's
|
78
|
+
# hacky for sure, but seems less diagreeable than mangling the
|
79
|
+
# return value in the class itself.
|
80
|
+
expect(klass.source(original_git_url, ref: ref, workdir: workdir).url.to_s)
|
81
|
+
.to eq rewritten_git_url
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
context "takes a HTTP/HTTPS file" do
|
86
|
+
before do
|
87
|
+
allow_any_instance_of(Vanagon::Component::Source::Http)
|
88
|
+
.to receive(:valid_url?)
|
89
|
+
.and_return(true)
|
90
|
+
|
91
|
+
allow(Vanagon::Component::Source::Http)
|
92
|
+
.to receive(:valid_url?)
|
93
|
+
.and_return(true)
|
94
|
+
end
|
95
|
+
|
96
|
+
it "returns an object of the correct type for http:// URLS" do
|
97
|
+
expect(klass.source(http_url, sum: sum, workdir: workdir).class)
|
98
|
+
.to equal(Vanagon::Component::Source::Http)
|
99
|
+
end
|
100
|
+
|
101
|
+
it "returns an object of the correct type for https:// URLS" do
|
102
|
+
expect(klass.source(https_url, sum: sum, workdir: workdir).class)
|
103
|
+
.to equal(Vanagon::Component::Source::Http)
|
104
|
+
end
|
105
|
+
|
106
|
+
before do
|
107
|
+
klass.register_rewrite_rule 'http',
|
108
|
+
'http://buildsources.delivery.puppetlabs.net'
|
109
|
+
end
|
110
|
+
it "applies rewrite rules to HTTP URLs" do
|
111
|
+
expect(klass.source(original_http_url, sum: sum, workdir: workdir).url)
|
112
|
+
.to eq(rewritten_http_url)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
context "takes a local file" do
|
117
|
+
before do
|
118
|
+
allow_any_instance_of(Vanagon::Component::Source::Local)
|
119
|
+
.to receive(:valid_file?)
|
120
|
+
.and_return(true)
|
121
|
+
|
122
|
+
allow(Vanagon::Component::Source::Local)
|
123
|
+
.to receive(:valid_file?)
|
124
|
+
.and_return(true)
|
125
|
+
end
|
126
|
+
|
127
|
+
it "returns an object of the correct type for file:// URLS" do
|
128
|
+
expect(klass.source(file_url, sum: sum, workdir: workdir).class)
|
129
|
+
.to eq Vanagon::Component::Source::Local
|
130
|
+
end
|
57
131
|
end
|
58
132
|
end
|
59
133
|
|
60
|
-
describe "
|
134
|
+
describe ".rewrite" do
|
61
135
|
let(:simple_rule) { Proc.new {|url| url.gsub('a', 'e') } }
|
62
136
|
let(:complex_rule) do
|
63
|
-
Proc.new
|
137
|
+
Proc.new do |url|
|
64
138
|
match = url.match(/github.com\/(.*)$/)
|
65
139
|
"git://github.delivery.puppetlabs.net/#{match[1].gsub('/', '-')}" if match
|
66
|
-
|
140
|
+
end
|
67
141
|
end
|
68
142
|
|
69
143
|
it 'replaces the first section of a url with a string if string is given' do
|
70
|
-
|
71
|
-
|
144
|
+
klass.register_rewrite_rule('http', 'http://buildsources.delivery.puppetlabs.net')
|
145
|
+
|
146
|
+
expect(klass.rewrite('http://things.and.stuff/foo.tar.gz', 'http'))
|
147
|
+
.to eq('http://buildsources.delivery.puppetlabs.net/foo.tar.gz')
|
72
148
|
end
|
73
149
|
|
74
150
|
it 'applies the rule to the url if a proc is given as the rule' do
|
75
|
-
|
76
|
-
|
151
|
+
klass.register_rewrite_rule('http', simple_rule)
|
152
|
+
|
153
|
+
expect(klass.rewrite('http://things.and.stuff/foo.tar.gz', 'http'))
|
154
|
+
.to eq('http://things.end.stuff/foo.ter.gz')
|
77
155
|
end
|
78
156
|
|
79
157
|
it 'applies the rule to the url if a proc is given as the rule' do
|
80
|
-
|
81
|
-
|
158
|
+
klass.register_rewrite_rule('git', complex_rule)
|
159
|
+
|
160
|
+
expect(klass.rewrite('git://github.com/puppetlabs/facter', 'git'))
|
161
|
+
.to eq('git://github.delivery.puppetlabs.net/puppetlabs-facter')
|
82
162
|
end
|
83
163
|
end
|
84
164
|
|
85
|
-
describe "
|
165
|
+
describe ".register_rewrite_rule" do
|
86
166
|
it 'only accepts Proc and String as rule types' do
|
87
|
-
expect{
|
167
|
+
expect { klass.register_rewrite_rule('http', 5) }
|
168
|
+
.to raise_error(Vanagon::Error)
|
88
169
|
end
|
89
170
|
|
90
171
|
it 'rejects invalid protocols' do
|
91
|
-
expect{
|
172
|
+
expect { klass.register_rewrite_rule('gopher', 'abcd') }
|
173
|
+
.to raise_error Vanagon::Error
|
92
174
|
end
|
93
175
|
|
176
|
+
before { klass.register_rewrite_rule('http', 'http://buildsources.delivery.puppetlabs.net') }
|
94
177
|
it 'registers the rule for the given protocol' do
|
95
|
-
|
96
|
-
|
178
|
+
expect(klass.rewrite_rules)
|
179
|
+
.to eq({'http' => 'http://buildsources.delivery.puppetlabs.net'})
|
97
180
|
end
|
98
181
|
end
|
99
182
|
end
|
@@ -4,31 +4,42 @@ describe "Vanagon::Platform" do
|
|
4
4
|
let(:platforms) do
|
5
5
|
[
|
6
6
|
{
|
7
|
-
:name
|
8
|
-
:os_name
|
9
|
-
:os_version
|
10
|
-
:architecture
|
11
|
-
:output_dir
|
12
|
-
:output_dir_with_target
|
13
|
-
:
|
7
|
+
:name => "debian-6-i386",
|
8
|
+
:os_name => "debian",
|
9
|
+
:os_version => "6",
|
10
|
+
:architecture => "i386",
|
11
|
+
:output_dir => "deb/lucid/",
|
12
|
+
:output_dir_with_target => "deb/lucid/thing",
|
13
|
+
:output_dir_empty_string => "deb/lucid/",
|
14
|
+
:block => %Q[
|
15
|
+
platform "debian-6-i386" do |plat|
|
16
|
+
plat.codename "lucid"
|
17
|
+
end ],
|
14
18
|
},
|
15
19
|
{
|
16
|
-
:name
|
17
|
-
:os_name
|
18
|
-
:os_version
|
19
|
-
:architecture
|
20
|
-
:output_dir
|
21
|
-
:output_dir_with_target
|
22
|
-
:
|
20
|
+
:name => "el-5-i386",
|
21
|
+
:os_name => "el",
|
22
|
+
:os_version => "5",
|
23
|
+
:architecture => "i386",
|
24
|
+
:output_dir => "el/5/products/i386",
|
25
|
+
:output_dir_with_target => "el/5/thing/i386",
|
26
|
+
:output_dir_empty_string => "el/5/i386",
|
27
|
+
:block => %Q[ platform "el-5-i386" do |plat| end ],
|
23
28
|
},
|
24
29
|
{
|
25
|
-
:name
|
26
|
-
:os_name
|
27
|
-
:os_version
|
28
|
-
:
|
29
|
-
:
|
30
|
-
:
|
31
|
-
:
|
30
|
+
:name => "debian-6-i386",
|
31
|
+
:os_name => "debian",
|
32
|
+
:os_version => "6",
|
33
|
+
:codename => "lucid",
|
34
|
+
:architecture => "i386",
|
35
|
+
:output_dir => "updated/output",
|
36
|
+
:output_dir_with_target => "updated/output",
|
37
|
+
:output_dir_empty_string => "updated/output",
|
38
|
+
:block => %Q[
|
39
|
+
platform "debian-6-i386" do |plat|
|
40
|
+
plat.codename "lucid"
|
41
|
+
plat.output_dir "updated/output"
|
42
|
+
end ],
|
32
43
|
},
|
33
44
|
]
|
34
45
|
end
|
@@ -67,6 +78,14 @@ describe "Vanagon::Platform" do
|
|
67
78
|
expect(cur_plat._platform.output_dir('thing')).to eq(plat[:output_dir_with_target])
|
68
79
|
end
|
69
80
|
end
|
81
|
+
|
82
|
+
it "does the right thing with empty strings" do
|
83
|
+
platforms.each do |plat|
|
84
|
+
cur_plat = Vanagon::Platform::DSL.new(plat[:name])
|
85
|
+
cur_plat.instance_eval(plat[:block])
|
86
|
+
expect(cur_plat._platform.output_dir('')).to eq(plat[:output_dir_empty_string])
|
87
|
+
end
|
88
|
+
end
|
70
89
|
end
|
71
90
|
|
72
91
|
describe "#architecture" do
|