diff options
author | Adam Edwards <adamed@opscode.com> | 2014-05-17 06:48:53 -0700 |
---|---|---|
committer | Adam Edwards <adamed@opscode.com> | 2014-05-17 06:48:53 -0700 |
commit | cabc5171e3d65b9a9a9831a0a07588f20c90c3e7 (patch) | |
tree | 476f8dca1941ffa239f1b0ba97a6238080f4b56f | |
parent | 9902fd92d533c30ffc167177826e61de122800e0 (diff) | |
download | wmi-lite-cabc5171e3d65b9a9a9831a0a07588f20c90c3e7.tar.gz |
More specific error handling
-rw-r--r-- | lib/wmi-lite/wmi.rb | 42 | ||||
-rw-r--r-- | lib/wmi-lite/wmi_exception.rb | 48 | ||||
-rw-r--r-- | spec/functional/wmi_spec.rb | 25 | ||||
-rw-r--r-- | spec/unit/wmi_spec.rb | 57 |
4 files changed, 150 insertions, 22 deletions
diff --git a/lib/wmi-lite/wmi.rb b/lib/wmi-lite/wmi.rb index cc6492d..b712ba9 100644 --- a/lib/wmi-lite/wmi.rb +++ b/lib/wmi-lite/wmi.rb @@ -18,32 +18,25 @@ require 'win32ole' if RUBY_PLATFORM =~ /mswin|mingw32|windows/ require 'wmi-lite/wmi_instance' +require 'wmi-lite/wmi_exception' module WmiLite class Wmi def initialize(namespace = nil) - @namespace = namespace + @namespace = namespace.nil? ? 'root/cimv2' : namespace @connection = nil end def query(wql_query) - results = start_query(wql_query) - - result_set = [] - - results.each do | result | - result_set.push(wmi_result_to_snapshot(result)) - end - - result_set + query_with_context(wql_query) end def instances_of(wmi_class) - query("select * from #{wmi_class}") + query_with_context("select * from #{wmi_class}", wmi_class) end def first_of(wmi_class) - query_result = start_query("select * from #{wmi_class}") + query_result = start_query("select * from #{wmi_class}", wmi_class) first_result = nil query_result.each do | record | first_result = record @@ -54,10 +47,27 @@ module WmiLite private - def start_query(wql_query) - connect_to_namespace - result = @connection.ExecQuery(wql_query) - raise_if_failed(result) + def query_with_context(wql_query, diagnostic_class_name = nil) + results = start_query(wql_query, diagnostic_class_name) + + result_set = [] + + results.each do | result | + result_set.push(wmi_result_to_snapshot(result)) + end + + result_set + end + + def start_query(wql_query, diagnostic_class_name = nil) + result = nil + begin + connect_to_namespace + result = @connection.ExecQuery(wql_query) + raise_if_failed(result) + rescue WIN32OLERuntimeError => native_exception + raise WmiException.new(native_exception, @namespace, wql_query, diagnostic_class_name) + end result end diff --git a/lib/wmi-lite/wmi_exception.rb b/lib/wmi-lite/wmi_exception.rb new file mode 100644 index 0000000..85c6387 --- /dev/null +++ b/lib/wmi-lite/wmi_exception.rb @@ -0,0 +1,48 @@ +# +# Author:: Adam Edwards (<adamed@getchef.com>) +# Copyright:: Copyright 2014 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. +# + +module WmiLite + class WmiException < Exception + def initialize(exception, namespace, query, class_name) + error_message = exception.message + error_code = nil + + # Parse the error to get the error status code + error_code_match = error_message.match(/[^\:]+\:\s*([0-9A-Fa-f]{1,8}).*/) + error_code = error_code_match.captures.first if error_code_match + error_code = '' if error_code.nil? + + # Use the status code to generate a more friendly message + case error_code + when /80041010/i + if class_name + error_message = "The specified class \'#{class_name}\' is not valid in the namespace \'#{namespace}\'.\n#{exception.message}." + else + error_message = "The specified query \'#{query}\' referenced a class that is not valid in the namespace \'#{namespace}\'\n#{exception.message}." + end + when /8004100E/i + error_message = "The specified namespace \'#{namespace}\' is not valid.\n#{exception.message}" + when /80041017/i + error_message = "The specified query \'#{query}\' is not valid.\n#{exception.message}" + end + + super(error_message) + end + end +end + diff --git a/spec/functional/wmi_spec.rb b/spec/functional/wmi_spec.rb index 53bf548..0be3778 100644 --- a/spec/functional/wmi_spec.rb +++ b/spec/functional/wmi_spec.rb @@ -35,16 +35,22 @@ describe WmiLite::Wmi, :windows_only do results = wmi.send(query_method, query_parameter) validate_wmi_results(results, wmi_class) end + + describe 'when the namespace is invalid' do + it_behaves_like 'an invalid namespace' + end end shared_examples_for 'an invalid query' do - it 'should raise an exception if an invalid namespace is specified' do - invalid_wmi = WmiLite::Wmi.new('root/notvalid') - expect { invalid_wmi.ExecQuery('Win32_Process') }.to raise_error + it 'should raise an exception' do + expect { wmi.send(query_method, wmi_query) }.to raise_error(WmiLite::WmiException) end + end - it 'should raise an exception if an invalid class is specified' do - expect { wmi.send(query_method, wmi_query) }.to raise_error + shared_examples_for 'an invalid namespace' do + it 'should raise an exception if an invalid namespace is specified' do + invalid_wmi = WmiLite::Wmi.new('root/notvalid') + expect { invalid_wmi.send(query_method, wmi_query) }.to raise_error(WmiLite::WmiException) end end @@ -88,10 +94,17 @@ describe WmiLite::Wmi, :windows_only do context 'when making invalid queries' do let(:namespace) { nil } - let(:wmi_query) { 'invalidclass' } + let(:wmi_query) { 'invalidclass' } let(:query_method) { :first_of } it_behaves_like 'an invalid query' + + let(:query_method) { :instances_of } + it_behaves_like 'an invalid query' + + let(:query_method) { :query } + let(:wmi_query) { 'nosql_4_life' } + it_behaves_like 'an invalid query' end let(:namespace) { nil } diff --git a/spec/unit/wmi_spec.rb b/spec/unit/wmi_spec.rb index beaaa46..d240f3e 100644 --- a/spec/unit/wmi_spec.rb +++ b/spec/unit/wmi_spec.rb @@ -148,6 +148,44 @@ describe WmiLite::Wmi do end + shared_examples_for 'an invalid query' do + let(:unparseable_error) { 'unparseableerror' } + it 'should raise an exception' do + wbem_connection.should_receive(:ExecQuery).and_raise(WIN32OLERuntimeError.new(unparseable_error)) + wmi_service = WmiLite::Wmi.new + expect { wmi_service.send(query_method, wmi_query) }.to raise_error(WmiLite::WmiException) + end + + it 'should raise an exception that starts with the original exception message' do + wbem_connection.should_receive(:ExecQuery).and_raise(WIN32OLERuntimeError.new(unparseable_error)) + wmi_service = WmiLite::Wmi.new + begin + wmi_service.send(query_method, wmi_query) + rescue WmiLite::WmiException => e + expect(e.message.start_with?(unparseable_error)).to eql(true) + end + end + end + + shared_examples_for 'an invalid namespace' do + let(:unparseable_error) { 'unparseableerror' } + it 'should raise an exception' do + wbem_locator.should_receive(:ConnectServer).and_raise(WIN32OLERuntimeError.new('unparseableerror')) + wmi_service = WmiLite::Wmi.new('notavalidnamespace') + expect { wmi_service.send(query_method, wmi_query) }.to raise_error(WmiLite::WmiException) + end + + it 'should raise an exception that starts with the original exception message' do + wbem_locator.should_receive(:ConnectServer).and_raise(WIN32OLERuntimeError.new('unparseableerror')) + wmi_service = WmiLite::Wmi.new + begin + wmi_service.send(query_method, wmi_query) + rescue WmiLite::WmiException => e + expect(e.message.start_with?(unparseable_error)).to eql(true) + end + end + end + shared_examples_for "the query method" do let(:wmi_properties1) { { 'cores' => 4, 'name' => 'mycomputer1', 'diskspace' => 400, 'os' => 'windows' } } @@ -212,6 +250,25 @@ describe WmiLite::Wmi do end end + context 'when making invalid queries' do + let(:namespace) { nil } + + let(:wmi_query) { 'invalidclass' } + let(:query_method) { :first_of } + + it_behaves_like 'an invalid query' + it_behaves_like 'an invalid namespace' + + let(:query_method) { :instances_of } + it_behaves_like 'an invalid query' + it_behaves_like 'an invalid namespace' + + let(:query_method) { :query } + let(:wmi_query) { 'nosql_4_life' } + it_behaves_like 'an invalid query' + it_behaves_like 'an invalid namespace' + end + it_should_behave_like "the first_of method" it_should_behave_like "the instances_of method" |