chef-cli 1.0.13 → 1.0.14

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7b5f6126a4c90780ea0e12bfb21478a40bce4d2432735b5ce2e36c6114414d06
4
- data.tar.gz: beed8e750ba8df274e82be2aa11238a07d55968d1686b7c1f0393c303639dc5f
3
+ metadata.gz: 86cf14e43550aba70dc825275b3a3a6b86513da7d550a0bc610175a769d53d56
4
+ data.tar.gz: 3fc61ee5fcd4aaa816d370840383e078a5597d8d7cb71fdcf57390758ba380d1
5
5
  SHA512:
6
- metadata.gz: 82d425973ce0b4e17c55a2f536773a5c9ad40ba50bdcd2b537b64d04462d4b9d970d27d642574f86529839549235007778b8c77608dfb19352b1fdef79c11e0d
7
- data.tar.gz: 041f50bcdc2cbaab8efdc1f51b53d279d6cf1b11a72deac5124885ad1e8acf52fb4ab052ff9dade90b60d2dcae7e88f7371bec74184504ff23655028bc0da13c
6
+ metadata.gz: 87b2f14824b5c4e2f75a2e570434d5b52db36e8bd49b074857fec624240cf099c16cb8ea57ce8bffc81aca9843e3fe2647662d99d52438964008fc4e05b0b6b4
7
+ data.tar.gz: 7022751ac3061e3823180c51b2e3288970e0666d6a11dbf9c0d28e5b472860637fe44e7f3cb67d0453146c280fcfb369d0b87be7a0c48bf8fb57014c9c54c76b
@@ -58,8 +58,6 @@ ChefCLI.commands do |c|
58
58
  c.builtin "describe-cookbook", :DescribeCookbook, require_path: "chef-cli/command/describe_cookbook",
59
59
  desc: "Prints cookbook checksum information used for cookbook identifier"
60
60
 
61
- c.builtin "verify", :Verify, desc: "Test the embedded #{ChefCLI::Dist::PRODUCT} applications", hidden: true
62
-
63
61
  # deprecated command that throws a failure warning if used. This was removed 4.2019
64
62
  c.builtin "provision", :Provision, desc: "Provision VMs and clusters via cookbook", hidden: true
65
63
  end
@@ -44,12 +44,6 @@ module ChefCLI
44
44
  class InvalidPolicyfileAttribute < StandardError
45
45
  end
46
46
 
47
- class MissingComponentError < RuntimeError
48
- def initialize(component_name, reason)
49
- super("Component #{component_name} is missing.\nReason: #{reason}")
50
- end
51
- end
52
-
53
47
  class OmnibusInstallNotFound < RuntimeError
54
48
  require_relative "dist"
55
49
 
@@ -16,5 +16,5 @@
16
16
  #
17
17
 
18
18
  module ChefCLI
19
- VERSION = "1.0.13".freeze
19
+ VERSION = "1.0.14".freeze
20
20
  end
@@ -48,7 +48,6 @@ describe ChefCLI::CLI do
48
48
 
49
49
 
50
50
  Available Commands:
51
- verify Test the embedded ChefCLI applications
52
51
  gem Runs the `gem` command in context of the embedded ruby
53
52
  example Example subcommand for testing
54
53
  E
@@ -94,8 +93,6 @@ describe ChefCLI::CLI do
94
93
  end
95
94
 
96
95
  before do
97
- commands_map.builtin "verify", :Verify, desc: "Test the embedded ChefCLI applications"
98
-
99
96
  commands_map.builtin "gem", :GemForwarder, require_path: "chef-cli/command/gem",
100
97
  desc: "Runs the `gem` command in context of the embedded ruby"
101
98
 
@@ -16,7 +16,6 @@
16
16
  #
17
17
 
18
18
  require "spec_helper"
19
- require "chef-cli/command/verify"
20
19
 
21
20
  describe ChefCLI::Command::Base do
22
21
  class TestCommand < ChefCLI::Command::Base
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chef-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.13
4
+ version: 1.0.14
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chef Software, Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-08-28 00:00:00.000000000 Z
11
+ date: 2019-09-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mixlib-cli
@@ -256,12 +256,10 @@ files:
256
256
  - lib/chef-cli/command/show_policy.rb
257
257
  - lib/chef-cli/command/undelete.rb
258
258
  - lib/chef-cli/command/update.rb
259
- - lib/chef-cli/command/verify.rb
260
259
  - lib/chef-cli/commands_map.rb
261
260
  - lib/chef-cli/completions/bash.sh.erb
262
261
  - lib/chef-cli/completions/chef.fish.erb
263
262
  - lib/chef-cli/completions/zsh.zsh.erb
264
- - lib/chef-cli/component_test.rb
265
263
  - lib/chef-cli/configurable.rb
266
264
  - lib/chef-cli/cookbook_metadata.rb
267
265
  - lib/chef-cli/cookbook_omnifetch.rb
@@ -429,9 +427,7 @@ files:
429
427
  - spec/unit/command/show_policy_spec.rb
430
428
  - spec/unit/command/undelete_spec.rb
431
429
  - spec/unit/command/update_spec.rb
432
- - spec/unit/command/verify_spec.rb
433
430
  - spec/unit/commands_map_spec.rb
434
- - spec/unit/component_test_spec.rb
435
431
  - spec/unit/configurable_spec.rb
436
432
  - spec/unit/cookbook_metadata_spec.rb
437
433
  - spec/unit/cookbook_profiler/git_spec.rb
@@ -645,9 +641,7 @@ test_files:
645
641
  - spec/unit/command/show_policy_spec.rb
646
642
  - spec/unit/command/undelete_spec.rb
647
643
  - spec/unit/command/update_spec.rb
648
- - spec/unit/command/verify_spec.rb
649
644
  - spec/unit/commands_map_spec.rb
650
- - spec/unit/component_test_spec.rb
651
645
  - spec/unit/configurable_spec.rb
652
646
  - spec/unit/cookbook_metadata_spec.rb
653
647
  - spec/unit/cookbook_profiler/git_spec.rb
@@ -1,547 +0,0 @@
1
- #
2
- # Copyright:: Copyright (c) 2014-2019 Chef Software Inc.
3
- # License:: Apache License, Version 2.0
4
- #
5
- # Licensed under the Apache License, Version 2.0 (the "License");
6
- # you may not use this file except in compliance with the License.
7
- # You may obtain a copy of the License at
8
- #
9
- # http://www.apache.org/licenses/LICENSE-2.0
10
- #
11
- # Unless required by applicable law or agreed to in writing, software
12
- # distributed under the License is distributed on an "AS IS" BASIS,
13
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- # See the License for the specific language governing permissions and
15
- # limitations under the License.
16
- #
17
-
18
- require_relative "base"
19
- require_relative "../exceptions"
20
- require_relative "../component_test"
21
- require_relative "../dist"
22
-
23
- module ChefCLI
24
- module Command
25
- class Verify < ChefCLI::Command::Base
26
- # TODO 2019-07-05 mp - this gets a little odd, because
27
- # this the commands that we verify here do not ship with
28
- # the chef-cli component - they're only in Workstation and DK.
29
- # This should continue to work in an installed Workstation package,
30
- # but we will probably want to find some way of letting clients (Workstation)
31
- # override this command so that it can report on all
32
- # of the components it installs.
33
- include ChefCLI::Helpers
34
-
35
- banner "Usage: #{ChefCLI::Dist::EXEC} verify [component, ...] [options]"
36
-
37
- option :omnibus_dir,
38
- long: "--omnibus-dir OMNIBUS_DIR",
39
- description: "Alternate path to omnibus install (used for testing)"
40
-
41
- option :unit,
42
- long: "--unit",
43
- description: "Run bundled app unit tests (only smoke tests run by default)"
44
-
45
- option :integration,
46
- long: "--integration",
47
- description: "Run integration tests. Possibly dangerous, for development systems only"
48
-
49
- option :verbose,
50
- long: "--verbose",
51
- description: "Display all test output, not just failing tests"
52
-
53
- class << self
54
- def add_component(name, _delete_me = nil)
55
- component = ComponentTest.new(name)
56
- yield component if block_given? # delete this conditional
57
- component_map[name] = component
58
- end
59
-
60
- def component(name)
61
- component_map[name]
62
- end
63
-
64
- def components
65
- component_map.values
66
- end
67
-
68
- def component_map
69
- @component_map ||= {}
70
- end
71
- end
72
-
73
- def components
74
- self.class.components
75
- end
76
-
77
- bundle_install_mutex = Mutex.new
78
-
79
- #
80
- # Components included in Chef Development kit:
81
- # :base_dir => Relative path of the component w.r.t. omnibus_apps_dir
82
- # :gem_base_dir => Takes a gem name instead and uses first gem found
83
- # :test_cmd => Test command to be launched for the component
84
- #
85
- add_component "berkshelf" do |c|
86
- c.gem_base_dir = "berkshelf"
87
- # For berks the real command to run is "#{embedded_bin("bundle")} exec thor spec:ci"
88
- # We can't run it right now since graphviz specs are included in the
89
- # test suite by default. We will be able to switch to that command when/if
90
- # Graphviz is added to omnibus.
91
- c.unit_test do
92
- bundle_install_mutex.synchronize { sh("#{embedded_bin("bundle")} install") }
93
- sh("#{embedded_bin("bundle")} exec #{embedded_bin("rspec")} --color --format progress spec/unit --tag ~graphviz")
94
- end
95
-
96
- # See older versions of this file in git to retrieve
97
- # our cucumber test command for berkshelf.
98
- # We had to remove them because we no longer bundle These tests cannot be run unless we bundle cucumber
99
- # c.integration_test do
100
- # bundle_install_mutex.synchronize { sh("#{embedded_bin("bundle")} install") }
101
- # sh("#{embedded_bin("bundle")} exec #{embedded_bin("cucumber")} --color --format progress --tags ~@no_run --tags ~@spawn --tags ~@graphviz --strict")
102
- # end
103
-
104
- c.smoke_test do
105
- tmpdir do |cwd|
106
- FileUtils.touch(File.join(cwd, "Berksfile"))
107
- sh("#{bin("berks")} install", cwd: cwd)
108
- end
109
- end
110
- end
111
-
112
- add_component "test-kitchen" do |c|
113
- c.gem_base_dir = "test-kitchen"
114
- c.unit_test do
115
- bundle_install_mutex.synchronize { sh("#{embedded_bin("bundle")} install") }
116
- sh("#{embedded_bin("bundle")} exec rake unit")
117
- end
118
- c.integration_test do
119
- bundle_install_mutex.synchronize { sh("#{embedded_bin("bundle")} install") }
120
- sh("#{embedded_bin("bundle")} exec rake features")
121
- end
122
-
123
- # NOTE: By default, kitchen tries to be helpful and install a driver
124
- # gem for you. This causes a race condition when running the tests
125
- # concurrently, because rubygems breaks when there are partially
126
- # installed gems in the gem repository. Instructing kitchen to create a
127
- # gemfile instead avoids the gem installation.
128
- c.smoke_test { run_in_tmpdir("kitchen init --create-gemfile") }
129
- end
130
-
131
- add_component "tk-policyfile-provisioner" do |c|
132
-
133
- c.gem_base_dir = "chef-cli"
134
-
135
- c.smoke_test do
136
- tmpdir do |cwd|
137
- File.open(File.join(cwd, "kitchen.yml"), "w+") do |f|
138
- f.print(<<~KITCHEN_YML)
139
- ---
140
- driver:
141
- name: dummy
142
- network:
143
- - ["forwarded_port", {guest: 80, host: 8080}]
144
-
145
- provisioner:
146
- name: policyfile_zero
147
- require_chef_omnibus: 12.3.0
148
-
149
- platforms:
150
- - name: ubuntu-14.04
151
-
152
- suites:
153
- - name: default
154
- run_list:
155
- - recipe[aar::default]
156
- attributes:
157
-
158
- KITCHEN_YML
159
- end
160
-
161
- sh("kitchen list", cwd: cwd)
162
-
163
- end
164
- end
165
-
166
- end
167
-
168
- add_component "chef-client" do |c|
169
- c.gem_base_dir = "chef"
170
- c.unit_test do
171
- bundle_install_mutex.synchronize { sh("#{embedded_bin("bundle")} install") }
172
- sh("#{embedded_bin("bundle")} exec #{embedded_bin("rspec")} -fp -t '~volatile_from_verify' spec/unit")
173
- end
174
- c.integration_test do
175
- bundle_install_mutex.synchronize { sh("#{embedded_bin("bundle")} install") }
176
- sh("#{embedded_bin("bundle")} exec #{embedded_bin("rspec")} -fp spec/integration spec/functional")
177
- end
178
-
179
- c.smoke_test do
180
- tmpdir do |cwd|
181
- FileUtils.touch(File.join(cwd, "apply.rb"))
182
- sh("#{bin("chef-apply")} apply.rb --chef-license 'accept-no-persist'", cwd: cwd)
183
- end
184
- end
185
- end
186
-
187
- add_component "chef-cli" do |c|
188
- c.gem_base_dir = "chef-cli"
189
- c.unit_test do
190
- bundle_install_mutex.synchronize { sh("#{embedded_bin("bundle")} install") }
191
- sh("#{embedded_bin("bundle")} exec #{embedded_bin("rspec")}")
192
- end
193
- c.smoke_test do
194
- run_in_tmpdir("#{bin("chef")} generate cookbook example")
195
- end
196
- end
197
-
198
- add_component "chef-apply" do |c|
199
- c.gem_base_dir = "chef-apply"
200
- # c.unit_test do
201
- # bundle_install_mutex.synchronize { sh("#{embedded_bin("bundle")} install") }
202
- # sh("#{embedded_bin("bundle")} exec rspec")
203
- # end
204
- c.smoke_test { sh("#{bin("chef-run")} -v", env: { "CHEF_TELEMETRY_OPT_OUT" => "true" }) }
205
- end
206
-
207
- add_component "chefspec" do |c|
208
- c.gem_base_dir = "chefspec"
209
- c.unit_test do
210
- bundle_install_mutex.synchronize { sh("#{embedded_bin("bundle")} install") }
211
- sh("#{embedded_bin("bundle")} exec #{embedded_bin("rake")} unit")
212
- end
213
- c.smoke_test do
214
- tmpdir do |cwd|
215
- FileUtils.mkdir(File.join(cwd, "spec"))
216
- with_file(File.join(cwd, "spec", "spec_helper.rb")) do |f|
217
- f.write <<~EOF
218
- require 'chefspec'
219
- require 'chefspec/berkshelf'
220
- require 'chefspec/cacher'
221
-
222
- RSpec.configure do |config|
223
- config.expect_with(:rspec) { |c| c.syntax = :expect }
224
- end
225
- EOF
226
- end
227
- FileUtils.touch(File.join(cwd, "Berksfile"))
228
- with_file(File.join(cwd, "spec", "foo_spec.rb")) do |f|
229
- f.write <<~EOF
230
- require 'spec_helper'
231
- EOF
232
- end
233
- sh(embedded_bin("rspec"), cwd: cwd)
234
- end
235
- end
236
- end
237
-
238
- add_component "generated-cookbooks-pass-chefspec" do |c|
239
-
240
- c.gem_base_dir = "chef-cli"
241
- c.smoke_test do
242
- tmpdir do |cwd|
243
- sh("#{bin("chef")} generate cookbook example", cwd: cwd)
244
- cb_cwd = File.join(cwd, "example")
245
- sh(embedded_bin("rspec"), cwd: cb_cwd)
246
- end
247
- end
248
- end
249
-
250
- add_component "fauxhai" do |c|
251
- c.gem_base_dir = "fauxhai"
252
- c.smoke_test { sh("#{embedded_bin("gem")} list fauxhai") }
253
- end
254
-
255
- add_component "kitchen-vagrant" do |c|
256
- c.gem_base_dir = "kitchen-vagrant"
257
- # The build is not passing in travis, so no tests
258
- c.smoke_test { sh("#{embedded_bin("gem")} list kitchen-vagrant") }
259
- end
260
-
261
- add_component "package installation" do |c|
262
-
263
- c.gem_base_dir = "chef-cli"
264
-
265
- c.smoke_test do
266
-
267
- if File.directory?(usr_bin_prefix)
268
- sh!("#{usr_bin_path("berks")} -v")
269
- sh!("#{usr_bin_path("chef")} -v")
270
- sh!("#{usr_bin_path("chef-client")} -v")
271
- sh!("#{usr_bin_path("chef-solo")} -v")
272
- sh!("#{usr_bin_path("delivery")} -V") unless Chef::Platform.windows?
273
-
274
- # In `knife`, `knife -v` follows a different code path that skips
275
- # command/plugin loading; `knife -h` loads commands and plugins, but
276
- # it exits with code 1, which is the same as a load error. Running
277
- # `knife exec` forces command loading to happen and this command
278
- # exits 0, which runs most of the code.
279
- #
280
- # See also: https://github.com/chef/chef-cli/issues/227
281
- sh!("#{usr_bin_path("knife")} exec -E true")
282
-
283
- tmpdir do |dir|
284
- # Kitchen tries to create a .kitchen dir even when just running
285
- # `kitchen -v`:
286
- sh!("#{usr_bin_path("kitchen")} -v", cwd: dir)
287
- end
288
-
289
- sh!("#{usr_bin_path("ohai")} -v")
290
- sh!("#{usr_bin_path("foodcritic")} -V")
291
- sh!("#{usr_bin_path("inspec")} version")
292
- end
293
-
294
- # Test blocks are expected to return a Mixlib::ShellOut compatible
295
- # object:
296
- ComponentTest::NullTestResult.new
297
- end
298
- end
299
-
300
- add_component "openssl" do |c|
301
- # https://github.com/chef/chef-cli/issues/420
302
- c.gem_base_dir = "chef"
303
-
304
- test = <<-EOF.gsub(/^\s+/, "")
305
- require "net/http" unless defined?(Net::HTTP)
306
-
307
- uris = %w{https://www.google.com https://chef.io/ https://ec2.amazonaws.com}
308
- uris.each do |uri|
309
- uri = URI(uri)
310
- puts "Fetching \#{uri} for SSL check"
311
- Net::HTTP.get uri
312
- end
313
- EOF
314
-
315
- c.unit_test do
316
- tmpdir do |cwd|
317
- with_file(File.join(cwd, "openssl.rb")) do |f|
318
- f.write test
319
- end
320
- sh!("#{Gem.ruby} openssl.rb", cwd: cwd)
321
- end
322
- end
323
- end
324
-
325
- add_component "inspec" do |c|
326
- c.gem_base_dir = "inspec"
327
-
328
- # Commenting out the unit and integration tests for now until we figure
329
- # out the bundler error
330
- # c.unit_test { sh("#{embedded_bin("bundle")} exec rake test:isolated") }
331
- # This runs Test Kitchen (using kitchen-inspec) with some inspec tests
332
- # c.integration_test { sh("#{embedded_bin("bundle")} exec rake test:vm") }
333
-
334
- # It would be nice to use a chef generator to create these specs, but
335
- # we dont have that yet. So we do it manually.
336
- c.smoke_test do
337
- tmpdir do |cwd|
338
- File.open(File.join(cwd, "some_spec.rb"), "w+") do |f|
339
- f.print <<-INSPEC_TEST
340
- rule '01' do
341
- impact 0.7
342
- title 'Some Test'
343
- desc 'Make sure inspec is installed and loading correct'
344
- describe 1 do
345
- it { should eq(1) }
346
- end
347
- end
348
- INSPEC_TEST
349
- end
350
- # TODO when we appbundle inspec, no longer `chef exec`
351
- sh("#{bin("chef")} exec #{embedded_bin("inspec")} exec .", cwd: cwd)
352
- end
353
- end
354
- end
355
-
356
- add_component "delivery-cli" do |c|
357
- # We'll want to come back and revisit getting unit tests added -
358
- # currently running the tests depends on cargo , which is not included
359
- # in our package.
360
- c.base_dir = "bin"
361
- c.smoke_test do
362
- tmpdir do |cwd|
363
- sh!("delivery setup --user=shipit --server=delivery.shipit.io --ent=chef --org=squirrels", cwd: cwd)
364
- end
365
- end
366
- end
367
-
368
- if Chef::Platform.windows?
369
- add_component "git" do |c|
370
- c.base_dir = "embedded/bin"
371
- c.smoke_test do
372
- tmpdir do |cwd|
373
- sh!("#{embedded_bin("git")} config -l")
374
- sh!("#{embedded_bin("git")} clone https://github.com/chef/license-acceptance", cwd: cwd)
375
- end
376
- end
377
- end
378
- else
379
- add_component "git" do |c|
380
- c.base_dir = "gitbin"
381
- c.smoke_test do
382
- tmpdir do |cwd|
383
- sh!("#{File.join(omnibus_root, "gitbin", "git")} config -l")
384
- sh!("#{File.join(omnibus_root, "gitbin", "git")} clone https://github.com/chef/license-acceptance", cwd: cwd)
385
-
386
- # If /usr/bin/git is a symlink, fail the test.
387
- # Note that this test cannot go last because it does not return a
388
- # Mixlib::Shellout object in the windows case, which will break the tests.
389
- failure_str = "#{nix_platform_native_bin_dir}/git contains a symlink which might mean we accidentally overwrote system git via chefcli."
390
- result = sh("readlink #{nix_platform_native_bin_dir}/git")
391
- # if a symlink was found, test to see if it is in a chefcli install
392
- if result.status.exitstatus == 0
393
- raise failure_str if result.stdout =~ /chefcli/
394
- end
395
-
396
- # <chef_dk>/bin/ should not contain a git binary.
397
- failure_str = "`<chef_dk>/bin/git --help` should fail as git should be installed in gitbin"
398
- fail_if_exit_zero("#{bin("git")} --help", failure_str)
399
- end
400
- end
401
- end
402
- end
403
-
404
- add_component "opscode-pushy-client" do |c|
405
- c.gem_base_dir = "opscode-pushy-client"
406
- # TODO the unit tests are currently failing in master
407
- # c.unit_test do
408
- # bundle_install_mutex.synchronize { sh("#{embedded_bin("bundle")} install") }
409
- # sh("#{embedded_bin("bundle")} exec rake spec")
410
- # end
411
-
412
- c.smoke_test do
413
- tmpdir do |cwd|
414
- sh("#{bin("pushy-client")} -v", cwd: cwd)
415
- end
416
- end
417
- end
418
-
419
- # We try and use some chef-sugar code to make sure it loads correctly
420
- add_component "chef-sugar" do |c|
421
- c.gem_base_dir = "chef-sugar"
422
- c.smoke_test do
423
- tmpdir do |cwd|
424
- with_file(File.join(cwd, "foo.rb")) do |f|
425
- f.write <<~EOF
426
- require 'chef/sugar'
427
- log 'something' do
428
- not_if { _64_bit? }
429
- end
430
- EOF
431
- end
432
- sh("#{bin("chef-apply")} foo.rb", cwd: cwd)
433
- end
434
- end
435
- end
436
-
437
- attr_reader :verification_threads
438
- attr_reader :verification_results
439
- attr_reader :verification_status
440
-
441
- def initialize
442
- super
443
- @verification_threads = [ ]
444
- @verification_results = [ ]
445
- @verification_status = 0
446
- end
447
-
448
- def run(params = [ ])
449
- err("[WARN] This is an internal command used by the ChefCLI development team. If you are a ChefCLI user, please do not run it.")
450
- @components_filter = parse_options(params)
451
-
452
- validate_components!
453
- invoke_tests
454
- wait_for_tests
455
- report_results
456
-
457
- verification_status
458
- end
459
-
460
- def omnibus_root
461
- config[:omnibus_dir] || super
462
- end
463
-
464
- def validate_components!
465
- components.each do |component|
466
- component.omnibus_root = omnibus_root
467
- component.assert_present!
468
- end
469
- end
470
-
471
- def components_to_test
472
- if @components_filter.empty?
473
- components
474
- else
475
- components.select do |component|
476
- @components_filter.include?(component.name.to_s)
477
- end
478
- end
479
- end
480
-
481
- def invoke_tests
482
- components_to_test.each do |component|
483
- # Run the component specs in parallel
484
- verification_threads << Thread.new do
485
-
486
- results = []
487
-
488
- results << component.run_smoke_test
489
-
490
- if config[:unit]
491
- results << component.run_unit_test
492
- end
493
-
494
- if config[:integration]
495
- results << component.run_integration_test
496
- end
497
-
498
- if results.any? { |r| r.exitstatus != 0 }
499
- component_status = 1
500
- @verification_status = 1
501
- else
502
- component_status = 0
503
- end
504
-
505
- {
506
- component: component,
507
- results: results,
508
- component_status: component_status,
509
- }
510
- end
511
-
512
- msg("Running verification for component '#{component.name}'")
513
- end
514
- end
515
-
516
- def wait_for_tests
517
- until verification_threads.empty?
518
- verification_threads.each do |t|
519
- if t.join(1)
520
- verification_threads.delete t
521
- verification_results << t.value
522
- t.value[:results].each do |result|
523
- if config[:verbose] || t.value[:component_status] != 0
524
- msg("")
525
- msg(result.stdout)
526
- msg(result.stderr) if result.stderr
527
- end
528
- end
529
- else
530
- $stdout.write "."
531
- end
532
- end
533
- end
534
- end
535
-
536
- def report_results
537
- msg("")
538
- msg("---------------------------------------------")
539
- verification_results.each do |result|
540
- message = result[:component_status] == 0 ? "succeeded" : "failed"
541
- msg("Verification of component '#{result[:component].name}' #{message}.")
542
- end
543
- end
544
-
545
- end
546
- end
547
- end
@@ -1,227 +0,0 @@
1
- #
2
- # Copyright:: Copyright (c) 2014-2019 Chef Software Inc.
3
- # License:: Apache License, Version 2.0
4
- #
5
- # Licensed under the Apache License, Version 2.0 (the "License");
6
- # you may not use this file except in compliance with the License.
7
- # You may obtain a copy of the License at
8
- #
9
- # http://www.apache.org/licenses/LICENSE-2.0
10
- #
11
- # Unless required by applicable law or agreed to in writing, software
12
- # distributed under the License is distributed on an "AS IS" BASIS,
13
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- # See the License for the specific language governing permissions and
15
- # limitations under the License.
16
- #
17
-
18
- require_relative "exceptions"
19
- require_relative "helpers"
20
-
21
- # https://github.com/bundler/bundler/issues/4368
22
- # As of rubygems 2.6.2, Rubygems will call Bundler::SpecSet#size, which does
23
- # not exist as of Bundler 1.11.2.
24
- #
25
- # `#size` and `#length` should be synonyms in idiomatic ruby so we alias to
26
- # make bundler and rubygems play nicely.
27
- if Object.const_defined?(:Bundler) &&
28
- Bundler.const_defined?(:SpecSet) &&
29
- Bundler::SpecSet.instance_methods.include?(:length) &&
30
- !Bundler::SpecSet.instance_methods.include?(:size)
31
-
32
- module Bundler
33
- class SpecSet
34
-
35
- alias_method :size, :length
36
-
37
- end
38
- end
39
-
40
- end
41
-
42
- module ChefCLI
43
- class ComponentTest
44
-
45
- class NullTestResult
46
- def exitstatus
47
- 0
48
- end
49
-
50
- def stdout
51
- ""
52
- end
53
-
54
- def stderr
55
- ""
56
- end
57
- end
58
-
59
- DEFAULT_TEST = lambda { |context| NullTestResult.new }
60
-
61
- include Helpers
62
-
63
- attr_accessor :base_dir
64
-
65
- attr_writer :omnibus_root
66
-
67
- attr_reader :name
68
-
69
- def initialize(name)
70
- @name = name
71
- @unit_test = DEFAULT_TEST
72
- @integration_test = DEFAULT_TEST
73
- @smoke_test = DEFAULT_TEST
74
- @base_dir = nil
75
- @gem_name_for_base_dir = nil
76
- end
77
-
78
- def unit_test(&test_block)
79
- @unit_test = test_block
80
- end
81
-
82
- def run_unit_test
83
- instance_eval(&@unit_test)
84
- end
85
-
86
- def integration_test(&test_block)
87
- @integration_test = test_block
88
- end
89
-
90
- def run_integration_test
91
- instance_eval(&@integration_test)
92
- end
93
-
94
- def smoke_test(&test_block)
95
- @smoke_test = test_block
96
- end
97
-
98
- def run_smoke_test
99
- instance_eval(&@smoke_test)
100
- end
101
-
102
- def bin(binary)
103
- File.join(omnibus_bin_dir, binary)
104
- end
105
-
106
- def embedded_bin(binary)
107
- File.join(omnibus_embedded_bin_dir, binary)
108
- end
109
-
110
- def sh(command, options = {})
111
- combined_opts = default_command_options.merge(options)
112
-
113
- # Env is a hash, so it needs to be merged separately
114
- if options.key?(:env)
115
- combined_opts[:env] = default_command_options[:env].merge(options[:env])
116
- end
117
- system_command(command, combined_opts)
118
- end
119
-
120
- # Just like #sh but raises an error if the the command returns an
121
- # unexpected exit code.
122
- #
123
- # Most verification steps just run a single command, then
124
- # ChefCLI::Command::Verify#invoke_tests handles the results by inspecting
125
- # the return value of the test block. For tests that run a lot of commands,
126
- # this is inconvenient so you can use #sh! instead.
127
- def sh!(*args)
128
- sh(*args).tap(&:error!)
129
- end
130
-
131
- # Run a command, if the command returns zero, raise an error,
132
- # otherwise, if it returns non-zero or doesn't exist,
133
- # return a passing command so that the test parser doesn't
134
- # crash.
135
- def fail_if_exit_zero(cmd_string, failure_string = "")
136
- result = sh(cmd_string)
137
- if result.status.exitstatus == 0
138
- raise failure_string
139
- else
140
- sh("true")
141
- end
142
- rescue Errno::ENOENT
143
- sh("true")
144
- end
145
-
146
- def nix_platform_native_bin_dir
147
- if /darwin/ =~ RUBY_PLATFORM
148
- "/usr/local/bin"
149
- else
150
- "/usr/bin"
151
- end
152
- end
153
-
154
- def run_in_tmpdir(command, options = {})
155
- tmpdir do |dir|
156
- options[:cwd] = dir
157
- sh(command, options)
158
- end
159
- end
160
-
161
- def tmpdir
162
- Dir.mktmpdir do |tmpdir|
163
- yield tmpdir
164
- end
165
- end
166
-
167
- def assert_present!
168
- unless File.exist?( component_path )
169
- raise MissingComponentError.new(name, "Could not find #{component_path}")
170
- end
171
- rescue Gem::LoadError => e
172
- raise MissingComponentError.new(name, e)
173
- end
174
-
175
- def default_command_options
176
- {
177
- cwd: component_path,
178
- env: {
179
- # Add the embedded/bin to the PATH so that bundle executable can
180
- # be found while running the tests.
181
- path_variable_key => omnibus_path,
182
- "CHEF_LICENSE" => "accept-no-persist",
183
- },
184
- timeout: 3600,
185
- }
186
- end
187
-
188
- def component_path
189
- if base_dir
190
- File.join(omnibus_root, base_dir)
191
- elsif gem_base_dir
192
- gem_base_dir
193
- else
194
- raise "`base_dir` or `gem_base_dir` must be defined for component `#{name}`"
195
- end
196
- end
197
-
198
- def gem_base_dir
199
- return nil if @gem_name_for_base_dir.nil?
200
-
201
- # There is no way to say "give me the latest prerelease OR normal version of this gem.
202
- # So we first ask if there is a normal version, and if there is not, we ask if there
203
- # is a prerelease version. ">= 0.a" is how we ask for a prerelease version, because a
204
- # prerelease version is defined as "any version with a letter in it."
205
- gem = Gem::Specification.find_by_name(@gem_name_for_base_dir)
206
- gem ||= Gem::Specification.find_by_name(@gem_name_for_base_dir, ">= 0.a")
207
- gem.gem_dir
208
- end
209
-
210
- def gem_base_dir=(gem_name)
211
- @gem_name_for_base_dir = gem_name
212
- end
213
-
214
- def omnibus_root
215
- @omnibus_root || raise("`omnibus_root` must be set before running tests")
216
- end
217
-
218
- def omnibus_path
219
- [omnibus_bin_dir, omnibus_embedded_bin_dir, ENV["PATH"]].join(File::PATH_SEPARATOR)
220
- end
221
-
222
- def path_variable_key
223
- ENV.keys.grep(/\Apath\Z/i).first
224
- end
225
-
226
- end
227
- end
@@ -1,340 +0,0 @@
1
- #
2
- # Copyright:: Copyright (c) 2014-2018 Chef Software Inc.
3
- # License:: Apache License, Version 2.0
4
- #
5
- # Licensed under the Apache License, Version 2.0 (the "License");
6
- # you may not use this file except in compliance with the License.
7
- # You may obtain a copy of the License at
8
- #
9
- # http://www.apache.org/licenses/LICENSE-2.0
10
- #
11
- # Unless required by applicable law or agreed to in writing, software
12
- # distributed under the License is distributed on an "AS IS" BASIS,
13
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- # See the License for the specific language governing permissions and
15
- # limitations under the License.
16
- #
17
-
18
- require "spec_helper"
19
- require "chef-cli/command/verify"
20
-
21
- module Gem
22
-
23
- # We stub Gem.ruby because `verify` uses it to locate the omnibus directory,
24
- # but we also use it in some of the "test commands" in these tests.
25
- class << self
26
- alias :real_ruby :ruby
27
- end
28
- end
29
-
30
- describe ChefCLI::Command::Verify do
31
-
32
- let(:command_instance) { ChefCLI::Command::Verify.new }
33
-
34
- let(:command_options) { [] }
35
-
36
- let(:components) { {} }
37
-
38
- let(:default_components) do
39
- [
40
- "berkshelf",
41
- "test-kitchen",
42
- "tk-policyfile-provisioner",
43
- "chef-client",
44
- "chef-cli",
45
- "chef-apply",
46
- "chefspec",
47
- "generated-cookbooks-pass-chefspec",
48
- "fauxhai",
49
- "kitchen-vagrant",
50
- "package installation",
51
- "openssl",
52
- "inspec",
53
- "chef-sugar",
54
- "opscode-pushy-client",
55
- "git",
56
- "delivery-cli",
57
- ]
58
- end
59
-
60
- def run_command(expected_exit_code)
61
- expect(command_instance.run(command_options)).to eq(expected_exit_code)
62
- end
63
-
64
- it "defines berks, tk, chef and chef-cli components by default" do
65
- expected_components = default_components
66
- expect(command_instance.components).not_to be_empty
67
- expect(command_instance.components.map(&:name)).to match_array(expected_components)
68
- end
69
-
70
- it "has a usage banner" do
71
- expect(command_instance.banner).to eq("Usage: chef verify [component, ...] [options]")
72
- end
73
-
74
- describe "when locating omnibus directory from the ruby path" do
75
- it "should find omnibus root directory from ruby path" do
76
- allow(Gem).to receive(:ruby).and_return(File.join(fixtures_path, "eg_omnibus_dir/valid/embedded/bin/ruby"))
77
- expect(command_instance.omnibus_root).to end_with("eg_omnibus_dir/valid")
78
- end
79
-
80
- it "should raise OmnibusInstallNotFound if directory is not looking like omnibus" do
81
- allow(Gem).to receive(:ruby).and_return(File.join(fixtures_path, ".rbenv/versions/2.1.1/bin/ruby"))
82
- expect { command_instance.omnibus_bin_dir }.to raise_error(ChefCLI::OmnibusInstallNotFound)
83
- end
84
-
85
- it "raises OmnibusInstallNotFound if omnibus directory doesn't exist" do
86
- allow(Gem).to receive(:ruby).and_return(File.join(fixtures_path, "eg_omnibus_dir/invalid/embedded/bin/ruby"))
87
- expect { command_instance.omnibus_bin_dir }.to raise_error(ChefCLI::OmnibusInstallNotFound)
88
- end
89
-
90
- context "and a component's gem is not installed" do
91
- before do
92
- component_map = ChefCLI::Command::Verify.component_map.dup
93
- component_map["cucumber"] = ChefCLI::ComponentTest.new("cucumber")
94
- component_map["cucumber"].gem_base_dir = "cucumber"
95
- allow(ChefCLI::Command::Verify).to receive(:component_map).and_return(component_map)
96
- end
97
-
98
- it "raises MissingComponentError when a component doesn't exist" do
99
- allow(Gem).to receive(:ruby).and_return(File.join(fixtures_path, "eg_omnibus_dir/missing_component/embedded/bin/ruby"))
100
- expect { command_instance.validate_components! }.to raise_error(ChefCLI::MissingComponentError)
101
- end
102
- end
103
- end
104
-
105
- describe "when running verify command" do
106
- let(:stdout_io) { StringIO.new }
107
- let(:stderr_io) { StringIO.new }
108
- let(:ruby_path) { File.join(fixtures_path, "eg_omnibus_dir/valid/embedded/bin/ruby") }
109
-
110
- def run_unit_test
111
- # Set rubyopt to empty to prevent bundler from infecting the ruby
112
- # subcommands (and loading a bunch of extra gems).
113
- lambda { |_self| sh("#{Gem.real_ruby} verify_me", env: { "RUBYOPT" => "" }) }
114
- end
115
-
116
- def run_integration_test
117
- lambda { |_self| sh("#{Gem.real_ruby} integration_test", env: { "RUBYOPT" => "" }) }
118
- end
119
-
120
- let(:all_tests_ok) do
121
- ChefCLI::ComponentTest.new("successful_comp").tap do |c|
122
- c.base_dir = "embedded/apps/berkshelf"
123
- c.unit_test(&run_unit_test)
124
- c.integration_test(&run_integration_test)
125
- c.smoke_test { sh("exit 0") }
126
- end
127
- end
128
-
129
- let(:all_tests_ok_2) do
130
- ChefCLI::ComponentTest.new("successful_comp_2").tap do |c|
131
- c.base_dir = "embedded/apps/test-kitchen"
132
- c.unit_test(&run_unit_test)
133
- c.smoke_test { sh("exit 0") }
134
- end
135
- end
136
-
137
- let(:failing_unit_test) do
138
- ChefCLI::ComponentTest.new("failing_comp").tap do |c|
139
- c.base_dir = "embedded/apps/chef"
140
- c.unit_test(&run_unit_test)
141
- c.smoke_test { sh("exit 0") }
142
- end
143
- end
144
-
145
- let(:passing_smoke_test_only) do
146
- component = failing_unit_test.dup
147
- component.smoke_test { sh("exit 0") }
148
- component
149
- end
150
-
151
- let(:failing_smoke_test_only) do
152
- component = all_tests_ok.dup
153
- component.smoke_test { sh("exit 1") }
154
- component
155
- end
156
-
157
- let(:component_without_integration_tests) do
158
- ChefCLI::ComponentTest.new("successful_comp").tap do |c|
159
- c.base_dir = "embedded/apps/berkshelf"
160
- c.unit_test { sh("./verify_me") }
161
- c.smoke_test { sh("exit 0") }
162
- end
163
- end
164
-
165
- def stdout
166
- stdout_io.string
167
- end
168
-
169
- before do
170
- allow(Gem).to receive(:ruby).and_return(ruby_path)
171
- allow(command_instance).to receive(:stdout).and_return(stdout_io)
172
- allow(command_instance).to receive(:stderr).and_return(stderr_io)
173
- allow(command_instance).to receive(:components).and_return(components)
174
- end
175
-
176
- context "when running smoke tests only" do
177
- describe "with single command with success" do
178
- let(:components) do
179
- [ passing_smoke_test_only ]
180
- end
181
-
182
- before do
183
- run_command(0)
184
- end
185
-
186
- it "should report the success of the command" do
187
- expect(stdout).to include("Verification of component 'failing_comp' succeeded.")
188
- end
189
-
190
- end
191
-
192
- describe "with single command with failure" do
193
- let(:components) do
194
- [ failing_smoke_test_only ]
195
- end
196
-
197
- before do
198
- run_command(1)
199
- end
200
-
201
- it "should report the failure of the command" do
202
- expect(stdout).to include("Verification of component 'successful_comp' failed.")
203
- end
204
-
205
- end
206
- end
207
-
208
- context "when running unit tests" do
209
-
210
- let(:command_options) { %w{--unit --verbose} }
211
-
212
- let(:components) do
213
- [ all_tests_ok ]
214
- end
215
-
216
- describe "with single command with success" do
217
- before do
218
- run_command(0)
219
- end
220
-
221
- it "should have embedded/bin on the PATH" do
222
- expect(stdout).to include(File.join(fixtures_path, "eg_omnibus_dir/valid/embedded/bin"))
223
- end
224
-
225
- it "should report the success of the command" do
226
- expect(stdout).to include("Verification of component 'successful_comp' succeeded.")
227
- end
228
-
229
- it "reports the component test output" do
230
- expect(stdout).to include("you are good to go...")
231
- end
232
-
233
- context "and --verbose is not enabled" do
234
-
235
- let(:command_options) { %w{--unit} }
236
-
237
- it "omits the component test output" do
238
- expect(stdout).to_not include("you are good to go...")
239
- end
240
- end
241
-
242
- context "and --integration flag is given" do
243
-
244
- let(:command_options) { %w{--integration --verbose} }
245
-
246
- it "should run the integration command also" do
247
- expect(stdout).to include("integration tests OK")
248
- end
249
-
250
- context "and no integration test command is specifed for the component" do
251
-
252
- let(:components) do
253
- [ component_without_integration_tests ]
254
- end
255
-
256
- it "skips the integration test and succeeds" do
257
- expect(stdout).to include("Verification of component 'successful_comp' succeeded.")
258
- end
259
-
260
- end
261
-
262
- end
263
-
264
- end
265
-
266
- describe "with single command with failure" do
267
- let(:components) do
268
- [ failing_unit_test ]
269
- end
270
-
271
- before do
272
- run_command(1)
273
- end
274
-
275
- it "should report the failure of the command" do
276
- expect(stdout).to include("Verification of component 'failing_comp' failed.")
277
- end
278
-
279
- it "reports the component test output" do
280
- expect(stdout).to include("i'm not feeling good today...")
281
- end
282
- end
283
-
284
- describe "with multiple commands with success" do
285
- let(:components) do
286
- [ all_tests_ok, all_tests_ok_2 ]
287
- end
288
-
289
- before do
290
- run_command(0)
291
- end
292
-
293
- it "should report the success of the command" do
294
- expect(stdout).to include("Verification of component 'successful_comp' succeeded.")
295
- expect(stdout).to include("Verification of component 'successful_comp_2' succeeded.")
296
- end
297
-
298
- it "reports the component test outputs" do
299
- expect(stdout).to include("you are good to go...")
300
- expect(stdout).to include("my friend everything is good...")
301
- end
302
-
303
- context "and components are filtered by CLI args" do
304
-
305
- let(:command_options) { [ "successful_comp_2" ] }
306
-
307
- it "verifies only the desired component" do
308
- expect(stdout).to_not include("Verification of component 'successful_comp_1' succeeded.")
309
- expect(stdout).to include("Verification of component 'successful_comp_2' succeeded.")
310
- end
311
-
312
- end
313
- end
314
-
315
- describe "with multiple commands with failures" do
316
- let(:components) do
317
- [ all_tests_ok, all_tests_ok_2, failing_unit_test ]
318
- end
319
-
320
- before do
321
- run_command(1)
322
- end
323
-
324
- it "should report the success and failure of the commands" do
325
- expect(stdout).to include("Verification of component 'successful_comp' succeeded.")
326
- expect(stdout).to include("Verification of component 'successful_comp_2' succeeded.")
327
- expect(stdout).to include("Verification of component 'failing_comp' failed.")
328
- end
329
-
330
- it "reports the component test outputs" do
331
- expect(stdout).to include("you are good to go...")
332
- expect(stdout).to include("my friend everything is good...")
333
- expect(stdout).to include("i'm not feeling good today...")
334
- end
335
- end
336
-
337
- end
338
- end
339
-
340
- end
@@ -1,128 +0,0 @@
1
- #
2
- # Copyright:: Copyright (c) 2014-2018 Chef Software Inc.
3
- # License:: Apache License, Version 2.0
4
- #
5
- # Licensed under the Apache License, Version 2.0 (the "License");
6
- # you may not use this file except in compliance with the License.
7
- # You may obtain a copy of the License at
8
- #
9
- # http://www.apache.org/licenses/LICENSE-2.0
10
- #
11
- # Unless required by applicable law or agreed to in writing, software
12
- # distributed under the License is distributed on an "AS IS" BASIS,
13
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- # See the License for the specific language governing permissions and
15
- # limitations under the License.
16
- #
17
-
18
- require "spec_helper"
19
- require "chef-cli/component_test"
20
- require "pathname"
21
-
22
- describe ChefCLI::ComponentTest do
23
-
24
- let(:component) do
25
- ChefCLI::ComponentTest.new("berkshelf").tap do |c|
26
- c.base_dir = "berkshelf"
27
- end
28
- end
29
-
30
- it "defines the component" do
31
- expect(component.name).to eq("berkshelf")
32
- end
33
-
34
- it "sets the component base directory" do
35
- expect(component.base_dir).to eq("berkshelf")
36
- end
37
-
38
- it "defines a default unit test" do
39
- expect(component.run_unit_test.exitstatus).to eq(0)
40
- expect(component.run_unit_test.stdout).to eq("")
41
- expect(component.run_unit_test.stderr).to eq("")
42
- end
43
-
44
- it "defines a default integration test" do
45
- expect(component.run_integration_test.exitstatus).to eq(0)
46
- expect(component.run_integration_test.stdout).to eq("")
47
- expect(component.run_integration_test.stderr).to eq("")
48
- end
49
-
50
- it "defines a default smoke test" do
51
- expect(component.run_smoke_test.exitstatus).to eq(0)
52
- expect(component.run_smoke_test.stdout).to eq("")
53
- expect(component.run_smoke_test.stderr).to eq("")
54
- end
55
-
56
- context "with basic tests defined" do
57
-
58
- let(:result) { {} }
59
-
60
- before do
61
- # capture a reference to results hash so we can use it in tests.
62
- result_hash = result
63
- component.tap do |c|
64
- c.unit_test { result_hash[:unit_test] = true }
65
- c.integration_test { result_hash[:integration_test] = true }
66
- c.smoke_test { result_hash[:smoke_test] = true }
67
- end
68
- end
69
-
70
- it "defines a unit test block" do
71
- component.run_unit_test
72
- expect(result[:unit_test]).to be true
73
- end
74
-
75
- it "defines an integration test block" do
76
- component.run_integration_test
77
- expect(result[:integration_test]).to be true
78
- end
79
-
80
- it "defines a smoke test block" do
81
- component.run_smoke_test
82
- expect(result[:smoke_test]).to be true
83
- end
84
-
85
- end
86
-
87
- context "with tests that shell out to commands" do
88
-
89
- let(:omnibus_root) { File.join(fixtures_path, "eg_omnibus_dir/valid/") }
90
-
91
- before do
92
- component.tap do |c|
93
- # Have to set omnibus dir so command can run with correct cwd
94
- c.omnibus_root = omnibus_root
95
-
96
- c.base_dir = "embedded/apps/berkshelf"
97
-
98
- c.unit_test { sh("true") }
99
-
100
- c.integration_test { sh("ruby -e 'puts Dir.pwd'", env: { "RUBYOPT" => "" }) }
101
-
102
- c.smoke_test { run_in_tmpdir("ruby -e 'puts Dir.pwd'", env: { "RUBYOPT" => "" }) }
103
- end
104
- end
105
-
106
- it "shells out and returns the shell out object" do
107
- expect(component.run_unit_test.exitstatus).to eq(0)
108
- expect(component.run_unit_test.stdout).to eq("")
109
- expect(component.run_unit_test.stderr).to eq("")
110
- end
111
-
112
- it "runs the command in the app's root" do
113
- result = component.run_integration_test
114
- expected_path = Pathname.new(File.join(omnibus_root, "embedded/apps/berkshelf")).realpath
115
- expect(Pathname.new(result.stdout.strip).realpath).to eq(expected_path)
116
- end
117
-
118
- it "runs commands in a temporary directory when specified" do
119
- result = component.run_smoke_test
120
-
121
- parent_of_cwd = Pathname.new(result.stdout.strip).parent.realpath
122
- tempdir = Pathname.new(Dir.tmpdir).realpath
123
- expect(parent_of_cwd).to eq(tempdir)
124
- end
125
-
126
- end
127
-
128
- end