From 23892ce1ad574042412e9cfb6a676fc994107250 Mon Sep 17 00:00:00 2001 From: "Ian H. Pittwood" Date: Tue, 4 Jun 2019 15:43:59 -0500 Subject: [PATCH] Add unit tests for xls plugin CLI This change implements unit tests for the Spyglass XLS plugin CLI. Change-Id: I0761f8508f3134b1ffb77e78543a72bf1fcf5ca5 --- .zuul.yaml | 21 +- spyglass_plugin_xls/cli.py | 2 +- spyglass_plugin_xls/examples/excel_spec.yaml | 88 +++---- spyglass_plugin_xls/examples/site_config.yaml | 6 +- test-requirements.txt | 5 + tests/__init__.py | 0 tests/shared/SiteDesignSpec_v0.1.xlsx | Bin 0 -> 17291 bytes tests/shared/excel_spec.yaml | 63 +++++ tests/shared/site_config.yaml | 33 +++ .../shared/templates/site-definition.yaml.j2 | 13 + tests/unit/__init__.py | 0 tests/unit/test_cli.py | 229 ++++++++++++++++++ tools/gate/run-unit-tests.sh | 12 + tox.ini | 14 +- 14 files changed, 436 insertions(+), 50 deletions(-) create mode 100644 tests/__init__.py create mode 100644 tests/shared/SiteDesignSpec_v0.1.xlsx create mode 100644 tests/shared/excel_spec.yaml create mode 100644 tests/shared/site_config.yaml create mode 100644 tests/shared/templates/site-definition.yaml.j2 create mode 100644 tests/unit/__init__.py create mode 100644 tests/unit/test_cli.py create mode 100755 tools/gate/run-unit-tests.sh diff --git a/.zuul.yaml b/.zuul.yaml index e7c200a..17f6011 100644 --- a/.zuul.yaml +++ b/.zuul.yaml @@ -1,3 +1,22 @@ +# 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. - project: templates: - - noop-jobs + - openstack-python36-jobs + - openstack-python37-jobs + - openstack-cover-jobs + check: + jobs: + - openstack-tox-pep8 + gate: + jobs: + - openstack-tox-pep8 diff --git a/spyglass_plugin_xls/cli.py b/spyglass_plugin_xls/cli.py index 7cdc3ea..fda9787 100644 --- a/spyglass_plugin_xls/cli.py +++ b/spyglass_plugin_xls/cli.py @@ -151,7 +151,7 @@ def generate_manifests_and_intermediary(*args, **kwargs): spyglass.cli.intermediary_processor('excel', **kwargs) LOG.info("Generate intermediary yaml") intermediary_yaml = process_input_ob.generate_intermediary_yaml() - if generate_intermediary: + if kwargs["generate_intermediary"]: LOG.debug("Dumping intermediary yaml") process_input_ob.dump_intermediary_file(kwargs['intermediary_dir']) else: diff --git a/spyglass_plugin_xls/examples/excel_spec.yaml b/spyglass_plugin_xls/examples/excel_spec.yaml index 694738e..be15b26 100644 --- a/spyglass_plugin_xls/examples/excel_spec.yaml +++ b/spyglass_plugin_xls/examples/excel_spec.yaml @@ -17,47 +17,47 @@ # design spec file. --- specs: - # Design Spec file name: SiteDesignSpec_v0.1.xlsx - xl_spec: - ipmi_sheet_name: 'Site-Information' - start_row: 4 - end_row: 15 - hostname_col: 2 - ipmi_address_col: 3 - host_profile_col: 5 - ipmi_gateway_col: 4 - private_ip_sheet: 'Site-Information' - net_type_col: 1 - vlan_col: 2 - vlan_start_row: 19 - vlan_end_row: 30 - net_start_row: 33 - net_end_row: 40 - net_col: 2 - net_vlan_col: 1 - public_ip_sheet: 'Site-Information' - oam_vlan_col: 1 - oam_ip_row: 43 - oam_ip_col: 2 - oob_net_row: 48 - oob_net_start_col: 2 - oob_net_end_col: 5 - ingress_ip_row: 45 - dns_ntp_ldap_sheet: 'Site-Information' - login_domain_row: 52 - ldap_col: 2 - global_group: 53 - ldap_search_url_row: 54 - ntp_row: 55 - ntp_col: 2 - dns_row: 56 - dns_col: 2 - domain_row: 51 - domain_col: 2 - location_sheet: 'Site-Information' - column: 2 - corridor_row: 59 - site_name_row: 58 - state_name_row: 60 - country_name_row: 61 - clli_name_row: 62 + # Design Spec file name: SiteDesignSpec_v0.1.xlsx + xl_spec: + ipmi_sheet_name: 'Site-Information' + start_row: 4 + end_row: 15 + hostname_col: 2 + ipmi_address_col: 3 + host_profile_col: 5 + ipmi_gateway_col: 4 + private_ip_sheet: 'Site-Information' + net_type_col: 1 + vlan_col: 2 + vlan_start_row: 19 + vlan_end_row: 30 + net_start_row: 33 + net_end_row: 40 + net_col: 2 + net_vlan_col: 1 + public_ip_sheet: 'Site-Information' + oam_vlan_col: 1 + oam_ip_row: 43 + oam_ip_col: 2 + oob_net_row: 48 + oob_net_start_col: 2 + oob_net_end_col: 5 + ingress_ip_row: 45 + dns_ntp_ldap_sheet: 'Site-Information' + login_domain_row: 52 + ldap_col: 2 + global_group: 53 + ldap_search_url_row: 54 + ntp_row: 55 + ntp_col: 2 + dns_row: 56 + dns_col: 2 + domain_row: 51 + domain_col: 2 + location_sheet: 'Site-Information' + column: 2 + corridor_row: 59 + site_name_row: 58 + state_name_row: 60 + country_name_row: 61 + clli_name_row: 62 diff --git a/spyglass_plugin_xls/examples/site_config.yaml b/spyglass_plugin_xls/examples/site_config.yaml index 25fa990..13979f6 100644 --- a/spyglass_plugin_xls/examples/site_config.yaml +++ b/spyglass_plugin_xls/examples/site_config.yaml @@ -1,6 +1,6 @@ -################################## -# Site Specific Tugboat Settings # -################################## +############################################## +# Site Specific Spyglass XLS Plugin Settings # +############################################## --- site_info: ldap: diff --git a/test-requirements.txt b/test-requirements.txt index fa50bf3..ed5a1e6 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -1,3 +1,8 @@ +# Testing +pytest==4.4.1 +pytest-xdist==1.28.0 +pytest-cov==2.6.1 + # Formatting yapf==0.27.0 diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/shared/SiteDesignSpec_v0.1.xlsx b/tests/shared/SiteDesignSpec_v0.1.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..cdf827808bc2f887f635c8985579449e8234fb03 GIT binary patch literal 17291 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