omnijack 0.1.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.
Files changed (44) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/.travis.yml +6 -0
  4. data/CHANGELOG.md +11 -0
  5. data/Gemfile +6 -0
  6. data/LICENSE.txt +15 -0
  7. data/NOTICE +5 -0
  8. data/README.md +119 -0
  9. data/Rakefile +23 -0
  10. data/features/list.feature +19 -0
  11. data/features/metadata.feature +43 -0
  12. data/features/platforms.feature +23 -0
  13. data/features/step_definitions/list.rb +12 -0
  14. data/features/step_definitions/metadata.rb +20 -0
  15. data/features/step_definitions/platforms.rb +8 -0
  16. data/features/step_definitions/project.rb +20 -0
  17. data/features/support/env.rb +4 -0
  18. data/lib/omnijack/config.rb +67 -0
  19. data/lib/omnijack/list.rb +94 -0
  20. data/lib/omnijack/metadata.rb +244 -0
  21. data/lib/omnijack/platforms.rb +96 -0
  22. data/lib/omnijack/project/metaprojects.rb +38 -0
  23. data/lib/omnijack/project.rb +63 -0
  24. data/lib/omnijack/version.rb +24 -0
  25. data/lib/omnijack.rb +54 -0
  26. data/omnijack.gemspec +37 -0
  27. data/spec/omnijack/config_spec.rb +55 -0
  28. data/spec/omnijack/list_spec.rb +133 -0
  29. data/spec/omnijack/metadata_spec.rb +577 -0
  30. data/spec/omnijack/platforms_spec.rb +132 -0
  31. data/spec/omnijack/project/angry_chef_spec.rb +55 -0
  32. data/spec/omnijack/project/chef_container_spec.rb +55 -0
  33. data/spec/omnijack/project/chef_dk_spec.rb +55 -0
  34. data/spec/omnijack/project/chef_server_spec.rb +55 -0
  35. data/spec/omnijack/project/chef_spec.rb +55 -0
  36. data/spec/omnijack/project_spec.rb +52 -0
  37. data/spec/omnijack_spec.rb +109 -0
  38. data/spec/spec_helper.rb +38 -0
  39. data/spec/support/real_test_data.json +131 -0
  40. data/vendor/chef/LICENSE +201 -0
  41. data/vendor/chef/NOTICE +21 -0
  42. data/vendor/chef/lib/chef/exceptions.rb +353 -0
  43. data/vendor/chef/lib/chef/mixin/params_validate.rb +242 -0
  44. metadata +276 -0
@@ -0,0 +1,244 @@
1
+ # Encoding: UTF-8
2
+ #
3
+ # Author:: Jonathan Hartman (<j@p4nt5.com>)
4
+ #
5
+ # Copyright (C) 2014, Jonathan Hartman
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 'ohai'
20
+ require 'open-uri'
21
+ require_relative 'config'
22
+ require_relative '../omnijack'
23
+ require_relative '../../vendor/chef/lib/chef/exceptions'
24
+ require_relative '../../vendor/chef/lib/chef/mixin/params_validate'
25
+
26
+ class Omnijack
27
+ # A class for representing an Omnitruck metadata object
28
+ #
29
+ # @author Jonathan Hartman <j@p4nt5.com>
30
+ class Metadata < Omnijack
31
+ include ::Chef::Mixin::ParamsValidate
32
+ include Config
33
+
34
+ def initialize(name, args = {})
35
+ super
36
+ args.each { |k, v| send(k, v) unless v.nil? } unless args.nil?
37
+ end
38
+
39
+ #
40
+ # Set up an accessor method for each piece of metadata
41
+ #
42
+ METADATA_ATTRIBUTES.each do |a|
43
+ define_method(a) { to_h[a] }
44
+ end
45
+ define_method(:filename) { to_h[:filename] }
46
+
47
+ #
48
+ # Make metadata accessible via hash keys
49
+ #
50
+ # @param [Symbol] key
51
+ # @return [String, NilClass]
52
+ #
53
+ def [](key)
54
+ to_h[key]
55
+ end
56
+
57
+ #
58
+ # Offer a hash representation of the metadata
59
+ #
60
+ # @return [Hash]
61
+ #
62
+ def to_h
63
+ raw_metadata.split("\n").each_with_object({}) do |line, hsh|
64
+ key = line.split[0].to_sym
65
+ val = case line.split[1]
66
+ when 'true' then true
67
+ when 'false' then false
68
+ else line.split[1]
69
+ end
70
+ hsh[key] = val
71
+ hsh[:filename] = val.split('/')[-1] if key == :url
72
+ end
73
+ end
74
+
75
+ #
76
+ # Use the raw metadata string as a string representation
77
+ #
78
+ define_method(:to_s) { raw_metadata }
79
+
80
+ #
81
+ # The version of the project
82
+ #
83
+ # @param [String, NilClass] arg
84
+ # @return [String]
85
+ #
86
+ def version(arg = nil)
87
+ set_or_return(:version,
88
+ arg,
89
+ kind_of: String,
90
+ default: 'latest',
91
+ callbacks: {
92
+ 'Invalid version string' => ->(a) { valid_version?(a) }
93
+ })
94
+ end
95
+
96
+ #
97
+ # Whether to enable prerelease and/or nightly packages
98
+ #
99
+ # @param [TrueClass, FalseClass, NilClass] arg
100
+ # @return [TrueClass, FalseClass]
101
+ #
102
+ [:prerelease, :nightlies].each do |m|
103
+ define_method(m) do |arg = nil|
104
+ set_or_return(m, arg, kind_of: [TrueClass, FalseClass], default: false)
105
+ end
106
+ end
107
+
108
+ #
109
+ # The name of the desired platform
110
+ #
111
+ # @param [String, NilClass]
112
+ # @return [String]
113
+ #
114
+ def platform(arg = nil)
115
+ set_or_return(:platform, arg, kind_of: String, default: node[:platform])
116
+ end
117
+
118
+ #
119
+ # The version of the desired platform
120
+ #
121
+ # @param [String, NilClass] arg
122
+ # @return [String]
123
+ #
124
+ def platform_version(arg = nil)
125
+ # TODO: The platform version parser living in `node` means passing e.g.
126
+ # '10.9.2' here won't result in it being shortened to '10.9'
127
+ set_or_return(:platform_version,
128
+ arg,
129
+ kind_of: String,
130
+ default: node[:platform_version])
131
+ end
132
+
133
+ #
134
+ # The machine architecture of the desired platform
135
+ #
136
+ # @param [String, NilClass]
137
+ # @return [String]
138
+ #
139
+ def machine_arch(arg = nil)
140
+ set_or_return(:machine_arch,
141
+ arg,
142
+ kind_of: String,
143
+ default: node[:kernel][:machine])
144
+ end
145
+
146
+ private
147
+
148
+ #
149
+ # Fetch the raw metadata from the configured URI
150
+ #
151
+ # @return [String]
152
+ #
153
+ def raw_metadata
154
+ @raw_metadata ||= api_url.open.read
155
+ end
156
+
157
+ #
158
+ # Construct the full API query URL from base + endpoint + params
159
+ #
160
+ # @return [URI::HTTP, URI::HTTPS]
161
+ #
162
+ def api_url
163
+ @api_url ||= URI.parse(
164
+ File.join(base_url, "#{endpoint}?#{URI.encode_www_form(query_params)}")
165
+ )
166
+ end
167
+
168
+ #
169
+ # Convert all the metadata attrs into params Omnitruck understands
170
+ #
171
+ # @return [Hash]
172
+ #
173
+ def query_params
174
+ { v: version,
175
+ prerelease: prerelease,
176
+ nightlies: nightlies,
177
+ p: platform,
178
+ pv: platform_version,
179
+ m: machine_arch }
180
+ end
181
+
182
+ #
183
+ # Return the API endpoint for the metadata of this project
184
+ #
185
+ # @return [String]
186
+ #
187
+ def endpoint
188
+ OMNITRUCK_PROJECTS[name][:endpoints][:metadata]
189
+ end
190
+
191
+ #
192
+ # Fetch and return node data from Ohai
193
+ #
194
+ # @return [Mash]
195
+ #
196
+ def node
197
+ unless @node
198
+ @node = Ohai::System.new.all_plugins('platform')[0].data
199
+ case @node[:platform]
200
+ when 'mac_os_x'
201
+ @node[:platform_version] = platform_version_mac_os_x
202
+ when 'windows'
203
+ @node[:platform_version] = platform_version_windows
204
+ end
205
+ end
206
+ @node
207
+ end
208
+
209
+ #
210
+ # Apply special logic for the version of an OS X platform
211
+ #
212
+ # @return [String]
213
+ #
214
+ def platform_version_mac_os_x
215
+ node[:platform_version].match(/^[0-9]+\.[0-9]+/).to_s
216
+ end
217
+
218
+ #
219
+ # Apply special logic for the version of a Windows platform
220
+ #
221
+ # @return [String]
222
+ #
223
+ def platform_version_windows
224
+ # Make a best guess and assume a server OS
225
+ # See: http://msdn.microsoft.com/en-us/library/windows/
226
+ # desktop/ms724832(v=vs.85).aspx
227
+ {
228
+ '6.3' => '2012r2', '6.2' => '2012', '6.1' => '2008r2', '6.0' => '2008',
229
+ '5.2' => '2003r2', '5.1' => 'xp', '5.0' => '2000'
230
+ }[node[:platform_version].match(/^[0-9]+\.[0-9]+/).to_s]
231
+ end
232
+
233
+ #
234
+ # Determine whether a string is a valid version string
235
+ #
236
+ # @param [String] arg
237
+ # @return [TrueClass, FalseClass]
238
+ #
239
+ def valid_version?(arg)
240
+ return true if arg == 'latest'
241
+ arg.match(/^[0-9]+\.[0-9]+\.[0-9]+(-[0-9]+)?$/) ? true : false
242
+ end
243
+ end
244
+ end
@@ -0,0 +1,96 @@
1
+ # Encoding: UTF-8
2
+ #
3
+ # Author:: Jonathan Hartman (<j@p4nt5.com>)
4
+ #
5
+ # Copyright (C) 2014, Jonathan Hartman
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 'json'
20
+ require 'open-uri'
21
+ require_relative 'config'
22
+ require_relative '../omnijack'
23
+
24
+ class Omnijack
25
+ # A class for representing an Omnitruck list of platform names
26
+ #
27
+ # @author Jonathan Hartman <j@p4nt5.com>
28
+ class Platforms < Omnijack
29
+ include Config
30
+
31
+ # TODO: Lots of duplicate code in platforms and list
32
+
33
+ #
34
+ # Make list items accessible via methods
35
+ #
36
+ # @param [Symbol] method_id
37
+ #
38
+ def method_missing(method_id, args = nil)
39
+ args.nil? && to_h[method_id] || super
40
+ end
41
+
42
+ #
43
+ # Make list items accessible via hash keys
44
+ #
45
+ # @param [Symbol] key
46
+ # @return [String, NilClass]
47
+ #
48
+ def [](key)
49
+ to_h[key]
50
+ end
51
+
52
+ #
53
+ # Offer a hash representation of the list
54
+ #
55
+ # @return [Hash]
56
+ #
57
+ def to_h
58
+ # TODO: Use a Mash -- some keys are better off addressed as strings
59
+ JSON.parse(raw_data, symbolize_names: true)
60
+ end
61
+
62
+ #
63
+ # Use the raw data string as a string representation
64
+ #
65
+ define_method(:to_s) { raw_data }
66
+
67
+ private
68
+
69
+ #
70
+ # Fetch the raw list from the configured URI
71
+ #
72
+ # @return [String]
73
+ #
74
+ def raw_data
75
+ @raw_data ||= api_url.open.read
76
+ end
77
+
78
+ #
79
+ # Construct the full API query URL from base + endpoint
80
+ #
81
+ # @return [URI::HTTP, URI::HTTPS]
82
+ #
83
+ def api_url
84
+ @api_url ||= URI.parse(::File.join(base_url, endpoint))
85
+ end
86
+
87
+ #
88
+ # Return the API endpoint for the package list of this project
89
+ #
90
+ # @return [String]
91
+ #
92
+ def endpoint
93
+ OMNITRUCK_PROJECTS[name][:endpoints][:platform_names]
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,38 @@
1
+ # Encoding: UTF-8
2
+ #
3
+ # Author:: Jonathan Hartman (<j@p4nt5.com>)
4
+ #
5
+ # Copyright (C) 2014, Jonathan Hartman
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_relative '../config'
20
+ require_relative '../project'
21
+
22
+ class Omnijack
23
+ class Project < Omnijack
24
+ end
25
+ end
26
+
27
+ # Dynamically define classes for each configured project
28
+ #
29
+ # @author Jonathan Hartman <j@p4nt5.com>
30
+ Omnijack::Config::OMNITRUCK_PROJECTS.each do |project_name, _|
31
+ klass = Class.new(Omnijack::Project) do
32
+ define_method(:initialize) do |args = {}|
33
+ super(project_name, args)
34
+ end
35
+ end
36
+ class_name = project_name.to_s.split('_').map(&:capitalize).join
37
+ Omnijack::Project.const_set(class_name, klass)
38
+ end
@@ -0,0 +1,63 @@
1
+ # Encoding: UTF-8
2
+ #
3
+ # Author:: Jonathan Hartman (<j@p4nt5.com>)
4
+ #
5
+ # Copyright (C) 2014, Jonathan Hartman
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_relative '../omnijack'
20
+ require_relative 'config'
21
+ require_relative 'list'
22
+ require_relative 'metadata'
23
+ require_relative 'platforms'
24
+ require_relative 'project/metaprojects'
25
+ require_relative '../../vendor/chef/lib/chef/exceptions'
26
+ require_relative '../../vendor/chef/lib/chef/mixin/params_validate'
27
+
28
+ class Omnijack
29
+ # A parent project that can contain metadata, a pkg list, and platforms
30
+ #
31
+ # @author Jonathan Hartman <j@p4nt5.com>
32
+ class Project < Omnijack
33
+ include Config
34
+
35
+ #
36
+ # The Metadata instance for the project
37
+ #
38
+ # @return [Omnijack::Metadata]
39
+ #
40
+ def metadata
41
+ # TODO: This requires too much knowledge of the Metadata class
42
+ @metadata ||= Metadata.new(name, args)
43
+ end
44
+
45
+ #
46
+ # The full list instance for the project
47
+ #
48
+ # @return [Omnijack::List]
49
+ #
50
+ def list
51
+ @list ||= List.new(name, args)
52
+ end
53
+
54
+ #
55
+ # The platform names instance for the project
56
+ #
57
+ # @return [Omnijack::Platforms]
58
+ #
59
+ def platforms
60
+ @platforms ||= Platforms.new(name, args)
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,24 @@
1
+ # Encoding: UTF-8
2
+ #
3
+ # Author:: Jonathan Hartman (<j@p4nt5.com>)
4
+ #
5
+ # Copyright (C) 2014, Jonathan Hartman
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
+ # Version string for Chef::Package::Metadata
20
+ #
21
+ # @author Jonathan Hartman <j@p4nt5.com>
22
+ class Omnijack
23
+ VERSION = '0.1.0'
24
+ end
data/lib/omnijack.rb ADDED
@@ -0,0 +1,54 @@
1
+ # Encoding: UTF-8
2
+ #
3
+ # Author:: Jonathan Hartman (<j@p4nt5.com>)
4
+ #
5
+ # Copyright (C) 2014, Jonathan Hartman
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_relative '../vendor/chef/lib/chef/exceptions'
20
+ require_relative '../vendor/chef/lib/chef/mixin/params_validate'
21
+ require_relative 'omnijack/config'
22
+ require_relative 'omnijack/project'
23
+ require_relative 'omnijack/list'
24
+ require_relative 'omnijack/metadata'
25
+ require_relative 'omnijack/platforms'
26
+ require_relative 'omnijack/version'
27
+
28
+ # Provide a base class with some commons everyone can inherit
29
+ #
30
+ # @author Jonathan Hartman <j@p4nt5.com>
31
+ class Omnijack
32
+ include ::Chef::Mixin::ParamsValidate
33
+ include Config
34
+
35
+ def initialize(name, args = {})
36
+ @name = name.to_sym
37
+ @args = args
38
+ base_url(args[:base_url]) if args && args[:base_url]
39
+ end
40
+ attr_reader :name, :args
41
+
42
+ #
43
+ # The base URL of the Omnitruck API
44
+ #
45
+ # @param [String, NilClass] arg
46
+ # @return [String]
47
+ #
48
+ def base_url(arg = nil)
49
+ # TODO: Better URL validation
50
+ set_or_return(:base_url, arg, kind_of: String, default: DEFAULT_BASE_URL)
51
+ end
52
+
53
+ # TODO: Every class' `endpoint` method is similar enough they could go here
54
+ end
data/omnijack.gemspec ADDED
@@ -0,0 +1,37 @@
1
+ # Encoding: UTF-8
2
+
3
+ lib = File.expand_path('../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'omnijack/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'omnijack'
9
+ spec.version = Omnijack::VERSION
10
+ spec.authors = ['Jonathan Hartman']
11
+ spec.email = %w(j@p4nt5.com)
12
+ spec.summary = 'A pallet jack to unload data from the Omnitruck'
13
+ spec.description = 'A pallet jack to unload data from the Omnitruck'
14
+ spec.homepage = 'https://rubygems.org/gems/omnijack'
15
+ spec.license = 'Apache v2.0'
16
+
17
+ spec.files = `git ls-files -z`.split("\x0")
18
+ spec.executables = spec.files.grep(/^bin\//) { |f| File.basename(f) }
19
+ spec.test_files = spec.files.grep(/^(test|spec|features)\//)
20
+ spec.require_paths = %w(lib)
21
+
22
+ spec.required_ruby_version = '>= 1.9.3'
23
+
24
+ spec.add_dependency 'ohai'
25
+ spec.add_dependency 'json'
26
+
27
+ spec.add_development_dependency 'bundler'
28
+ spec.add_development_dependency 'rake'
29
+ spec.add_development_dependency 'rubocop'
30
+ spec.add_development_dependency 'cane'
31
+ spec.add_development_dependency 'countloc'
32
+ spec.add_development_dependency 'rspec'
33
+ spec.add_development_dependency 'simplecov'
34
+ spec.add_development_dependency 'simplecov-console'
35
+ spec.add_development_dependency 'coveralls'
36
+ spec.add_development_dependency 'cucumber'
37
+ end
@@ -0,0 +1,55 @@
1
+ # Encoding: UTF-8
2
+ #
3
+ # Author:: Jonathan Hartman (<j@p4nt5.com>)
4
+ #
5
+ # Copyright (C) 2014, Jonathan Hartman
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_relative '../spec_helper'
20
+ require_relative '../../lib/omnijack/config'
21
+
22
+ describe Omnijack::Config do
23
+ describe 'DEFAULT_BASE_URL' do
24
+ it 'uses the official Chef API' do
25
+ expected = 'https://www.getchef.com/chef'
26
+ expect(described_class::DEFAULT_BASE_URL).to eq(expected)
27
+ end
28
+ end
29
+
30
+ describe 'OMNITRUCK_PROJECTS' do
31
+ it 'recognizes all the valid Omnitruck projects' do
32
+ expected = [:angry_chef, :chef, :chef_dk, :chef_container, :chef_server]
33
+ expect(described_class::OMNITRUCK_PROJECTS.keys).to eq(expected)
34
+ end
35
+
36
+ described_class::OMNITRUCK_PROJECTS.each do |project, attrs|
37
+ attrs[:endpoints].each do |name, endpoint|
38
+ it "uses a valid #{project}::#{name} endpoint" do
39
+ url = "http://www.getchef.com/chef#{endpoint}"
40
+ url << '?v=latest&p=ubuntu&pv=12.04&m=x86_64' if name == :metadata
41
+
42
+ # Some endpoints aren't available on Chef's public Omnitruck API
43
+ if [:angry_chef, :chef_dk, :chef_container].include?(project) && \
44
+ [:package_list, :platform_names].include?(name)
45
+ expected = 404
46
+ else
47
+ expected = 200
48
+ end
49
+
50
+ expect(Net::HTTP.get_response(URI(url)).code.to_i).to eq(expected)
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end