diff options
author | Lamont Granquist <lamont@scriptkiddie.org> | 2019-03-11 11:49:31 -0700 |
---|---|---|
committer | Lamont Granquist <lamont@scriptkiddie.org> | 2019-03-11 11:49:31 -0700 |
commit | 66015ba654469f4dacfd78d40b02aafee52bbf1b (patch) | |
tree | b00d0de111d18980f446b006ac63ef599eea8108 /spec/support | |
parent | 4037976199b728d4bdc18fd428e8d40a84c97e2b (diff) | |
download | chef-66015ba654469f4dacfd78d40b02aafee52bbf1b.tar.gz |
Extract Action Collection from Data Collector
See the PR for details on this change.
Signed-off-by: Lamont Granquist <lamont@scriptkiddie.org>
Diffstat (limited to 'spec/support')
-rw-r--r-- | spec/support/shared/context/client.rb | 305 | ||||
-rw-r--r-- | spec/support/shared/examples/client.rb | 104 |
2 files changed, 0 insertions, 409 deletions
diff --git a/spec/support/shared/context/client.rb b/spec/support/shared/context/client.rb deleted file mode 100644 index d6c49c896b..0000000000 --- a/spec/support/shared/context/client.rb +++ /dev/null @@ -1,305 +0,0 @@ - -require "spec_helper" - -# Stubs a basic client object -shared_context "client" do - let(:fqdn) { "hostname.example.org" } - let(:hostname) { "hostname" } - let(:machinename) { "machinename.example.org" } - let(:platform) { "example-platform" } - let(:platform_version) { "example-platform-1.0" } - - let(:ohai_data) do - { - fqdn: fqdn, - hostname: hostname, - machinename: machinename, - platform: platform, - platform_version: platform_version, - } - end - - let(:ohai_system) do - ohai = instance_double("Ohai::System", all_plugins: true, data: ohai_data, logger: logger) - allow(ohai).to receive(:[]) do |k| - ohai_data[k] - end - ohai - end - - let(:node) do - Chef::Node.new.tap do |n| - n.name(fqdn) - n.chef_environment("_default") - end - end - - let(:json_attribs) { nil } - let(:client_opts) { {} } - - let(:stdout) { STDOUT } - let(:stderr) { STDERR } - - let(:client) do - Chef::Config[:event_loggers] = [] - allow(Ohai::System).to receive(:new).and_return(ohai_system) - opts = client_opts.merge({ logger: logger }) - Chef::Client.new(json_attribs, opts).tap do |c| - c.node = node - end - end - - let(:logger) { instance_double("Mixlib::Log::Child", trace: nil, debug: nil, warn: nil, info: nil, error: nil, fatal: nil) } - - before do - stub_const("Chef::Client::STDOUT_FD", stdout) - stub_const("Chef::Client::STDERR_FD", stderr) - allow(client).to receive(:logger).and_return(logger) - end -end - -# Stubs a client for a client run. -# Requires a client object be defined in the scope of this included context. -# e.g.: -# describe "some functionality" do -# include_context "client" -# include_context "a client run" -# ... -# end -shared_context "a client run" do - let(:stdout) { StringIO.new } - let(:stderr) { StringIO.new } - - let(:api_client_exists?) { false } - let(:enable_fork) { false } - - let(:http_data_collector) { double("Chef::ServerAPI (data collector)") } - let(:http_cookbook_sync) { double("Chef::ServerAPI (cookbook sync)") } - let(:http_node_load) { double("Chef::ServerAPI (node)") } - let(:http_node_save) { double("Chef::ServerAPI (node save)") } - let(:reporting_rest_client) { double("Chef::ServerAPI (reporting client)") } - - let(:runner) { instance_double("Chef::Runner") } - let(:audit_runner) { instance_double("Chef::Audit::Runner", failed?: false) } - - def stub_for_register - # --Client.register - # Make sure Client#register thinks the client key doesn't - # exist, so it tries to register and create one. - allow(File).to receive(:exists?).and_call_original - expect(File).to receive(:exists?) - .with(Chef::Config[:client_key]) - .exactly(:once) - .and_return(api_client_exists?) - - unless api_client_exists? - # Client.register will register with the validation client name. - expect_any_instance_of(Chef::ApiClient::Registration).to receive(:run) - end - end - - def stub_for_data_collector_init - expect(Chef::ServerAPI).to receive(:new) - .with(Chef::Config[:data_collector][:server_url], validate_utf8: false) - .exactly(:once) - .and_return(http_data_collector) - end - - def stub_for_node_load - # Client.register will then turn around create another - # Chef::ServerAPI object, this time with the client key it got from the - # previous step. - expect(Chef::ServerAPI).to receive(:new) - .with(Chef::Config[:chef_server_url], client_name: fqdn, - signing_key_filename: Chef::Config[:client_key]) - .exactly(:once) - .and_return(http_node_load) - - # --Client#build_node - # looks up the node, which we will return, then later saves it. - expect(Chef::Node).to receive(:find_or_create).with(fqdn).and_return(node) - - # --ResourceReporter#node_load_completed - # gets a run id from the server for storing resource history - # (has its own tests, so stubbing it here.) - expect_any_instance_of(Chef::ResourceReporter).to receive(:node_load_completed) - end - - def stub_rest_clean - allow(client).to receive(:rest_clean).and_return(reporting_rest_client) - end - - def stub_for_sync_cookbooks - # --Client#setup_run_context - # ---Client#sync_cookbooks -- downloads the list of cookbooks to sync - # - expect_any_instance_of(Chef::CookbookSynchronizer).to receive(:sync_cookbooks) - expect(Chef::ServerAPI).to receive(:new).with(Chef::Config[:chef_server_url], version_class: Chef::CookbookManifestVersions).and_return(http_cookbook_sync) - expect(http_cookbook_sync).to receive(:post) - .with("environments/_default/cookbook_versions", { run_list: [] }) - .and_return({}) - end - - def stub_for_required_recipe - response = Net::HTTPNotFound.new("1.1", "404", "Not Found") - exception = Net::HTTPClientException.new('404 "Not Found"', response) - expect(http_node_load).to receive(:get).with("required_recipe").and_raise(exception) - end - - def stub_for_converge - # define me - end - - def stub_for_audit - # define me - end - - def stub_for_node_save - # define me - end - - def stub_for_run - # define me - end - - before do - Chef::Config[:client_fork] = enable_fork - Chef::Config[:cache_path] = windows? ? 'C:\chef' : "/var/chef" - Chef::Config[:why_run] = false - Chef::Config[:audit_mode] = :enabled - Chef::Config[:chef_guid] = "default-guid" - - stub_rest_clean - stub_for_register - stub_for_data_collector_init - stub_for_node_load - stub_for_sync_cookbooks - stub_for_required_recipe - stub_for_converge - stub_for_audit - stub_for_node_save - - expect_any_instance_of(Chef::RunLock).to receive(:acquire) - expect_any_instance_of(Chef::RunLock).to receive(:save_pid) - expect_any_instance_of(Chef::RunLock).to receive(:release) - - # Post conditions: check that node has been filled in correctly - expect(client).to receive(:run_started) - - stub_for_run - end -end - -shared_context "converge completed" do - def stub_for_converge - # --Client#converge - expect(Chef::Runner).to receive(:new).and_return(runner) - expect(runner).to receive(:converge).and_return(true) - end - - def stub_for_node_save - allow(node).to receive(:data_for_save).and_return(node.for_json) - - # --Client#save_updated_node - expect(Chef::ServerAPI).to receive(:new).with(Chef::Config[:chef_server_url], client_name: fqdn, - signing_key_filename: Chef::Config[:client_key], validate_utf8: false).and_return(http_node_save) - expect(http_node_save).to receive(:put).with("nodes/#{fqdn}", node.for_json).and_return(true) - end -end - -shared_context "converge failed" do - let(:converge_error) do - err = Chef::Exceptions::UnsupportedAction.new("Action unsupported") - err.set_backtrace([ "/path/recipe.rb:15", "/path/recipe.rb:12" ]) - err - end - - def stub_for_converge - expect(Chef::Runner).to receive(:new).and_return(runner) - expect(runner).to receive(:converge).and_raise(converge_error) - end - - def stub_for_node_save - expect(client).to_not receive(:save_updated_node) - end -end - -shared_context "audit phase completed" do - def stub_for_audit - # -- Client#run_audits - expect(Chef::Audit::Runner).to receive(:new).and_return(audit_runner) - expect(audit_runner).to receive(:run).and_return(true) - expect(client.events).to receive(:audit_phase_complete) - end -end - -shared_context "audit phase failed with error" do - let(:audit_error) do - err = RuntimeError.new("Unexpected audit error") - err.set_backtrace([ "/path/recipe.rb:57", "/path/recipe.rb:55" ]) - err - end - - def stub_for_audit - expect(Chef::Audit::Runner).to receive(:new).and_return(audit_runner) - expect(Chef::Audit::Logger).to receive(:read_buffer).and_return("Audit mode output!") - expect(audit_runner).to receive(:run).and_raise(audit_error) - expect(client.events).to receive(:audit_phase_failed).with(audit_error, "Audit mode output!") - end -end - -shared_context "audit phase completed with failed controls" do - let(:audit_runner) do - instance_double("Chef::Audit::Runner", failed?: true, - num_failed: 1, num_total: 3) end - - let(:audit_error) do - err = Chef::Exceptions::AuditsFailed.new(audit_runner.num_failed, audit_runner.num_total) - err.set_backtrace([ "/path/recipe.rb:108", "/path/recipe.rb:103" ]) - err - end - - def stub_for_audit - expect(Chef::Audit::Runner).to receive(:new).and_return(audit_runner) - expect(Chef::Audit::Logger).to receive(:read_buffer).and_return("Audit mode output!") - expect(audit_runner).to receive(:run) - expect(Chef::Exceptions::AuditsFailed).to receive(:new).with( - audit_runner.num_failed, audit_runner.num_total - ).and_return(audit_error) - expect(client.events).to receive(:audit_phase_failed).with(audit_error, "Audit mode output!") - end -end - -shared_context "run completed" do - def stub_for_run - expect(client).to receive(:run_completed_successfully) - - # --ResourceReporter#run_completed - # updates the server with the resource history - # (has its own tests, so stubbing it here.) - expect_any_instance_of(Chef::ResourceReporter).to receive(:run_completed) - # --AuditReporter#run_completed - # posts the audit data to server. - # (has its own tests, so stubbing it here.) - expect_any_instance_of(Chef::Audit::AuditReporter).to receive(:run_completed) - end -end - -shared_context "run failed" do - def stub_for_run - expect(client).to receive(:run_failed) - - # --ResourceReporter#run_completed - # updates the server with the resource history - # (has its own tests, so stubbing it here.) - expect_any_instance_of(Chef::ResourceReporter).to receive(:run_failed) - # --AuditReporter#run_completed - # posts the audit data to server. - # (has its own tests, so stubbing it here.) - expect_any_instance_of(Chef::Audit::AuditReporter).to receive(:run_failed) - end - - before do - expect(Chef::Application).to receive(:debug_stacktrace).with an_instance_of(Chef::Exceptions::RunFailedWrappingError) - end -end diff --git a/spec/support/shared/examples/client.rb b/spec/support/shared/examples/client.rb deleted file mode 100644 index 6479c9d582..0000000000 --- a/spec/support/shared/examples/client.rb +++ /dev/null @@ -1,104 +0,0 @@ - -require "spec_helper" -require "spec/support/shared/context/client" - -# requires platform and platform_version be defined -shared_examples "a completed run" do - include_context "run completed" - - it "runs ohai, sets up authentication, loads node state, synchronizes policy, converges, and runs audits" do - # This is what we're testing. - expect(client.run).to be true - - # fork is stubbed, so we can see the outcome of the run - expect(node.automatic_attrs[:platform]).to eq(platform) - expect(node.automatic_attrs[:platform_version]).to eq(platform_version) - end - - describe "setting node GUID" do - let(:chef_guid_path) { "/tmp/chef_guid" } - let(:chef_guid) { "test-test-test" } - let(:metadata_file) { "data_collector_metadata.json" } - let(:metadata_path) { Pathname.new(File.join(Chef::Config[:file_cache_path], metadata_file)).cleanpath.to_s } - let(:file) { instance_double(File) } - - before do - allow(File).to receive(:read).and_call_original - Chef::Config[:chef_guid_path] = chef_guid_path - Chef::Config[:chef_guid] = nil - end - - it "loads from the config" do - expect(File).to receive(:exists?).with(chef_guid_path).and_return(true) - expect(File).to receive(:read).with(chef_guid_path).and_return(chef_guid) - client.run - expect(Chef::Config[:chef_guid]).to eql(chef_guid) - expect(node.automatic_attrs[:chef_guid]).to eql(chef_guid) - end - - it "loads from the data collector config" do - expect(File).to receive(:exists?).with(chef_guid_path).and_return(false) - expect(Chef::FileCache).to receive(:load).with(metadata_file).and_return("{\"node_uuid\": \"#{chef_guid}\"}") - - expect(File).to receive(:open).with(chef_guid_path, "w+").and_yield(file) - expect(file).to receive(:write).with(chef_guid) - - client.run - expect(Chef::Config[:chef_guid]).to eql(chef_guid) - expect(node.automatic_attrs[:chef_guid]).to eql(chef_guid) - end - - it "creates a new one" do - expect(File).to receive(:exists?).with(chef_guid_path).and_return(false) - expect(File).to receive(:exists?).with(metadata_path).and_return(false) - - expect(SecureRandom).to receive(:uuid).and_return(chef_guid).at_least(:once) - - # we'll try and write the generated UUID to the data collector too, and that's ok - allow(File).to receive(:open).with(metadata_path, "w", 420) - - expect(File).to receive(:open).with(chef_guid_path, "w+").and_yield(file) - expect(file).to receive(:write).with(chef_guid) - - client.run - expect(Chef::Config[:chef_guid]).to eql(chef_guid) - expect(node.automatic_attrs[:chef_guid]).to eql(chef_guid) - end - end -end - -shared_examples "a completed run with audit failure" do - include_context "run completed" - - before do - expect(Chef::Application).to receive(:debug_stacktrace).with an_instance_of(Chef::Exceptions::RunFailedWrappingError) - end - - it "converges, runs audits, saves the node and raises the error in a wrapping error" do - expect { client.run }.to raise_error(Chef::Exceptions::RunFailedWrappingError) do |error| - expect(error.wrapped_errors.size).to eq(run_errors.size) - run_errors.each do |run_error| - expect(error.wrapped_errors).to include(run_error) - expect(error.backtrace).to include(*run_error.backtrace) - end - end - - # fork is stubbed, so we can see the outcome of the run - expect(node.automatic_attrs[:platform]).to eq(platform) - expect(node.automatic_attrs[:platform_version]).to eq(platform_version) - end -end - -shared_examples "a failed run" do - include_context "run failed" - - it "skips node save and raises the error in a wrapping error" do - expect { client.run }.to raise_error(Chef::Exceptions::RunFailedWrappingError) do |error| - expect(error.wrapped_errors.size).to eq(run_errors.size) - run_errors.each do |run_error| - expect(error.wrapped_errors).to include(run_error) - expect(error.backtrace).to include(*run_error.backtrace) - end - end - end -end |