summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTyler Cloke <tylercloke@gmail.com>2015-04-29 11:10:00 -0700
committerTyler Cloke <tylercloke@gmail.com>2015-04-29 11:10:00 -0700
commitcd47ee5615506a83684ea80cac0d2abc277972f0 (patch)
tree3143b320046ba8eca2de5099c82a2800f21b1df6
parent8385125e5bf3bd4139f75c7f4d5d2cb030ebaa98 (diff)
parent9850147d638bae25d4fc2e1166e486d807ecdd9f (diff)
downloadchef-cd47ee5615506a83684ea80cac0d2abc277972f0.tar.gz
Merge pull request #3297 from chef/tc/key-list
Implemented `knife user key list` and `knife client key list`.
-rw-r--r--lib/chef/knife/client_key_list.rb69
-rw-r--r--lib/chef/knife/key_list.rb88
-rw-r--r--lib/chef/knife/key_list_base.rb45
-rw-r--r--lib/chef/knife/user_key_list.rb69
-rw-r--r--spec/support/key_helpers.rb74
-rw-r--r--spec/unit/knife/key_create_spec.rb50
-rw-r--r--spec/unit/knife/key_helper.rb74
-rw-r--r--spec/unit/knife/key_list_spec.rb214
8 files changed, 644 insertions, 39 deletions
diff --git a/lib/chef/knife/client_key_list.rb b/lib/chef/knife/client_key_list.rb
new file mode 100644
index 0000000000..f6f29ae03f
--- /dev/null
+++ b/lib/chef/knife/client_key_list.rb
@@ -0,0 +1,69 @@
+#
+# Author:: Tyler Cloke (tyler@chef.io)
+# Copyright:: Copyright (c) 2015 Chef Software, Inc
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'chef/knife'
+require 'chef/knife/key_list_base'
+
+class Chef
+ class Knife
+ # Implements knife user key list using Chef::Knife::KeyList
+ # as a service class.
+ #
+ # @author Tyler Cloke
+ #
+ # @attr_reader [String] actor the name of the client that this key is for
+ class ClientKeyList < Knife
+ include Chef::Knife::KeyListBase
+
+ banner "knife client key list CLIENT (options)"
+
+ attr_reader :actor
+
+ def initialize(argv=[])
+ super(argv)
+ @service_object = nil
+ end
+
+ def run
+ apply_params!(@name_args)
+ service_object.run
+ end
+
+ def list_method
+ :list_by_client
+ end
+
+ def actor_missing_error
+ 'You must specify a client name'
+ end
+
+ def service_object
+ @service_object ||= Chef::Knife::KeyList.new(@actor, list_method, ui, config)
+ end
+
+ def apply_params!(params)
+ @actor = params[0]
+ if @actor.nil?
+ show_usage
+ ui.fatal(actor_missing_error)
+ exit 1
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/knife/key_list.rb b/lib/chef/knife/key_list.rb
new file mode 100644
index 0000000000..e96a27161f
--- /dev/null
+++ b/lib/chef/knife/key_list.rb
@@ -0,0 +1,88 @@
+#
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'chef/key'
+require 'chef/json_compat'
+require 'chef/exceptions'
+
+class Chef
+ class Knife
+ # Service class for UserKeyList and ClientKeyList, used to list keys.
+ # Implements common functionality of knife [user | org client] key list.
+ #
+ # @author Tyler Cloke
+ #
+ # @attr_accessor [Hash] cli input, see UserKeyList and ClientKeyList for what could populate it
+ class KeyList
+
+ attr_accessor :config
+
+ def initialize(actor, list_method, ui, config)
+ @actor = actor
+ @list_method = list_method
+ @ui = ui
+ @config = config
+ end
+
+ def expired_and_non_expired_msg
+<<EOS
+You cannot pass both --only-expired and --only-non-expired.
+Please pass one or none.
+EOS
+ end
+
+ def display_info(string)
+ @ui.output(string)
+ end
+
+ def colorize(string)
+ @ui.color(string, :cyan)
+ end
+
+ def run
+ if @config[:only_expired] && @config[:only_non_expired]
+ raise Chef::Exceptions::KeyCommandInputError, expired_and_non_expired_msg
+ end
+
+ # call proper list function
+ keys = Chef::Key.send(@list_method, @actor)
+ if @config[:with_details]
+ max_length = 0
+ keys.each do |key|
+ key['name'] = key['name'] + ":"
+ max_length = key['name'].length if key['name'].length > max_length
+ end
+ keys.each do |key|
+ next if !key['expired'] && @config[:only_expired]
+ next if key['expired'] && @config[:only_non_expired]
+ display = "#{colorize(key['name'].ljust(max_length))} #{key['uri']}"
+ display = "#{display} (expired)" if key["expired"]
+ display_info(display)
+ end
+ else
+ keys.each do |key|
+ next if !key['expired'] && @config[:only_expired]
+ next if key['expired'] && @config[:only_non_expired]
+ display_info(key['name'])
+ end
+ end
+ end
+
+ end
+ end
+end
diff --git a/lib/chef/knife/key_list_base.rb b/lib/chef/knife/key_list_base.rb
new file mode 100644
index 0000000000..861db0d75a
--- /dev/null
+++ b/lib/chef/knife/key_list_base.rb
@@ -0,0 +1,45 @@
+#
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+class Chef
+ class Knife
+ # Extendable module that class_eval's common options into UserKeyList and ClientKeyList
+ #
+ # @author Tyler Cloke
+ module KeyListBase
+ def self.included(includer)
+ includer.class_eval do
+ option :with_details,
+ :short => "-w",
+ :long => "--with-details",
+ :description => "Show corresponding URIs and whether the key has expired or not."
+
+ option :only_expired,
+ :short => "-e",
+ :long => "--only-expired",
+ :description => "Only show expired keys."
+
+ option :only_non_expired,
+ :short => "-n",
+ :long => "--only-non-expired",
+ :description => "Only show non-expired keys."
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/knife/user_key_list.rb b/lib/chef/knife/user_key_list.rb
new file mode 100644
index 0000000000..a73f59c86f
--- /dev/null
+++ b/lib/chef/knife/user_key_list.rb
@@ -0,0 +1,69 @@
+#
+# Author:: Tyler Cloke (tyler@chef.io)
+# Copyright:: Copyright (c) 2015 Chef Software, Inc
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'chef/knife'
+require 'chef/knife/key_list_base'
+
+class Chef
+ class Knife
+ # Implements knife user key list using Chef::Knife::KeyList
+ # as a service class.
+ #
+ # @author Tyler Cloke
+ #
+ # @attr_reader [String] actor the name of the client that this key is for
+ class UserKeyList < Knife
+ include Chef::Knife::KeyListBase
+
+ banner "knife user key list USER (options)"
+
+ attr_reader :actor
+
+ def initialize(argv=[])
+ super(argv)
+ @service_object = nil
+ end
+
+ def run
+ apply_params!(@name_args)
+ service_object.run
+ end
+
+ def list_method
+ :list_by_user
+ end
+
+ def actor_missing_error
+ 'You must specify a user name'
+ end
+
+ def service_object
+ @service_object ||= Chef::Knife::KeyList.new(@actor, list_method, ui, config)
+ end
+
+ def apply_params!(params)
+ @actor = params[0]
+ if @actor.nil?
+ show_usage
+ ui.fatal(actor_missing_error)
+ exit 1
+ end
+ end
+ end
+ end
+end
diff --git a/spec/support/key_helpers.rb b/spec/support/key_helpers.rb
new file mode 100644
index 0000000000..36ababc09a
--- /dev/null
+++ b/spec/support/key_helpers.rb
@@ -0,0 +1,74 @@
+#
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'spec_helper'
+
+shared_examples_for "a knife key command" do
+ let(:stderr) { StringIO.new }
+ let(:params) { [] }
+ let(:command) do
+ c = described_class.new([])
+ c.ui.config[:disable_editing] = true
+ allow(c.ui).to receive(:stderr).and_return(stderr)
+ allow(c.ui).to receive(:stdout).and_return(stderr)
+ allow(c).to receive(:show_usage)
+ c
+ end
+
+ context "before apply_params! is called" do
+ context "when apply_params! is called with invalid args" do
+ it "shows the usage" do
+ expect(command).to receive(:show_usage)
+ expect { command.apply_params!(params) }.to exit_with_code(1)
+ end
+
+ it "outputs the proper error" do
+ expect { command.apply_params!(params) }.to exit_with_code(1)
+ expect(stderr.string).to include(command.actor_missing_error)
+ end
+
+ it "exits 1" do
+ expect { command.apply_params!(params) }.to exit_with_code(1)
+ end
+ end
+ end # before apply_params! is called
+
+ context "after apply_params! is called with valid args" do
+ let(:params) { ["charmander"] }
+ before do
+ command.apply_params!(params)
+ end
+
+ it "properly defines the actor" do
+ expect(command.actor).to eq("charmander")
+ end
+ end # after apply_params! is called with valid args
+
+ context "when the command is run" do
+ before do
+ allow(command).to receive(:service_object).and_return(service_object)
+ allow(command).to receive(:name_args).and_return(["charmander"])
+ end
+
+ context "when the command is successful" do
+ before do
+ expect(service_object).to receive(:run)
+ end
+ end
+ end
+end # a knife key command
diff --git a/spec/unit/knife/key_create_spec.rb b/spec/unit/knife/key_create_spec.rb
index 1bdd0f3ba1..c24f57c9ac 100644
--- a/spec/unit/knife/key_create_spec.rb
+++ b/spec/unit/knife/key_create_spec.rb
@@ -23,12 +23,10 @@ require 'chef/knife/key_create'
require 'chef/key'
describe "key create commands that inherit knife" do
-
- let(:stderr) { StringIO.new }
- let(:params) { [] }
- let(:service_object) { instance_double(Chef::Knife::KeyCreate) }
-
shared_examples_for "a key create command" do
+ let(:stderr) { StringIO.new }
+ let(:params) { [] }
+ let(:service_object) { instance_double(Chef::Knife::KeyCreate) }
let(:command) do
c = described_class.new([])
c.ui.config[:disable_editing] = true
@@ -38,34 +36,12 @@ describe "key create commands that inherit knife" do
c
end
- context "before apply_params! is called" do
- context "when apply_params! is called with invalid args" do
- it "shows the usage" do
- expect(command).to receive(:show_usage)
- expect { command.apply_params!(params) }.to exit_with_code(1)
- end
-
- it "outputs the proper error" do
- expect { command.apply_params!(params) }.to exit_with_code(1)
- expect(stderr.string).to include(command.actor_missing_error)
- end
-
- it "exits 1" do
- expect { command.apply_params!(params) }.to exit_with_code(1)
- end
- end
- end # before apply_params! is called
-
context "after apply_params! is called with valid args" do
let(:params) { ["charmander"] }
before do
command.apply_params!(params)
end
- it "properly defines the actor" do
- expect(command.actor).to eq("charmander")
- end
-
context "when the service object is called" do
it "creates a new instance of Chef::Knife::KeyCreate with the correct args" do
expect(Chef::Knife::KeyCreate).to receive(:new).
@@ -75,26 +51,22 @@ describe "key create commands that inherit knife" do
end
end # when the service object is called
end # after apply_params! is called with valid args
- context "when the command is run" do
- before do
- allow(command).to receive(:service_object).and_return(service_object)
- allow(command).to receive(:name_args).and_return(["charmander"])
- end
-
- context "when the command is successful" do
- before do
- expect(service_object).to receive(:run)
- end
- end
- end
end # a key create command
describe Chef::Knife::UserKeyCreate do
it_should_behave_like "a key create command"
+ # defined in key_helper.rb
+ it_should_behave_like "a knife key command" do
+ let(:service_object) { instance_double(Chef::Knife::KeyCreate) }
+ end
end
describe Chef::Knife::ClientKeyCreate do
it_should_behave_like "a key create command"
+ # defined in key_helper.rb
+ it_should_behave_like "a knife key command" do
+ let(:service_object) { instance_double(Chef::Knife::KeyCreate) }
+ end
end
end
diff --git a/spec/unit/knife/key_helper.rb b/spec/unit/knife/key_helper.rb
new file mode 100644
index 0000000000..36ababc09a
--- /dev/null
+++ b/spec/unit/knife/key_helper.rb
@@ -0,0 +1,74 @@
+#
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'spec_helper'
+
+shared_examples_for "a knife key command" do
+ let(:stderr) { StringIO.new }
+ let(:params) { [] }
+ let(:command) do
+ c = described_class.new([])
+ c.ui.config[:disable_editing] = true
+ allow(c.ui).to receive(:stderr).and_return(stderr)
+ allow(c.ui).to receive(:stdout).and_return(stderr)
+ allow(c).to receive(:show_usage)
+ c
+ end
+
+ context "before apply_params! is called" do
+ context "when apply_params! is called with invalid args" do
+ it "shows the usage" do
+ expect(command).to receive(:show_usage)
+ expect { command.apply_params!(params) }.to exit_with_code(1)
+ end
+
+ it "outputs the proper error" do
+ expect { command.apply_params!(params) }.to exit_with_code(1)
+ expect(stderr.string).to include(command.actor_missing_error)
+ end
+
+ it "exits 1" do
+ expect { command.apply_params!(params) }.to exit_with_code(1)
+ end
+ end
+ end # before apply_params! is called
+
+ context "after apply_params! is called with valid args" do
+ let(:params) { ["charmander"] }
+ before do
+ command.apply_params!(params)
+ end
+
+ it "properly defines the actor" do
+ expect(command.actor).to eq("charmander")
+ end
+ end # after apply_params! is called with valid args
+
+ context "when the command is run" do
+ before do
+ allow(command).to receive(:service_object).and_return(service_object)
+ allow(command).to receive(:name_args).and_return(["charmander"])
+ end
+
+ context "when the command is successful" do
+ before do
+ expect(service_object).to receive(:run)
+ end
+ end
+ end
+end # a knife key command
diff --git a/spec/unit/knife/key_list_spec.rb b/spec/unit/knife/key_list_spec.rb
new file mode 100644
index 0000000000..b65697a105
--- /dev/null
+++ b/spec/unit/knife/key_list_spec.rb
@@ -0,0 +1,214 @@
+#
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'spec_helper'
+require 'chef/knife/user_key_list'
+require 'chef/knife/client_key_list'
+require 'chef/knife/key_list'
+require 'chef/key'
+
+describe "key list commands that inherit knife" do
+ shared_examples_for "a key list command" do
+ let(:stderr) { StringIO.new }
+ let(:params) { [] }
+ let(:service_object) { instance_double(Chef::Knife::KeyList) }
+ let(:command) do
+ c = described_class.new([])
+ c.ui.config[:disable_editing] = true
+ allow(c.ui).to receive(:stderr).and_return(stderr)
+ allow(c.ui).to receive(:stdout).and_return(stderr)
+ allow(c).to receive(:show_usage)
+ c
+ end
+
+ context "after apply_params! is called with valid args" do
+ let(:params) { ["charmander"] }
+ before do
+ command.apply_params!(params)
+ end
+
+ context "when the service object is called" do
+ it "creates a new instance of Chef::Knife::KeyList with the correct args" do
+ expect(Chef::Knife::KeyList).to receive(:new).
+ with("charmander", command.list_method, command.ui, command.config).
+ and_return(service_object)
+ command.service_object
+ end
+ end # when the service object is called
+ end # after apply_params! is called with valid args
+ end # a key list command
+
+ describe Chef::Knife::UserKeyList do
+ it_should_behave_like "a key list command"
+ # defined in key_helpers.rb
+ it_should_behave_like "a knife key command" do
+ let(:service_object) { instance_double(Chef::Knife::KeyList) }
+ end
+ end
+
+ describe Chef::Knife::ClientKeyList do
+ it_should_behave_like "a key list command"
+ # defined in key_helpers.rb
+ it_should_behave_like "a knife key command" do
+ let(:service_object) { instance_double(Chef::Knife::KeyList) }
+ end
+ end
+end
+
+describe Chef::Knife::KeyList do
+ let(:config) { Hash.new }
+ let(:actor) { "charmander" }
+ let(:ui) { instance_double("Chef::Knife::UI") }
+
+ shared_examples_for "key list run command" do
+ let(:key_list_object) {
+ described_class.new(actor, list_method, ui, config)
+ }
+
+ before do
+ allow(Chef::Key).to receive(list_method).and_return(http_response)
+ allow(key_list_object).to receive(:display_info)
+ # simply pass the string though that colorize takes in
+ allow(key_list_object).to receive(:colorize).with(kind_of(String)) do |input|
+ input
+ end
+ end
+
+ context "when only_expired and only_non_expired were both passed" do
+ before do
+ key_list_object.config[:only_expired] = true
+ key_list_object.config[:only_non_expired] = true
+ end
+
+ it "raises a Chef::Exceptions::KeyCommandInputError with the proper error message" do
+ expect{ key_list_object.run }.to raise_error(Chef::Exceptions::KeyCommandInputError, key_list_object.expired_and_non_expired_msg)
+ end
+ end
+
+ context "when the command is run" do
+ before do
+ key_list_object.config[:only_expired] = false
+ key_list_object.config[:only_non_expired] = false
+ key_list_object.config[:with_details] = false
+ end
+
+ it "calls Chef::Key with the proper list command and input" do
+ expect(Chef::Key).to receive(list_method).with(actor)
+ key_list_object.run
+ end
+
+ it "displays all the keys" do
+ expect(key_list_object).to receive(:display_info).with(/non-expired/).twice
+ expect(key_list_object).to receive(:display_info).with(/out-of-date/).once
+ key_list_object.run
+ end
+
+ context "when only_expired is called" do
+ before do
+ key_list_object.config[:only_expired] = true
+ end
+
+ it "excludes displaying non-expired keys" do
+ expect(key_list_object).to receive(:display_info).with(/non-expired/).exactly(0).times
+ key_list_object.run
+ end
+
+ it "displays the expired keys" do
+ expect(key_list_object).to receive(:display_info).with(/out-of-date/).once
+ key_list_object.run
+ end
+ end # when only_expired is called
+
+ context "when only_non_expired is called" do
+ before do
+ key_list_object.config[:only_non_expired] = true
+ end
+
+ it "excludes displaying expired keys" do
+ expect(key_list_object).to receive(:display_info).with(/out-of-date/).exactly(0).times
+ key_list_object.run
+ end
+
+ it "displays the non-expired keys" do
+ expect(key_list_object).to receive(:display_info).with(/non-expired/).twice
+ key_list_object.run
+ end
+ end # when only_expired is called
+
+ context "when with_details is false" do
+ before do
+ key_list_object.config[:with_details] = false
+ end
+
+ it "does not display the uri" do
+ expect(key_list_object).to receive(:display_info).with(/https/).exactly(0).times
+ key_list_object.run
+ end
+
+ it "does not display the expired status" do
+ expect(key_list_object).to receive(:display_info).with(/\(expired\)/).exactly(0).times
+ key_list_object.run
+ end
+ end # when with_details is false
+
+ context "when with_details is true" do
+ before do
+ key_list_object.config[:with_details] = true
+ end
+
+ it "displays the uri" do
+ expect(key_list_object).to receive(:display_info).with(/https/).exactly(3).times
+ key_list_object.run
+ end
+
+ it "displays the expired status" do
+ expect(key_list_object).to receive(:display_info).with(/\(expired\)/).once
+ key_list_object.run
+ end
+ end # when with_details is true
+
+ end # when the command is run
+
+ end # key list run command
+
+ context "when list_method is :list_by_user" do
+ it_should_behave_like "key list run command" do
+ let(:list_method) { :list_by_user }
+ let(:http_response) {
+ [
+ {"uri"=>"https://api.opscode.piab/users/charmander/keys/non-expired1", "name"=>"non-expired1", "expired"=>false},
+ {"uri"=>"https://api.opscode.piab/users/charmander/keys/non-expired2", "name"=>"non-expired2", "expired"=>false},
+ {"uri"=>"https://api.opscode.piab/users/mary/keys/out-of-date", "name"=>"out-of-date", "expired"=>true}
+ ]
+ }
+ end
+ end
+
+ context "when list_method is :list_by_client" do
+ it_should_behave_like "key list run command" do
+ let(:list_method) { :list_by_client }
+ let(:http_response) {
+ [
+ {"uri"=>"https://api.opscode.piab/organizations/pokemon/clients/charmander/keys/non-expired1", "name"=>"non-expired1", "expired"=>false},
+ {"uri"=>"https://api.opscode.piab/organizations/pokemon/clients/charmander/keys/non-expired2", "name"=>"non-expired2", "expired"=>false},
+ {"uri"=>"https://api.opscode.piab/organizations/pokemon/clients/mary/keys/out-of-date", "name"=>"out-of-date", "expired"=>true}
+ ]
+ }
+ end
+ end
+end