Skip to content

Commit

Permalink
Properly handle multiple things being returned from Windows API.
Browse files Browse the repository at this point in the history
Signed-off-by: Pete Higgins <pete@peterhiggins.org>
  • Loading branch information
phiggins committed Apr 15, 2020
1 parent be90072 commit 065d46c
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 40 deletions.
25 changes: 15 additions & 10 deletions lib/ohai/plugins/windows/dmi.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,21 +53,26 @@
# `Ohai::Common::CMI.convenience_keys` replace the faked-out `dmi`
# collection with the one with the original property names.
DMI_TO_WIN32OLE.each do |dmi_key, ole_key|
wmi_object = wmi.first_of("Win32_#{ole_key}").wmi_ole_object
wmi_objects = wmi.instances_of("Win32_#{ole_key}").map(&:wmi_ole_object)

split_name_properties = Mash.new
properties = Mash.new
split_name_properties = []
properties = []

wmi_object.properties_.each do |property|
property_name = property.name
value = wmi_object.invoke(property_name)
wmi_objects.each do |wmi_object|
split_name_properties << Mash.new
properties << Mash.new

split_name = property_name.scan(SPLIT_REGEX).join(" ")
split_name_properties[split_name] = value
properties[property_name] = value
wmi_object.properties_.each do |property|
property_name = property.name
value = wmi_object.invoke(property_name)

split_name = property_name.scan(SPLIT_REGEX).join(" ")
split_name_properties.last[split_name] = value
properties.last[property_name] = value
end
end

dmi[dmi_key] = Mash.new(all_records: [split_name_properties], _all_records: [properties])
dmi[dmi_key] = Mash.new(all_records: split_name_properties, _all_records: properties)
end

Ohai::Common::DMI.convenience_keys(dmi)
Expand Down
94 changes: 64 additions & 30 deletions spec/unit/plugins/windows/dmi_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,48 +21,82 @@
describe Ohai::System, "DMI", :windows_only do
let(:plugin) { get_plugin("windows/dmi") }

# Each test case has 3 elements:
# * The name of the property as it comes from the Windows APIs
# * The transformed snake-case version of the property name
# * A unique dummy value per test case
CASES = [
%w{Depth depth aaa},
%w{PartNumber part_number bbb},
%w{NumberOfPowerCords number_of_power_cords ccc},
%w{SKU sku ddd},
%w{SMBIOSAssetTag smbios_asset_tag eee},
%w{DeviceID device_id fff},
%w{L2CacheSize l2_cache_size ggg},
].freeze

before do
require "wmi-lite/wmi"

properties = CASES.map {|name, _, _| double(name: name) }
wmi_ole_object = double properties_: properties

CASES.each do |name, _, value|
allow(wmi_ole_object).to receive(:invoke).with(name).and_return(value)
empty_wmi_object = WmiLite::Wmi::Instance.new(double(properties_: []))
%w{Processor Bios ComputerSystemProduct BaseBoard}.each do |type|
expect_any_instance_of(WmiLite::Wmi).to receive(:instances_of).with("Win32_#{type}").and_return([empty_wmi_object])
end
end

wmi_object = WmiLite::Wmi::Instance.new(wmi_ole_object)
expect_any_instance_of(WmiLite::Wmi).to receive(:first_of).with("Win32_SystemEnclosure").and_return(wmi_object)
context "when property names are different types of camel casing" do
# Each test case has 3 elements:
# * The name of the property as it comes from the Windows APIs
# * The transformed snake-case version of the property name
# * A unique dummy value per test case
CASES = [
%w{Depth depth aaa},
%w{PartNumber part_number bbb},
%w{NumberOfPowerCords number_of_power_cords ccc},
%w{SKU sku ddd},
%w{SMBIOSAssetTag smbios_asset_tag eee},
%w{DeviceID device_id fff},
%w{L2CacheSize l2_cache_size ggg},
].freeze

empty_wmi_object = WmiLite::Wmi::Instance.new(double(properties_: []))
%w{Processor Bios ComputerSystemProduct BaseBoard}.each do |type|
expect_any_instance_of(WmiLite::Wmi).to receive(:first_of).with("Win32_#{type}").and_return(empty_wmi_object)
before do
properties = CASES.map {|name, _, _| double(name: name) }
wmi_ole_object = double properties_: properties

CASES.each do |name, _, value|
allow(wmi_ole_object).to receive(:invoke).with(name).and_return(value)
end

wmi_object = WmiLite::Wmi::Instance.new(wmi_ole_object)
expect_any_instance_of(WmiLite::Wmi).to receive(:instances_of).with("Win32_SystemEnclosure").and_return([wmi_object])

plugin.run
end

plugin.run
CASES.each do |name, transformed_name, value|
it "adds #{name} to :all_records" do
expect(plugin[:dmi][:chassis][:all_records].first[name]).to eq(value)
end

it "adds #{transformed_name} to the root" do
expect(plugin[:dmi][:chassis][transformed_name]).to eq(value)
end
end
end

CASES.each do |name, transformed_name, value|
it "adds #{name} to :all_records" do
expect(plugin[:dmi][:chassis][:all_records].first[name]).to eq(value)
context "when multiple objects of one type are returned from the Windows API" do
before do
properties = [
double(name: "UniqueProperty"),
double(name: "SharedProperty"),
]

wmi_ole_objects = %w[tacos nachos].map do |value|
object = double properties_: properties
allow(object).to receive(:invoke).with("UniqueProperty").and_return(value)
allow(object).to receive(:invoke).with("SharedProperty").and_return("Taco Bell")
object
end

wmi_objects = wmi_ole_objects.map {|o| WmiLite::Wmi::Instance.new(o) }
expect_any_instance_of(WmiLite::Wmi).to receive(:instances_of).with("Win32_SystemEnclosure").and_return(wmi_objects)

plugin.run
end

it "adds unique values to :all_records" do
values = plugin[:dmi][:chassis][:all_records].map {|r| r["UniqueProperty"] }
expect(values).to eq(%w[tacos nachos])
end

it "adds #{transformed_name} to the root" do
expect(plugin[:dmi][:chassis][transformed_name]).to eq(value)
it "adds shared values to the root with snake case key" do
expect(plugin[:dmi][:chassis]["shared_property"]).to eq("Taco Bell")
end
end
end

0 comments on commit 065d46c

Please sign in to comment.