From 6323a1c51022ed7e84d955138fe3169042f5818c Mon Sep 17 00:00:00 2001 From: Julia Kreger Date: Thu, 5 Nov 2015 23:27:29 -0500 Subject: [PATCH] Add functional testing of CSV file parsing The CSV file parsing feature of bifrost is ultimately the most logic heavy feature of the inventory and thus sensitive to change. As a result, we need test supplying input and see if our expected output results. Variations added including base ssh/vm testing, ipmi with and without bridging, and if a DHCP address is defined. Testing the results of these combonations should help identify any changes to the CSV parsing that may break users. As part of this, it was realized the CSV example lacks a driver filed example, and minor tweak of the unit testing file. Change-Id: Id50db2387dac32a9c16e927db309a32a7806d7cc Partial-Bug: 1499801 --- bifrost/tests/functional/__init__.py | 0 .../functional/test_inventory_functional.py | 122 ++++++++++++++++++ bifrost/tests/unit/test_inventory.py | 3 +- bifrost/tests/utils.py | 45 +++++++ playbooks/inventory/baremetal.csv.example | 4 +- 5 files changed, 171 insertions(+), 3 deletions(-) create mode 100644 bifrost/tests/functional/__init__.py create mode 100644 bifrost/tests/functional/test_inventory_functional.py create mode 100644 bifrost/tests/utils.py diff --git a/bifrost/tests/functional/__init__.py b/bifrost/tests/functional/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/bifrost/tests/functional/test_inventory_functional.py b/bifrost/tests/functional/test_inventory_functional.py new file mode 100644 index 000000000..e2b80c0ec --- /dev/null +++ b/bifrost/tests/functional/test_inventory_functional.py @@ -0,0 +1,122 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2015 Hewlett-Packard Development Company, L.P. +# +# 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. + +import json + +from bifrost.tests import base +from bifrost.tests import utils + + +class TestBifrostInventoryFunctional(base.TestCase): + + def setUp(self): + self.maxDiff = None + super(TestBifrostInventoryFunctional, self).setUp() + + def test_csv_file_conversion_multiline_general(self): + # NOTE(TheJulia): While this is a massive amount of input + # and resulting output that is parsed as part of this + # and similar tests, we need to ensure consistency, + # and that is largely what this test is geared to ensure. + CSV = """00:01:02:03:04:05,root,undefined,192.0.2.2,1,8192,512, +unused,,00000000-0000-0000-0000-000000000001,hostname0, +192.168.1.2,,,,| +00:01:02:03:04:06,root,undefined,192.0.2.3,2,8192,1024, +unused,,00000000-0000-0000-0000-000000000002,hostname1, +192.168.1.3,,,,,agent_ipmitool""".replace('\n', '').replace('|', '\n') + expected_hostvars = """{"hostname1": + {"uuid": "00000000-0000-0000-0000-000000000002", "driver": "agent_ipmitool", + "name": "hostname1", "ipv4_address": "192.168.1.3", "ansible_ssh_host": + "192.168.1.3", "driver_info": {"power": {"ipmi_address": "192.0.2.3", + "ipmi_password": "undefined", "ipmi_username": "root", + "ipmi_target_address": null, "ipmi_target_channel": null, + "ipmi_transit_address": null, "ipmi_transit_channel": null}}, "nics": + [{"mac": "00:01:02:03:04:06"}], "properties": {"ram": "8192", "cpu_arch": + "x86_64", "disk_size": "1024", "cpus": "2"}}, "hostname0": + {"uuid": "00000000-0000-0000-0000-000000000001", "driver": "agent_ssh", + "name": "hostname0", "ipv4_address": "192.168.1.2", "ansible_ssh_host": + "192.168.1.2", "driver_info": {"power": {"ssh_virt_type": "virsh", + "ssh_key_filename": "/home/ironic/.ssh/id_rsa", "ssh_username": + "ironic", "ssh_port": 22, "ssh_address": "192.0.2.2"}}, "nics": + [{"mac": "00:01:02:03:04:05"}], "properties": {"ram": "8192", + "cpu_arch": "x86_64", "disk_size": "512", "cpus": "1"}}}""".replace('\n', '') + expected_groups = """{"baremetal": {"hosts": ["hostname0", + "hostname1"]}, "localhost": {"hosts": ["127.0.0.1"]}}""".replace('\n', '') + + (groups, hostvars) = utils.bifrost_csv_conversion(CSV) + self.assertDictEqual(json.loads(str(expected_hostvars)), hostvars) + self.assertDictEqual(json.loads(expected_groups), groups) + + def test_csv_file_conversion_ipmi_dual_bridging(self): + CSV = """00:01:02:03:04:06,root,undefined,192.0.2.3,2,8192,1024, +unused,,00000000-0000-0000-0000-000000000002,hostname1, +192.168.1.3,10,20,30,40,agent_ipmitool""".replace('\n', '').replace('|', '\n') + + expected_hostvars = """{"hostname1": + {"uuid": "00000000-0000-0000-0000-000000000002", "driver": "agent_ipmitool", + "name": "hostname1", "ipv4_address": "192.168.1.3", "ansible_ssh_host": + "192.168.1.3", "driver_info": {"power": {"ipmi_address": "192.0.2.3", + "ipmi_password": "undefined", "ipmi_username": "root", + "ipmi_target_address": "20", "ipmi_target_channel": "10", + "ipmi_transit_address": "40", "ipmi_transit_channel": "30", + "ipmi_bridging": "dual"}}, "nics": + [{"mac": "00:01:02:03:04:06"}], "properties": {"ram": "8192", "cpu_arch": + "x86_64", "disk_size": "1024", "cpus": "2"}}}""".replace('\n', '') + + expected_groups = """{"baremetal": {"hosts": ["hostname1"]}, + "localhost": {"hosts": ["127.0.0.1"]}}""".replace('\n', '') + + (groups, hostvars) = utils.bifrost_csv_conversion(CSV) + self.assertDictEqual(json.loads(str(expected_hostvars)), hostvars) + self.assertDictEqual(json.loads(expected_groups), groups) + + def test_csv_file_conversion_ipmi_single_bridging(self): + CSV = """00:01:02:03:04:06,root,undefined,192.0.2.3,2,8192,1024, +unused,,00000000-0000-0000-0000-000000000002,hostname1, +192.168.1.3,10,20,,,agent_ipmitool""".replace('\n', '').replace('|', '\n') + + expected_hostvars = """{"hostname1": + {"uuid": "00000000-0000-0000-0000-000000000002", "driver": "agent_ipmitool", + "name": "hostname1", "ipv4_address": "192.168.1.3", "ansible_ssh_host": + "192.168.1.3", "driver_info": {"power": {"ipmi_address": "192.0.2.3", + "ipmi_password": "undefined", "ipmi_username": "root", + "ipmi_target_address": "20", "ipmi_target_channel": "10", + "ipmi_transit_address": null, "ipmi_transit_channel": null, + "ipmi_bridging": "single"}}, "nics": + [{"mac": "00:01:02:03:04:06"}], "properties": {"ram": "8192", "cpu_arch": + "x86_64", "disk_size": "1024", "cpus": "2"}}}""".replace('\n', '') + + (groups, hostvars) = utils.bifrost_csv_conversion(CSV) + self.assertDictEqual(json.loads(str(expected_hostvars)), hostvars) + + def test_csv_file_conversion_dhcp(self): + CSV = """00:01:02:03:04:06,root,undefined,192.0.2.3,2,8192,1024, +unused,,00000000-0000-0000-0000-000000000002,hostname1 +,,,,,,agent_ipmitool""".replace('\n', '').replace('|', '\n') + + expected_hostvars = """{"hostname1": + {"uuid": "00000000-0000-0000-0000-000000000002", "driver": "agent_ipmitool", + "name": "hostname1", "addressing_mode": "dhcp", "ipv4_address": null, + "driver_info": {"power": {"ipmi_address": "192.0.2.3", "ipmi_password": + "undefined", "ipmi_username": "root", "ipmi_target_address": null, + "ipmi_target_channel": null, "ipmi_transit_address": null, + "ipmi_transit_channel": null}}, "nics": + [{"mac": "00:01:02:03:04:06"}], "properties": {"ram": "8192", "cpu_arch": + "x86_64", "disk_size": "1024", "cpus": "2"}}}""".replace('\n', '') + + (groups, hostvars) = utils.bifrost_csv_conversion(CSV) + self.assertDictEqual(json.loads(str(expected_hostvars)), hostvars) diff --git a/bifrost/tests/unit/test_inventory.py b/bifrost/tests/unit/test_inventory.py index a84652007..b5395d1fc 100644 --- a/bifrost/tests/unit/test_inventory.py +++ b/bifrost/tests/unit/test_inventory.py @@ -20,10 +20,11 @@ Tests for `bifrost` module. """ from bifrost import inventory + from bifrost.tests import base -class TestBifrostInventory(base.TestCase): +class TestBifrostInventoryUnit(base.TestCase): def test_inventory_preparation(self): (groups, hostvars) = inventory._prepare_inventory() diff --git a/bifrost/tests/utils.py b/bifrost/tests/utils.py new file mode 100644 index 000000000..9027e72ed --- /dev/null +++ b/bifrost/tests/utils.py @@ -0,0 +1,45 @@ +# Copyright (c) 2015 Hewlett-Packard Development Company, L.P. +# +# 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. + +import contextlib +import tempfile + +from bifrost import inventory + + +@contextlib.contextmanager +def temporary_file(file_data): + file = None + file = tempfile.NamedTemporaryFile(mode='w') + file.write(file_data) + file.flush() + + try: + yield file.name + finally: + if file is not None: + file.close() + + +def bifrost_csv_conversion(csv_data): + # TODO(TheJulia): To call prep feels like a bug and should be fixed. + (groups, hostvars) = inventory._prepare_inventory() + with temporary_file(csv_data) as file: + (groups, hostvars) = inventory._process_baremetal_csv( + file, + groups, + hostvars) + # NOTE(TheJulia): Returning separately so the file is closed first + return (groups, hostvars) diff --git a/playbooks/inventory/baremetal.csv.example b/playbooks/inventory/baremetal.csv.example index ca9a47cfd..bc3e273f9 100644 --- a/playbooks/inventory/baremetal.csv.example +++ b/playbooks/inventory/baremetal.csv.example @@ -1,5 +1,5 @@ -00:1c:ab:8a:97:eb,root,undefined,192.168.122.1,1,8192,512,Control,VM,a8cb6624-0d9f-c882-affc-046ebb96ec01,hostname0,192.168.1.2,,,, -00:2b:b7:65:83:19,root,undefined,192.168.122.1,1,8192,512,Control,VM,a8cb6624-0d9f-c882-affc-046ebb96ec02,hostname1,192.168.1.3,,,, +00:1c:ab:8a:97:eb,root,undefined,192.168.122.1,1,8192,512,Control,VM,a8cb6624-0d9f-c882-affc-046ebb96ec01,hostname0,192.168.1.2,,,,,agent_ipmitool +00:2b:b7:65:83:19,root,undefined,192.168.122.1,1,8192,512,Control,VM,a8cb6624-0d9f-c882-affc-046ebb96ec02,hostname1,192.168.1.3,,,,,pxe_ipmitool 00:3a:ca:56:7d:2e,root,undefined,192.168.122.1,1,8192,512,Control,VM,a8cb6624-0d9f-c882-affc-046ebb96ec03,hostname2,192.168.1.4,,,, 00:4e:d5:45:6f:31,root,undefined,192.168.122.1,1,8192,512,SwiftStorage,VM,a8cb6624-0d9f-c882-affc-046ebb96ec04,hostname3,192.168.1.5,,,, 00:5a:ed:39:57:31,root,undefined,192.168.122.1,1,8192,512,SwiftStorage,VM,a8cb6624-0d9f-c882-affc-046ebb96ec05,hostname4,192.168.1.6,,,,