diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..0ac7820 --- /dev/null +++ b/debian/changelog @@ -0,0 +1,5 @@ +sonic-platform-pde (1.0) unstable; urgency=low + + * Add support for SAI unit test cores for SWIG-Python interface + + -- Dante Su Tue, 29 Oct 2019 15:00:00 +0800 diff --git a/debian/compat b/debian/compat new file mode 100644 index 0000000..ec63514 --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +9 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..fc83c3d --- /dev/null +++ b/debian/control @@ -0,0 +1,10 @@ +Source: sonic-platform-pde +Section: main +Priority: extra +Maintainer: Dante Su , Geans Pin , William Schwartz +Build-Depends: debhelper (>= 9), bzip2 +Standards-Version: 3.9.3 + +Package: sonic-platform-pde +Architecture: amd64 +Description: PDE test suite diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000..4d2724d --- /dev/null +++ b/debian/rules @@ -0,0 +1,25 @@ +#!/usr/bin/make -f + +PACKAGE_NAME := sonic-platform-pde +TOPDIR := $(shell pwd) +PYTHON ?= python2 + +%: + dh $@ + +override_dh_auto_build: + make -C sonic-pde-tests/sonic_pde_saiut + +override_dh_auto_install: + mkdir -p debian/$(PACKAGE_NAME)/usr/local + cp -rf $(TOPDIR)/sonic-pde-tests/sonic_pde_tests debian/$(PACKAGE_NAME)/usr/local + cp -rf $(TOPDIR)/sonic-pde-tests/sonic_pde_saiut/*.so debian/$(PACKAGE_NAME)/usr/local/sonic_pde_tests/ + cp -rf $(TOPDIR)/sonic-pde-tests/sonic_pde_saiut/*.py debian/$(PACKAGE_NAME)/usr/local/sonic_pde_tests/ + cd sonic-pde-tests; \ + $(PYTHON) setup.py install --root=$(TOPDIR)/debian/$(PACKAGE_NAME) --install-layout=deb + +override_dh_usrlocal: + +override_dh_clean: + dh_clean + make -C sonic-pde-tests/sonic_pde_saiut clean diff --git a/sonic-pde-tests/MANIFEST.in b/sonic-pde-tests/MANIFEST.in new file mode 100644 index 0000000..e69de29 diff --git a/sonic-pde-tests/docs/Makefile b/sonic-pde-tests/docs/Makefile new file mode 100644 index 0000000..bb72cd8 --- /dev/null +++ b/sonic-pde-tests/docs/Makefile @@ -0,0 +1,216 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = build + +# User-friendly check for sphinx-build +ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) +$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) +endif + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source + +.PHONY: help +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " applehelp to make an Apple Help Book" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + @echo " coverage to run coverage check of the documentation (if enabled)" + +.PHONY: clean +clean: + rm -rf $(BUILDDIR)/* + +.PHONY: html +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +.PHONY: dirhtml +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +.PHONY: singlehtml +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +.PHONY: pickle +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +.PHONY: json +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +.PHONY: htmlhelp +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +.PHONY: qthelp +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/sonic_pde_tests.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/sonic_pde_tests.qhc" + +.PHONY: applehelp +applehelp: + $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp + @echo + @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." + @echo "N.B. You won't be able to view it unless you put it in" \ + "~/Library/Documentation/Help or install it in your application" \ + "bundle." + +.PHONY: devhelp +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/sonic_pde_tests" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/sonic_pde_tests" + @echo "# devhelp" + +.PHONY: epub +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +.PHONY: latex +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +.PHONY: latexpdf +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +.PHONY: latexpdfja +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +.PHONY: text +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +.PHONY: man +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +.PHONY: texinfo +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +.PHONY: info +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +.PHONY: gettext +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +.PHONY: changes +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +.PHONY: linkcheck +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +.PHONY: doctest +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +.PHONY: coverage +coverage: + $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage + @echo "Testing of coverage in the sources finished, look at the " \ + "results in $(BUILDDIR)/coverage/python.txt." + +.PHONY: xml +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +.PHONY: pseudoxml +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/sonic-pde-tests/docs/README.rst b/sonic-pde-tests/docs/README.rst new file mode 100644 index 0000000..b6c92ac --- /dev/null +++ b/sonic-pde-tests/docs/README.rst @@ -0,0 +1,26 @@ +sonic_pde_tests +================ + +This package is a part of the SONiC Platform Development Kit (PDK) and packaged +under the SONiC Platform Development Environment (PDE). + +build +===== +- get source + +- cd && ./build.sh + + (generates sonic_pde_tests-.deb) + +install +======= + +- remove existing ifupdown package + dpkg -r sonic_pde_tests + +- install sonic_pde_tests using `dpkg -i` + +- or install from deb + dpkg -i sonic_pde_tests-.deb + + diff --git a/sonic-pde-tests/docs/source/conf.py b/sonic-pde-tests/docs/source/conf.py new file mode 100644 index 0000000..0d01213 --- /dev/null +++ b/sonic-pde-tests/docs/source/conf.py @@ -0,0 +1,300 @@ +# -*- coding: utf-8 -*- +# +# sonic_pde_tests documentation build configuration file, created by +# sphinx-quickstart on Wed Jul 31 12:33:51 2019. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys +import os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +sys.path.insert(0, os.path.abspath('../../')) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.napoleon', + 'sphinx.ext.doctest', +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'sonic_pde_tests' +copyright = u'2019, Broadcom' +author = u'Broadcom' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = u'0.0.1' +# The full version, including alpha/beta/rc tags. +release = u'0.0.1' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = [] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +#keep_warnings = False + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = False + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'alabaster' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +#html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Language to be used for generating the HTML full-text search index. +# Sphinx supports the following languages: +# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' +# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr' +#html_search_language = 'en' + +# A dictionary with options for the search language support, empty by default. +# Now only 'ja' uses this config value +#html_search_options = {'type': 'default'} + +# The name of a javascript file (relative to the configuration directory) that +# implements a search results scorer. If empty, the default will be used. +#html_search_scorer = 'scorer.js' + +# Output file base name for HTML help builder. +htmlhelp_basename = 'sonic_pde_testsdoc' + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', + +# Latex figure (float) alignment +#'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'sonic_pde_tests.tex', u'sonic\\_pde\\_tests Documentation', + u'Broadcom', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'sonic_pde_tests', u'sonic_pde_tests Documentation', + [author], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'sonic_pde_tests', u'sonic_pde_tests Documentation', + author, 'sonic_pde_tests', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +#texinfo_no_detailmenu = False + +# Napoleon settings +napoleon_google_docstring = True +napoleon_numpy_docstring = False +napoleon_include_init_with_doc = False +napoleon_include_private_with_doc = False +napoleon_include_special_with_doc = True +napoleon_use_admonition_for_examples = False +napoleon_use_admonition_for_notes = False +napoleon_use_admonition_for_references = False +napoleon_use_ivar = False +napoleon_use_param = True +napoleon_use_rtype = True diff --git a/sonic-pde-tests/docs/source/index.rst b/sonic-pde-tests/docs/source/index.rst new file mode 100644 index 0000000..9c2a79d --- /dev/null +++ b/sonic-pde-tests/docs/source/index.rst @@ -0,0 +1,22 @@ +.. sonic_pde_tests documentation master file, created by + sphinx-quickstart on Wed Jul 31 12:33:51 2019. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to sonic_pde_tests's documentation! +=========================================== + +Contents: + +.. toctree:: + :maxdepth: 2 + +.. include:: ../README.rst + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + diff --git a/sonic-pde-tests/docs/source/modules.rst b/sonic-pde-tests/docs/source/modules.rst new file mode 100644 index 0000000..9fa8dc9 --- /dev/null +++ b/sonic-pde-tests/docs/source/modules.rst @@ -0,0 +1,7 @@ +sonic_pde_tests +=============== + +.. toctree:: + :maxdepth: 4 + + sonic_pde_tests diff --git a/sonic-pde-tests/docs/source/sonic_pde_tests.rst b/sonic-pde-tests/docs/source/sonic_pde_tests.rst new file mode 100644 index 0000000..0baac08 --- /dev/null +++ b/sonic-pde-tests/docs/source/sonic_pde_tests.rst @@ -0,0 +1,134 @@ +sonic_pde_tests package +======================= + +Submodules +---------- + +sonic_pde_tests.conftest module +------------------------------- + +.. automodule:: sonic_pde_tests.conftest + :members: + :undoc-members: + :show-inheritance: + +sonic_pde_tests.test_bmc module +------------------------------- + +.. automodule:: sonic_pde_tests.test_bmc + :members: + :undoc-members: + :show-inheritance: + +sonic_pde_tests.test_config module +---------------------------------- + +.. automodule:: sonic_pde_tests.test_config + :members: + :undoc-members: + :show-inheritance: + +sonic_pde_tests.test_cpld module +-------------------------------- + +.. automodule:: sonic_pde_tests.test_cpld + :members: + :undoc-members: + :show-inheritance: + +sonic_pde_tests.test_eeprom module +---------------------------------- + +.. automodule:: sonic_pde_tests.test_eeprom + :members: + :undoc-members: + :show-inheritance: + +sonic_pde_tests.test_fan module +------------------------------- + +.. automodule:: sonic_pde_tests.test_fan + :members: + :undoc-members: + :show-inheritance: + +sonic_pde_tests.test_leds module +-------------------------------- + +.. automodule:: sonic_pde_tests.test_leds + :members: + :undoc-members: + :show-inheritance: + +sonic_pde_tests.test_os module +------------------------------ + +.. automodule:: sonic_pde_tests.test_os + :members: + :undoc-members: + :show-inheritance: + +sonic_pde_tests.test_platform module +------------------------------------ + +.. automodule:: sonic_pde_tests.test_platform + :members: + :undoc-members: + :show-inheritance: + +sonic_pde_tests.test_port module +-------------------------------- + +.. automodule:: sonic_pde_tests.test_port + :members: + :undoc-members: + :show-inheritance: + +sonic_pde_tests.test_psu module +------------------------------- + +.. automodule:: sonic_pde_tests.test_psu + :members: + :undoc-members: + :show-inheritance: + +sonic_pde_tests.test_rtc module +------------------------------- + +.. automodule:: sonic_pde_tests.test_rtc + :members: + :undoc-members: + :show-inheritance: + +sonic_pde_tests.test_sfp module +------------------------------- + +.. automodule:: sonic_pde_tests.test_sfp + :members: + :undoc-members: + :show-inheritance: + +sonic_pde_tests.test_thermal module +----------------------------------- + +.. automodule:: sonic_pde_tests.test_thermal + :members: + :undoc-members: + :show-inheritance: + +sonic_pde_tests.test_usb module +------------------------------- + +.. automodule:: sonic_pde_tests.test_usb + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: sonic_pde_tests + :members: + :undoc-members: + :show-inheritance: diff --git a/sonic-pde-tests/setup.cfg b/sonic-pde-tests/setup.cfg new file mode 100644 index 0000000..e69de29 diff --git a/sonic-pde-tests/setup.py b/sonic-pde-tests/setup.py new file mode 100644 index 0000000..c95dce7 --- /dev/null +++ b/sonic-pde-tests/setup.py @@ -0,0 +1,38 @@ +# https://github.com/ninjaaron/fast-entry_points +# workaround for slow 'pkg_resources' import +# +# NOTE: this only has effect on console_scripts and no speed-up for commands +# under scripts/. Consider stop using scripts and use console_scripts instead +# +# https://stackoverflow.com/questions/18787036/difference-between-entry-points-console-scripts-and-scripts-in-setup-py +try: + import fastentrypoints +except ImportError: + from setuptools.command import easy_install + import pkg_resources + easy_install.main(['fastentrypoints']) + pkg_resources.require('fastentrypoints') + import fastentrypoints + +import glob +from setuptools import setup + +setup( + name='sonic_pde_tests', + version='1.0', + description='PDE pytest runtime utilities for SONiC', + license='Apache 2.0', + author='Broadcom SONiC Team', + packages=[ + 'sonic_pde_tests', + 'sonic_pde_saiut', + ], + package_data={ + 'sonic_pde_tests': ['data/platform/*.json','data/template/*.json'], + 'sonic_pde_saiut': ['*.so'], + }, + tests_require = [ + 'pytest' + ], + keywords='sonic PDE utilities', +) diff --git a/sonic-pde-tests/sonic_pde_saiut/.gitignore b/sonic-pde-tests/sonic_pde_saiut/.gitignore new file mode 100644 index 0000000..d04aa85 --- /dev/null +++ b/sonic-pde-tests/sonic_pde_saiut/.gitignore @@ -0,0 +1,3 @@ +/.inc/ +/saiut.py +/saiut_wrap.c diff --git a/sonic-pde-tests/sonic_pde_saiut/Makefile b/sonic-pde-tests/sonic_pde_saiut/Makefile new file mode 100644 index 0000000..06c6c9a --- /dev/null +++ b/sonic-pde-tests/sonic_pde_saiut/Makefile @@ -0,0 +1,26 @@ +SAI_INC := /usr/include/sai +SAI_LIB := /usr/lib + +CC := gcc +CFLAGS := -fPIC -I/usr/include/python2.7 -I$(SAI_INC) +LDFLAGS := -L$(SAI_LIB) -lsai + +all: _saiut.so + +setup: + rm -rf .inc + mkdir -p .inc + ln -s $(SAI_INC)/saitypes.h .inc/ + ln -s $(SAI_INC)/saistatus.h .inc/ + ln -s $(SAI_INC)/saiport.h .inc/ + +saiut_wrap.c: setup saiut.i + swig -python saiut.i + +saiut_wrap.o: saiut_wrap.c + +_saiut.so: saiut.o saiut_wrap.o + gcc -shared $^ $(LDFLAGS) -o $@ + +clean: + rm -rf *.so *.o *_wrap.c saiut.py saiut.pyc .inc/ diff --git a/sonic-pde-tests/sonic_pde_saiut/__init__.py b/sonic-pde-tests/sonic_pde_saiut/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/sonic-pde-tests/sonic_pde_saiut/saiut.c b/sonic-pde-tests/sonic_pde_saiut/saiut.c new file mode 100644 index 0000000..4cc2be2 --- /dev/null +++ b/sonic-pde-tests/sonic_pde_saiut/saiut.c @@ -0,0 +1,610 @@ +/********************************************************************** + * Copyright 2019 Broadcom. All rights reserved. + * The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. + **********************************************************************/ +#include +#include +#include +#include +#include +#include + +#define _SAI_API_ID_MIN (SAI_API_UNSPECIFIED + 1) +#define _SAI_API_ID_MAX SAI_API_BRIDGE +#define _SAI_MAX_PORTS 512 /* max. number of front panel ports */ +#define _SAI_PROFILE_MAX_KVPS 64 /* max. number of KVP */ +#define COUNTOF(x) (sizeof(x) / sizeof((x)[0])) +#define TRUE 1 +#define FALSE 0 + +static int sdk_pfc_dl_recovery = 0; +static int pfc_deadlock_detect_event = 0; +static int pfc_deadlock_recover_event = 0; + +sai_object_id_t g_switch_id = 0; + +void *g_switch_apis[_SAI_API_ID_MAX + 1]; + +/* + * SAI: front port list + * BCM: logical port list + */ +sai_object_id_t g_switch_ports[_SAI_MAX_PORTS]; + +/* + * SAI: Mapping port to lane + * BCM: Mapping logical port to physical port + */ +uint32_t g_switch_l2p[_SAI_MAX_PORTS]; + +/* + * SAI: Mapping lane to port + * BCM: Mapping physical port to logical port + */ +sai_object_id_t g_switch_p2l[_SAI_MAX_PORTS]; + +typedef struct _profile_kvp_s +{ + char *key; + char *val; +} profile_kvp_t; + +static profile_kvp_t profile_kvps[_SAI_PROFILE_MAX_KVPS]; + +/** + * skip_spaces - Removes leading whitespace from @str. + * @str: The string to be stripped. + * + * Returns a pointer to the first non-whitespace character in @str. + */ +static char *skip_spaces(const char *str) +{ + while (isspace(*str)) + { + ++str; + } + return (char *)str; +} + +/** + * strim - Removes leading and trailing whitespace from @s. + * @s: The string to be stripped. + * + * Note that the first trailing whitespace is replaced with a %NUL-terminator + * in the given string @s. Returns a pointer to the first non-whitespace + * character in @s. + */ +static char *strim(char *s) +{ + size_t size; + char *end; + + s = skip_spaces(s); + size = strlen(s); + if (!size) + { + return s; + } + + end = s + size - 1; + while (end >= s && isspace(*end)) + { + end--; + } + *(end + 1) = '\0'; + + return s; +} + +static int _profile_reload(const char *filename) +{ + FILE *fp = NULL; + char buf[256] = { 0 }; + char *ptr = NULL, *key = NULL, *val = NULL; + unsigned int idx = 0; + + fp = fopen(filename, "r"); + if (!fp) + { + printf("Unable to open '%s'\n", filename); + return -1; + } + + while (fgets(buf, sizeof(buf) - 1, fp)) + { + /* skip comments */ + ptr = strchr(buf, '#'); + if (ptr) + { + *ptr = 0; + } + + /* skip empty lines */ + ptr = strim(buf); + if (ptr[0] == 0) + { + continue; + } + + key = ptr; + val = strchr(key, '='); + if (val == NULL) + { + continue; + } + *(val++) = 0; + + if (profile_kvps[idx].key) + { + free(profile_kvps[idx].key); + } + profile_kvps[idx].key = strdup(key); + + if (profile_kvps[idx].val) + { + free(profile_kvps[idx].val); + } + profile_kvps[idx].val = strdup(val); + + ++idx; + } + + fclose(fp); +} + +/* + * Get variable value given its name + */ +static const char *_profile_get_value(sai_switch_profile_id_t id, + const char *key) +{ + int i; + + if (id != 0) + { + return NULL; + } + + for (i = 0; profile_kvps[i].key; ++i) + { + if (0 == strcmp(key, profile_kvps[i].key)) + { + return profile_kvps[i].val; + } + } + return NULL; +} + +/* + * Enumerate all the K/V pairs in a profile. + * Pointer to NULL passed as variable restarts enumeration. + * Function returns 0 if next value exists, -1 at the end of the list. + */ +static int _profile_get_next_value(sai_switch_profile_id_t id, + const char **key, + const char **value) +{ + static int index = 0; + + if (id != 0) + { + return -1; + } + + /* enumeration reset */ + if (NULL == *key) + { + index = 0; + return 0; + } + + if (NULL == profile_kvps[index].key) + { + return -1; + } + + *key = profile_kvps[index].key; + if (NULL != value) + { + *value = profile_kvps[index].val; + } + + return profile_kvps[++index].key ? 0 : -1; +} + +static sai_service_method_table_t saiut_services = +{ + .profile_get_value = _profile_get_value, + .profile_get_next_value = _profile_get_next_value +}; + +/* + * Routine Description: + * Switch oper state change notification + * + * Arguments: + * [in] switch_oper_status - new switch oper state + * + * Return Values: + * None + */ +static void _switch_state_change_event(sai_object_id_t switch_id, + sai_switch_oper_status_t status) +{ + printf("\n----Host received switch status event: %d from switch: 0x%lx\n", + status, switch_id); +} + +/* + * Routine Description: + * FDB notifications + * + * Arguments: + * [in] count - number of notifications + * [in] data - pointer to fdb event notification data array + * + * Return Values: + * None + */ +void _switch_fdb_event(uint32_t count, + sai_fdb_event_notification_data_t *data) +{ + /* skipped */ +} + +/* + * Routine Description: + * Port state change notification + * Passed as a parameter into sai_initialize_switch() + * + * Arguments: + * [in] count - number of notifications + * [in] data - array of port operational status + * + * Return Values: + * None + */ +void _switch_port_state_change_event(uint32_t count, + sai_port_oper_status_notification_t *data) +{ + printf("\n----Host received port link status event on port %3d: %s\n", + (int)(data->port_id), + (SAI_PORT_OPER_STATUS_UP == data->port_state) ? " UP" : "DOWN"); +} + +/* + * Routine Description: + * PFC event notifications + * + * Arguments: + * [in] count - number of notifications + * [in] data - pointer to pfc event notification data + * + * Return Values: + * None + */ +void _switch_queue_pfc_deadlock_event(uint32_t count, + sai_queue_deadlock_notification_data_t *data) +{ + switch (data->event) + { + case SAI_QUEUE_PFC_DEADLOCK_EVENT_TYPE_DETECTED: + printf("Deadlock detected on queue id %d count number is %d\n", + (int)(data->queue_id), count); + pfc_deadlock_detect_event++; + break; + + case SAI_QUEUE_PFC_DEADLOCK_EVENT_TYPE_RECOVERED: + printf("Deadlock recovered on queue id %d count number is %d\n", + (int)(data->queue_id), count); + pfc_deadlock_recover_event++; + break; + + default: + printf("Unknown deadlock event on queue id %d count number is %d\n", + (int)(data->queue_id), count); + break; + } + + if (!sdk_pfc_dl_recovery) + { + /* Should not return true if we want to have sdk based pfc dl recovery */ + data->app_managed_recovery = TRUE; + } +} + +static sai_attribute_t saiut_attr[] = +{ + { SAI_SWITCH_ATTR_INIT_SWITCH, .value.booldata = TRUE }, + { SAI_SWITCH_ATTR_SWITCH_PROFILE_ID, .value.u32 = 0 }, + { SAI_SWITCH_ATTR_SWITCH_STATE_CHANGE_NOTIFY, .value.ptr = _switch_state_change_event }, + { SAI_SWITCH_ATTR_FDB_EVENT_NOTIFY, .value.ptr = _switch_fdb_event }, + { SAI_SWITCH_ATTR_PORT_STATE_CHANGE_NOTIFY, .value.ptr = _switch_port_state_change_event }, + { SAI_SWITCH_ATTR_QUEUE_PFC_DEADLOCK_NOTIFY, .value.ptr = _switch_queue_pfc_deadlock_event }, + { SAI_SWITCH_ATTR_SRC_MAC_ADDRESS, .value.mac = { 0x00, 0x05, 0x06, 0x08, 0x05, 0x00 } }, +}; + +sai_status_t portGetAttribute(sai_object_id_t port, sai_attribute_t *attr) +{ + sai_port_api_t *apis = g_switch_apis[SAI_API_PORT]; + + if (g_switch_id == 0) + { + return SAI_STATUS_FAILURE; + } + return apis->get_port_attribute(port, 1, attr); +} + +sai_status_t portSetAttribute(sai_object_id_t port, sai_attribute_t *attr) +{ + sai_port_api_t *apis = g_switch_apis[SAI_API_PORT]; + + if (g_switch_id == 0) + { + return SAI_STATUS_FAILURE; + } + return apis->set_port_attribute(port, attr); +} + +sai_object_id_t portGetId(uint32_t lane) +{ + return (lane < COUNTOF(g_switch_p2l)) ? g_switch_p2l[lane] : 0; +} + +bool portGetAdminState(sai_object_id_t port) +{ + sai_attribute_t attr; + + if (port > 0) + { + attr.id = SAI_PORT_ATTR_ADMIN_STATE; + attr.value.booldata = FALSE; + if (SAI_STATUS_SUCCESS == portGetAttribute(port, &attr)) + { + return attr.value.booldata; + } + } + return FALSE; +} + +sai_status_t portSetAdminState(sai_object_id_t port, bool enable) +{ + sai_attribute_t attr; + + if (port > 0) + { + attr.id = SAI_PORT_ATTR_ADMIN_STATE; + attr.value.booldata = enable; + return portSetAttribute(port, &attr); + } + return SAI_STATUS_FAILURE; +} + +uint32_t portGetSpeed(sai_object_id_t port) +{ + sai_attribute_t attr; + + if (port > 0) + { + attr.id = SAI_PORT_ATTR_SPEED; + attr.value.u32 = 0; + if (SAI_STATUS_SUCCESS == portGetAttribute(port, &attr)) + { + return attr.value.u32; + } + } + return 0; +} + +sai_status_t portSetSpeed(sai_object_id_t port, uint32_t speed) +{ + sai_attribute_t attr; + + if (port > 0) + { + attr.id = SAI_PORT_ATTR_SPEED; + attr.value.u32 = 0; + return portSetAttribute(port, &attr); + } + return SAI_STATUS_FAILURE; +} + +uint64_t portGetCounter(sai_object_id_t port, sai_stat_id_t id) +{ + sai_port_api_t *apis = g_switch_apis[SAI_API_PORT]; + uint64_t counter = 0; + + if ((g_switch_id == 0) || (apis == NULL)) + { + return 0; + } + + if (SAI_STATUS_SUCCESS != apis->get_port_stats(port, 1, &id, &counter)) + { + counter = 0; + printf("port %d: unable to get counter\n", (int)port); + } + return counter; +} + +sai_status_t portClearCounter(sai_object_id_t port, sai_stat_id_t id) +{ + sai_port_api_t *apis = g_switch_apis[SAI_API_PORT]; + + if ((g_switch_id == 0) || (apis == NULL)) + { + return SAI_STATUS_FAILURE; + } + return apis->clear_port_stats(port, 1, &id); +} + +sai_status_t switchGetAttribute(sai_attribute_t *attr) +{ + sai_switch_api_t *apis = g_switch_apis[SAI_API_SWITCH]; + + if (g_switch_id == 0) + { + return SAI_STATUS_FAILURE; + } + return apis->get_switch_attribute(g_switch_id, 1, attr); +} + +sai_status_t switchSetAttribute(sai_attribute_t *attr) +{ + sai_switch_api_t *apis = g_switch_apis[SAI_API_SWITCH]; + + if (g_switch_id == 0) + { + return SAI_STATUS_FAILURE; + } + return apis->set_switch_attribute(g_switch_id, attr); +} + +uint32_t switchGetPortNumber(void) +{ + sai_status_t rv = SAI_STATUS_FAILURE; + sai_attribute_t attr; + + attr.id = SAI_SWITCH_ATTR_PORT_NUMBER; + attr.value.u32 = 0; + + rv = switchGetAttribute(&attr); + if (SAI_STATUS_SUCCESS != rv) + { + printf("Unable to get port number\n"); + return 0; + } + return (uint32_t)attr.value.u32; +} + +sai_status_t switchShell(bool enable) +{ + sai_attribute_t attr; + sai_status_t rv = SAI_STATUS_FAILURE; + + if (enable) + { + attr.id = SAI_SWITCH_ATTR_SWITCH_SHELL_ENABLE; + attr.value.booldata = TRUE; + rv = switchSetAttribute(&attr); + } + return rv; +} + +sai_status_t switchInitialize(const char *mac) +{ + sai_status_t rv = SAI_STATUS_FAILURE; + sai_switch_api_t *sai_switch_apis = NULL; + sai_object_list_t list; + sai_attribute_t attr; + uint32_t i, lanes[32]; + + if (0 != _profile_reload("/usr/share/sonic/hwsku/sai.profile")) + { + profile_kvps[0].key = SAI_KEY_INIT_CONFIG_FILE; + profile_kvps[0].val = "./config.bcm"; + } + + /* Initialize SAI library core */ + rv = sai_api_initialize(0, &saiut_services); + if (SAI_STATUS_SUCCESS != rv) + { + printf("Unable to initialize SAI library\n"); + return rv; + } + + /* Initialize SAI API function pointers */ + for (i = _SAI_API_ID_MIN; i <= _SAI_API_ID_MAX; i++) + { + rv = sai_api_query(i, &g_switch_apis[i]); + if (SAI_STATUS_SUCCESS != rv) + { + printf("API %u is not available\n", i); + } + } + + /* Create the switch instance */ + sai_switch_apis = g_switch_apis[SAI_API_SWITCH]; + rv = sai_switch_apis->create_switch(&g_switch_id, COUNTOF(saiut_attr), + saiut_attr); + if (SAI_STATUS_SUCCESS != rv) + { + printf("Unable to created switch\n"); + return rv; + } + printf("Created switch: 0x%lx, port number: %d\n", + g_switch_id, switchGetPortNumber()); + + /* Initialize the switch port list and maps */ + list.count = _SAI_MAX_PORTS; + list.list = g_switch_ports; + attr.id = SAI_SWITCH_ATTR_PORT_LIST; + attr.value.objlist = list; + rv = switchGetAttribute(&attr); + if (SAI_STATUS_SUCCESS != rv) + { + printf("Unable to get switch port list\n"); + return rv; + } + if (g_switch_ports[0] == 0) + { + printf("None of valid port is available on the switch?\n"); + return SAI_STATUS_FAILURE; + } + for (i = 0; i < _SAI_MAX_PORTS; ++i) + { + if (g_switch_ports[i] == 0) + { + break; + } + attr.id = SAI_PORT_ATTR_HW_LANE_LIST; + attr.value.u32list.count = COUNTOF(lanes); + attr.value.u32list.list = lanes; + rv = portGetAttribute(g_switch_ports[i], &attr); + if (SAI_STATUS_SUCCESS != rv) + { + printf("Unable to get lane list of port %d\n", + (int)g_switch_ports[i]); + return rv; + } + /* logical port to physical port */ + g_switch_l2p[g_switch_ports[i] & 0x1ff] = lanes[0]; + g_switch_p2l[lanes[0]] = g_switch_ports[i]; + } + + return SAI_STATUS_SUCCESS; +} + +sai_status_t switchShutdown(void) +{ + sai_status_t ret = SAI_STATUS_SUCCESS; + sai_switch_api_t *apis = g_switch_apis[SAI_API_SWITCH]; + + if (g_switch_id) + { + ret = apis->remove_switch(g_switch_id); + g_switch_id = 0; + } + return ret; +} + +extern int sai_driver_process_command(char *cmd); +sai_status_t bcmDiagCommand(char *cmd) +{ + int rv; + + rv = sai_driver_process_command(cmd); + return (rv == 0) ? SAI_STATUS_SUCCESS : SAI_STATUS_FAILURE; +} + +extern char *bcm_port_name(int unit, int port); +sai_status_t bcmSendPackets(sai_object_id_t port, uint32_t num, uint32_t len) +{ + char cmd[128]; + + num = (num == 0) ? 1 : num; + len = (len == 0) ? 68 : len; + sprintf(cmd, "tx %u pbm=%s L=%d", num, + bcm_port_name(0, (uint32_t)port), len); + return bcmDiagCommand(cmd); +} diff --git a/sonic-pde-tests/sonic_pde_saiut/saiut.h b/sonic-pde-tests/sonic_pde_saiut/saiut.h new file mode 100644 index 0000000..3a074ba --- /dev/null +++ b/sonic-pde-tests/sonic_pde_saiut/saiut.h @@ -0,0 +1,25 @@ +/********************************************************************** + * Copyright 2019 Broadcom. All rights reserved. + * The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. + **********************************************************************/ +#ifndef _SAIUT_H +#define _SAIUT_H + +sai_object_id_t portGetId(uint32_t lane); +bool portGetAdminState(sai_object_id_t port); +sai_status_t portSetAdminState(sai_object_id_t port, bool enable); +uint32_t portGetSpeed(sai_object_id_t port); +sai_status_t portSetSpeed(sai_object_id_t port, uint32_t speed); +uint64_t portGetCounter(sai_object_id_t port, sai_stat_id_t id); +sai_status_t portClearCounter(sai_object_id_t port, sai_stat_id_t id); + +uint32_t switchGetPortNumber(void); +sai_status_t switchShell(bool enable); +sai_status_t switchInitialize(const char *mac); +sai_status_t switchShutdown(void); + +/* Broadcom SAI */ +sai_status_t bcmDiagCommand(char *cmd); +sai_status_t bcmSendPackets(sai_object_id_t port, uint32_t num, uint32_t len); + +#endif diff --git a/sonic-pde-tests/sonic_pde_saiut/saiut.i b/sonic-pde-tests/sonic_pde_saiut/saiut.i new file mode 100644 index 0000000..ce993d2 --- /dev/null +++ b/sonic-pde-tests/sonic_pde_saiut/saiut.i @@ -0,0 +1,16 @@ +%module saiut + +%define NO_RET_TYPE +%enddef + +%include + +%{ +#include +#include "saiut.h" +%} + +%include ".inc/saitypes.h" +%include ".inc/saistatus.h" +%include ".inc/saiport.h" +%include "saiut.h" diff --git a/sonic-pde-tests/sonic_pde_tests/__init__.py b/sonic-pde-tests/sonic_pde_tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/sonic-pde-tests/sonic_pde_tests/conftest.py b/sonic-pde-tests/sonic_pde_tests/conftest.py new file mode 100644 index 0000000..d552a82 --- /dev/null +++ b/sonic-pde-tests/sonic_pde_tests/conftest.py @@ -0,0 +1,95 @@ +import os +import pytest +import json +import subprocess + +def pytest_configure(config): + config.addinivalue_line("markers", "semiauto: this marks test will run in semiauto mode.") + +def pytest_addoption(parser): + parser.addoption( + "--semiauto", action="store_true", default=False, help="run semiautomated tests") + +def pytest_collection_modifyitems(config,items): + if config.getoption("--semiauto"): + return + skip_semiauto = pytest.mark.skip(reason="need --semiauto option to run") + for item in items: + if "semiauto" in item.keywords: + item.add_marker(skip_semiauto) + +# Get platform name from ONIE +def get_onie_pname(): + cmd = "cat /host/machine.conf | grep onie_platform | cut -d '=' -f 2" + pin = subprocess.Popen(cmd, + shell=True, + close_fds=True, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + id = pin.communicate()[0] + id = id.strip() + return id + +# Copy template platform config JSON to targeted platform JSON +def create_platform_json(Pfname): + INPUT_DIR = os.path.dirname(os.path.abspath(__file__)) + tname = os.path.join(INPUT_DIR, 'data/template/platform-config.json') + cmd = "cp "+tname+" "+Pfname + subprocess.Popen(cmd, + shell=True, + close_fds=True, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + +# Copy template platform test JSON to targeted platform JSON +def create_test_json(Tfname): + INPUT_DIR = os.path.dirname(os.path.abspath(__file__)) + tname = os.path.join(INPUT_DIR, 'data/template/test-config.json') + cmd = "cp "+tname+" "+Tfname + subprocess.Popen(cmd, + shell=True, + close_fds=True, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + +def pytest_runtest_setup(item): + INPUT_DIR = os.path.dirname(os.path.abspath(__file__)) + Pfname = os.path.join(INPUT_DIR, 'data/platform', "platform-" + get_onie_pname() + "-config.json") + Tfname = os.path.join(INPUT_DIR, 'data/platform', "test-" + get_onie_pname() + "-config.json") + if os.path.isfile(Pfname): + return + else: + create_platform_json(Pfname) + if os.path.isfile(Tfname): + return + else: + create_test_json(Tfname) + +@pytest.fixture(scope='function',autouse='True') +def json_config_data(): + """ Loads json file """ + INPUT_DIR = os.path.dirname(os.path.abspath(__file__)) + fname = os.path.join(INPUT_DIR, 'data/platform', "platform-" + get_onie_pname() + "-config.json") + try: + with open('/home/pde/platform-config.json') as file_object: + contents=json.load(file_object) + except: + with open(fname) as file_object: + contents=json.load(file_object) + + return contents + +@pytest.fixture(scope='function',autouse='True') +def json_test_data(): + """ Loads json file """ + INPUT_DIR = os.path.dirname(os.path.abspath(__file__)) + fname = os.path.join(INPUT_DIR, 'data/platform', "test-" + get_onie_pname() + "-config.json") + try: + with open('/home/pde/test-config.json') as file_object: + contents=json.load(file_object) + except: + with open(fname) as file_object: + contents=json.load(file_object) + + return contents + diff --git a/sonic-pde-tests/sonic_pde_tests/data/platform/platform-x86_64-accton_as7312_54x-r0-config.json b/sonic-pde-tests/sonic_pde_tests/data/platform/platform-x86_64-accton_as7312_54x-r0-config.json new file mode 100644 index 0000000..1373a4e --- /dev/null +++ b/sonic-pde-tests/sonic_pde_tests/data/platform/platform-x86_64-accton_as7312_54x-r0-config.json @@ -0,0 +1,91 @@ +{ + "PLATFORM": { + "num_psus": 2, + "num_cplds": 3, + "num_syseeproms": 1, + "num_fans": 6, + "num_ports": 54, + "num_sfps": 6, + "num_temps": 3, + "num_serviceports": 1, + "serviceport": "eth0", + "thermal_policy_support": "true", + "modules" : { + "FAN": { + "support" : "true", + "path": "as7312_54x", + "name": "fanutil", + "class": "FanUtil" + }, + "TEMP": { + "support" : "true", + "path": "as7312_54x", + "name": "thermalutil", + "class": "ThermalUtil" + }, + "CPLD": { + "support": "false" + }, + "SYSLED": { + "support": "false" + } + }, + "drivers": { + "CPLD": { + "driver_info": { + "support": "true", + "type": "ODM", + "name": "accton_i2c_cpld" + } + }, + "PSU": { + "driver_info": { + "support": "true", + "type": "ODM", + "name": "accton_as7312_54x_psu" + } + }, + "FAN": { + "driver_info": { + "support": "true", + "type": "ODM", + "name": "accton_as7312_54x_fan" + } + }, + "SFP": { + "driver_info": { + "support": "false" + } + }, + "TEMP": { + "driver_info": { + "support": "true", + "type": "GENERIC", + "name": "lm75" + } + }, + "SYSLED": { + "driver_info": { + "support": "true", + "type": "ODM", + "name": "accton_as7312_54x_leds" + } + }, + "EEPROM": { + "driver_info": { + "support": "true", + "type": "GENERIC", + "name": "at24" + } + }, + "MAC": { + "driver_info": { + "support": "true", + "type": "GENERIC", + "name": "igb" + } + } + } + } +} + diff --git a/sonic-pde-tests/sonic_pde_tests/data/platform/platform-x86_64-accton_as7326_56x-r0-config.json b/sonic-pde-tests/sonic_pde_tests/data/platform/platform-x86_64-accton_as7326_56x-r0-config.json new file mode 100644 index 0000000..64b9f8a --- /dev/null +++ b/sonic-pde-tests/sonic_pde_tests/data/platform/platform-x86_64-accton_as7326_56x-r0-config.json @@ -0,0 +1,87 @@ +{ + "PLATFORM": { + "num_psus": 2, + "num_cplds": 3, + "num_syseeproms": 1, + "num_fans": 6, + "num_ports": 54, + "num_sfps": 6, + "num_temps": 6, + "num_serviceports": 1, + "serviceport": "eth0", + "thermal_policy_support": "true", + "modules" : { + "FAN": { + "support": "true" + }, + "TEMP": { + "support": "true" + }, + "CPLD": { + "support": "false" + }, + "SYSLED": { + "support": "false" + }, + "PSU": { + "support": "true" + } + }, + "drivers": { + "CPLD": { + "driver_info": { + "support": "true", + "type": "ODM", + "name": "accton_i2c_cpld" + } + }, + "SFP": { + "driver_info": { + "support": "false" + } + }, + "PSU": { + "driver_info": { + "support": "false" + } + }, + "FAN": { + "driver_info": { + "support": "false" + } + }, + "SFP": { + "driver_info": { + "support": "false" + } + }, + "TEMP": { + "driver_info": { + "support": "false" + } + }, + "SYSLED": { + "driver_info": { + "support": "true", + "type": "ODM", + "name": "accton_as7326_56x_leds" + } + }, + "EEPROM": { + "driver_info": { + "support": "true", + "type": "GENERIC", + "name": "at24" + } + }, + "MAC": { + "driver_info": { + "support": "true", + "type": "GENERIC", + "name": "tg3" + } + } + } + } +} + diff --git a/sonic-pde-tests/sonic_pde_tests/data/platform/platform-x86_64-accton_as7712_32x-r0-config.json b/sonic-pde-tests/sonic_pde_tests/data/platform/platform-x86_64-accton_as7712_32x-r0-config.json new file mode 100644 index 0000000..b52c84d --- /dev/null +++ b/sonic-pde-tests/sonic_pde_tests/data/platform/platform-x86_64-accton_as7712_32x-r0-config.json @@ -0,0 +1,90 @@ +{ + "PLATFORM": { + "num_psus": 2, + "num_cplds": 3, + "num_syseeproms": 1, + "num_fans": 6, + "num_ports": 32, + "num_sfps": 32, + "num_temps": 3, + "num_serviceports": 1, + "serviceport": "eth0", + "modules" : { + "FAN": { + "support" : "true", + "path": "as7312_54x", + "name": "fanutil", + "class": "FanUtil" + }, + "TEMP": { + "support" : "true", + "path": "as7312_54x", + "name": "thermalutil", + "class": "ThermalUtil" + }, + "CPLD": { + "support": "false" + }, + "SYSLED": { + "support": "false" + } + }, + "drivers": { + "CPLD": { + "driver_info": { + "support": "true", + "type": "ODM", + "name": "accton_i2c_cpld" + } + }, + "PSU": { + "driver_info": { + "support": "true", + "type": "ODM", + "name": "accton_as7712_32x_psu" + } + }, + "FAN": { + "driver_info": { + "support": "true", + "type": "ODM", + "name": "accton_as7712_32x_fan" + } + }, + "SFP": { + "driver_info": { + "support": "false" + } + }, + "TEMP": { + "driver_info": { + "support": "true", + "type": "GENERIC", + "name": "lm75" + } + }, + "SYSLED": { + "driver_info": { + "support": "true", + "type": "ODM", + "name": "leds_accton_as7712_32x" + } + }, + "EEPROM": { + "driver_info": { + "support": "true", + "type": "GENERIC", + "name": "at24" + } + }, + "MAC": { + "driver_info": { + "support": "true", + "type": "GENERIC", + "name": "igb" + } + } + } + } +} + diff --git a/sonic-pde-tests/sonic_pde_tests/data/platform/platform-x86_64-accton_as7726_32x-r0-config.json b/sonic-pde-tests/sonic_pde_tests/data/platform/platform-x86_64-accton_as7726_32x-r0-config.json new file mode 100644 index 0000000..5bb50c0 --- /dev/null +++ b/sonic-pde-tests/sonic_pde_tests/data/platform/platform-x86_64-accton_as7726_32x-r0-config.json @@ -0,0 +1,94 @@ +{ + "PLATFORM": { + "num_psus": 2, + "num_cplds": 3, + "num_syseeproms": 1, + "num_fans": 6, + "num_ports": 32, + "num_sfps": 34, + "num_temps": 5, + "num_serviceports": 1, + "serviceport": "eth0", + "thermal_policy_support": "false", + "modules" : { + "FAN": { + "support" : "true", + "path": "as7726_32x", + "name": "fanutil", + "class": "FanUtil" + }, + "TEMP": { + "support" : "true", + "path": "as7726_32x", + "name": "thermalutil", + "class": "ThermalUtil" + }, + "CPLD": { + "support": "false" + }, + "PSU": { + "support": "true" + }, + "SYSLED": { + "support": "false" + } + }, + "drivers": { + "CPLD": { + "driver_info": { + "support": "true", + "type": "ODM", + "name": "accton_as7726_32x_cpld" + } + }, + "PSU": { + "driver_info": { + "support": "true", + "type": "ODM", + "name": "accton_as7726_32x_psu" + } + }, + "FAN": { + "driver_info": { + "support": "true", + "type": "ODM", + "name": "accton_as7726_32x_fan" + } + }, + "SFP": { + "driver_info": { + "support": "false" + } + }, + "TEMP": { + "driver_info": { + "support": "true", + "type": "GENERIC", + "name": "lm75" + } + }, + "SYSLED": { + "driver_info": { + "support": "true", + "type": "ODM", + "name": "accton_as7726_32x_leds" + } + }, + "EEPROM": { + "driver_info": { + "support": "true", + "type": "GENERIC", + "name": "at24" + } + }, + "MAC": { + "driver_info": { + "support": "true", + "type": "GENERIC", + "name": "tg3" + } + } + } + } +} + diff --git a/sonic-pde-tests/sonic_pde_tests/data/platform/platform-x86_64-accton_as7816_64x-r0-config.json b/sonic-pde-tests/sonic_pde_tests/data/platform/platform-x86_64-accton_as7816_64x-r0-config.json new file mode 100644 index 0000000..ff5939a --- /dev/null +++ b/sonic-pde-tests/sonic_pde_tests/data/platform/platform-x86_64-accton_as7816_64x-r0-config.json @@ -0,0 +1,98 @@ +{ + "PLATFORM": { + "num_psus": 2, + "num_cplds": 2, + "num_syseeproms": 1, + "num_fans": 4, + "num_ports": 54, + "num_sfps": 64, + "num_temps": 6, + "num_serviceports": 1, + "serviceport": "eth0", + "modules" : { + "FAN": { + "support": "true", + "path": "as7816_64x", + "name": "fanutil.py", + "class": "FanUtil" + }, + "TEMP": { + "support": "true", + "path": "as7816_64x", + "name": "thermalutil", + "class": "ThermalUtil" + }, + "CPLD": { + "support": "true", + "path": "as7816_64x", + "name": "cpldutil", + "class" : "CpldUtil" + }, + "SYSLED": { + "support": "true", + "path": "as7816_64x", + "name": "ledutil", + "class": "LedUtil" + } + }, + "drivers": { + "CPLD": { + "driver_info": { + "support": "true", + "type": "ODM", + "name": "accton_i2c_cpld" + } + }, + "PSU": { + "driver_info": { + "support": "true", + "type": "ODM", + "name": "as7816_64x_psu" + } + }, + "FAN": { + "driver_info": { + "support": "true", + "type": "ODM", + "name": "as7816_64x_fan" + } + }, + "SFP": { + "driver_info": { + "support": "true", + "type": "ODM", + "name": "as7816_64x_sfp" + } + }, + "TEMP": { + "driver_info": { + "support": "true", + "type": "GENERIC", + "name": "lm75" + } + }, + "SYSLED": { + "driver_info": { + "support": "true", + "type": "ODM", + "name": "as7816_64x_leds" + } + }, + "EEPROM": { + "driver_info": { + "support": "true", + "type": "GENERIC", + "name": "at24" + } + }, + "MAC": { + "driver_info": { + "support": "true", + "type": "GENERIC", + "name": "igb" + } + } + } + } +} + diff --git a/sonic-pde-tests/sonic_pde_tests/data/platform/platform-x86_64-quanta_ix8_rglbmc-r0-config.json b/sonic-pde-tests/sonic_pde_tests/data/platform/platform-x86_64-quanta_ix8_rglbmc-r0-config.json new file mode 100644 index 0000000..0a89d53 --- /dev/null +++ b/sonic-pde-tests/sonic_pde_tests/data/platform/platform-x86_64-quanta_ix8_rglbmc-r0-config.json @@ -0,0 +1,82 @@ +{ + "PLATFORM": { + "num_psus": 2, + "num_cplds": 0, + "num_syseeproms": 1, + "num_fans": 0, + "num_ports": 56, + "num_sfps": 56, + "num_temps": 0, + "num_serviceports": 1, + "serviceport": "eth0", + "thermal_policy_support": "false", + "modules" : { + "FAN": { + "support": "false" + }, + "TEMP": { + "support": "false" + }, + "CPLD": { + "support": "false" + }, + "SYSLED": { + "support": "false" + }, + "PSU": { + "support": "false" + } + }, + "drivers": { + "CPLD": { + "driver_info": { + "support": "true", + "type": "ODM", + "name": "qci_platform_ix8" + } + }, + "PSU": { + "driver_info": { + "support": "false" + } + }, + "FAN": { + "driver_info": { + "support": "false" + } + }, + "SFP": { + "driver_info": { + "support": "false" + } + }, + "TEMP": { + "driver_info": { + "support": "false" + } + }, + "SYSLED": { + "driver_info": { + "support": "true", + "type": "ODM", + "name": "qci_cpld_led" + } + }, + "EEPROM": { + "driver_info": { + "support": "true", + "type": "GENERIC", + "name": "at24" + } + }, + "MAC": { + "driver_info": { + "support": "true", + "type": "GENERIC", + "name": "igb" + } + } + } + } +} + diff --git a/sonic-pde-tests/sonic_pde_tests/data/platform/platform-x86_64-quanta_ix9_bwde-r0-config.json b/sonic-pde-tests/sonic_pde_tests/data/platform/platform-x86_64-quanta_ix9_bwde-r0-config.json new file mode 100644 index 0000000..f047d1a --- /dev/null +++ b/sonic-pde-tests/sonic_pde_tests/data/platform/platform-x86_64-quanta_ix9_bwde-r0-config.json @@ -0,0 +1,81 @@ +{ + "PLATFORM": { + "num_psus": 2, + "num_cplds": 0, + "num_syseeproms": 1, + "num_fans": 6, + "num_ports": 32, + "num_sfps": 32, + "num_temps": 0, + "num_serviceports": 1, + "serviceport": "eth0", + "thermal_policy_support": "false", + "modules" : { + "FAN": { + "support": "true" + }, + "TEMP": { + "support": "false" + }, + "CPLD": { + "support": "false" + }, + "SYSLED": { + "support": "false" + }, + "PSU": { + "support": "true" + } + }, + "drivers": { + "CPLD": { + "driver_info": { + "support": "true", + "type": "ODM", + "name": "qci_platform_ix9" + } + }, + "PSU": { + "driver_info": { + "support": "false" + } + }, + "FAN": { + "driver_info": { + "support": "false" + } + }, + "SFP": { + "driver_info": { + "support": "false" + } + }, + "TEMP": { + "driver_info": { + "support": "false" + } + }, + "SYSLED": { + "driver_info": { + "support": "true", + "type": "ODM", + "name": "qci_cpld_led" + } + }, + "EEPROM": { + "driver_info": { + "support": "true", + "type": "GENERIC", + "name": "at24" + } + }, + "MAC": { + "driver_info": { + "support": "true", + "type": "GENERIC", + "name": "igb" + } + } + } + } +} \ No newline at end of file diff --git a/sonic-pde-tests/sonic_pde_tests/data/platform/test-x86_64-accton_as7312_54x-r0-config.json b/sonic-pde-tests/sonic_pde_tests/data/platform/test-x86_64-accton_as7312_54x-r0-config.json new file mode 100644 index 0000000..0fab858 --- /dev/null +++ b/sonic-pde-tests/sonic_pde_tests/data/platform/test-x86_64-accton_as7312_54x-r0-config.json @@ -0,0 +1,162 @@ +{ + "PLATFORM": { + "powercontrol": true, + "PSU": { + "present": [ + 1, + 2 + ], + "PSU1": { + "psu_serial_num": "AAAA" + }, + "PSU2": { + "psu_serial_num": "BBBB" + } + }, + "SFP": { + "present": [ + 6, + 9, + 15, + 24, + 36, + 39, + 48, + 56, + 64, + 68, + 72 + ] + }, + "USB": { + "enable": "yes", + "device": "sdb", + "mountpoint": "/media/usb-storage" + }, + "EEPROM": { + "mac": "00:11:22:33:44:55", + "ser": "AABBCCDDEEFF", + "model": "AAAA" + }, + "CPLD": { + "CPLD1": { + "version": "2" + }, + "CPLD2": { + "version": "1" + } + }, + "FAN": { + "present": [ + 1, + 2, + 3, + 4, + 5, + 6 + ], + "FAN1": { + "direction": "exhaust" + }, + "FAN2": { + "direction": "exhaust" + }, + "FAN3": { + "direction": "exhaust" + }, + "FAN4": { + "direction": "exhaust" + }, + "FAN5": { + "direction": "exhaust" + }, + "FAN6": { + "direction": "exhaust" + } + }, + "THERMAL_POLICY": + { + "service_name": "as7312-platform-monitor", + "POLICY_NUM":4, + "F2B": + { + "0": [0,34000,32], + "1": [35000,39000,50], + "2": [40000,44000,63], + "3": [45000,100000,100] + }, + "B2F": + { + "0": [0,34000,44], + "1": [35000,39000,63], + "2": [40000,44000,75], + "3": [45000,100000,100] + }, + "FAN_REMOVED_DUTY":100 + }, + "MAC": + { + "MAC1":{ + "ifname": "eth0", + "macaddr": "XX:XX:XX:XX:XX:XX" + } + }, + "SYSLED": + { + "FANTRAY":{ + "FANTRAY1":{ + "color":"GREEN", + "state" : "SOLID" + }, + "FANTRAY2":{ + "color":"GREEN", + "state" : "SOLID" + }, + "FANTRAY3":{ + "color":"GREEN", + "state" : "SOLID" + }, + "FANTRAY4":{ + "color":"GREEN", + "state" : "SOLID" + } + }, + "PSU":{ + "PSU1":{ + "color":"GREEN", + "state" : "SOLID" + }, + "PSU2":{ + "color":"GREEN", + "state" : "SOLID" + } + }, + "FAN":{ + "color":"GREEN", + "state" : "SOLID" + }, + "SYS":{ + "color":"GREEN", + "state" : "SOLID" + }, + "LOC":{ + "color":"GREEN", + "state" : "SOLID" + } + }, + "OS": + { + "flooding": { + "dmesg": [ + "error" + ], + "syslog": [ + "i2c", + "usb", + "pci" + ] + } + } + + } +} diff --git a/sonic-pde-tests/sonic_pde_tests/data/platform/test-x86_64-accton_as7326_56x-r0-config.json b/sonic-pde-tests/sonic_pde_tests/data/platform/test-x86_64-accton_as7326_56x-r0-config.json new file mode 100644 index 0000000..283b678 --- /dev/null +++ b/sonic-pde-tests/sonic_pde_tests/data/platform/test-x86_64-accton_as7326_56x-r0-config.json @@ -0,0 +1,178 @@ +{ + "PLATFORM": { + "powercontrol": true, + "PSU": { + "present": [ + 1, + 2 + ], + "status": [ + true, + false + ], + "PSU1": { + "mfr_id":"ChiconyPower", + "model":"FSF019", + "output_voltage":12, + "psu_serial_num": "000084" + } + }, + "SFP": { + "present": [ + 6, + 9, + 15, + 24, + 36, + 39, + 48, + 56, + 64, + 68, + 72 + ] + }, + "USB": { + "enable": "yes", + "device": "sdb", + "mountpoint": "/media/usb-storage" + }, + "EEPROM": { + "mac": "00:11:22:33:44:55", + "ser": "AABBCCDDEEFF", + "model": "AAAA" + }, + "CPLD": { + "CPLD1": { + "version": "2" + }, + "CPLD2": { + "version": "1" + } + }, + "FAN": { + "present": [ + 1, + 2, + 3, + 4, + 5, + 6 + ], + "FAN1": { + "direction": "exhaust" + }, + "FAN2": { + "direction": "exhaust" + }, + "FAN3": { + "direction": "exhaust" + }, + "FAN4": { + "direction": "exhaust" + }, + "FAN5": { + "direction": "exhaust" + }, + "FAN6": { + "direction": "exhaust" + } + }, + "THERMAL_POLICY": + { + "service_name": "as7326-platform-monitor", + "POLICY_NUM":3, + "F2B": + { + "0": [0,39,38], + "1": [40,44,75], + "2": [45,100,100] + }, + "B2F": + { + "0": [0,39,38], + "1": [40,44,75], + "2": [45,100,100] + }, + "FAN_REMOVED_DUTY":100 + }, + "MAC": + { + "MAC1":{ + "ifname": "eth0", + "macaddr": "XX:XX:XX:XX:XX:XX" + } + }, + "SYSLED": + { + "FANTRAY":{ + "FANTRAY1":{ + "color":"GREEN", + "state" : "SOLID" + }, + "FANTRAY2":{ + "color":"GREEN", + "state" : "SOLID" + }, + "FANTRAY3":{ + "color":"GREEN", + "state" : "SOLID" + }, + "FANTRAY4":{ + "color":"GREEN", + "state" : "SOLID" + } + }, + "PSU":{ + "PSU1":{ + "color":"GREEN", + "state" : "SOLID" + }, + "PSU2":{ + "color":"GREEN", + "state" : "SOLID" + } + }, + "FAN":{ + "color":"GREEN", + "state" : "SOLID" + }, + "SYS":{ + "color":"GREEN", + "state" : "SOLID" + }, + "LOC":{ + "color":"GREEN", + "state" : "SOLID" + } + }, + "CONFIG": + { + "required": { + "config.bcm": [ + "parity_enable=1" + ] + } + }, + "OS": + { + "flooding": { + "dmesg": [ + "error" + ], + "syslog": [ + "i2c", + "usb", + "pci" + ] + } + }, + "PMON": + { + "syslog": [ + "psud", + "fand" + ] + } + } +} diff --git a/sonic-pde-tests/sonic_pde_tests/data/platform/test-x86_64-accton_as7712_32x-r0-config.json b/sonic-pde-tests/sonic_pde_tests/data/platform/test-x86_64-accton_as7712_32x-r0-config.json new file mode 100644 index 0000000..910ebcd --- /dev/null +++ b/sonic-pde-tests/sonic_pde_tests/data/platform/test-x86_64-accton_as7712_32x-r0-config.json @@ -0,0 +1,146 @@ +{ + "PLATFORM": { + "powercontrol": false, + "PSU": { + "present": [ + 1, + 2 + ], + "status": [ + "True", + "False" + ], + "PSU1": { + "psu_serial_num": "AAAA" + }, + "PSU2": { + "psu_serial_num": "BBBB" + } + }, + "SFP": { + "present": [ + 13, + 17, + 52, + 68 + ] + }, + "USB": { + "enable": "yes", + "device": "sdb", + "mountpoint": "/media/usb-storage" + }, + "EEPROM": { + "mac": "3c:2c:99:2e:d9:75", + "ser": "771232X1752003", + "model": "7712-32X-O-AC-F" + }, + "CPLD": { + "CPLD1": { + "version": "2" + }, + "CPLD2": { + "version": "1" + } + }, + "FAN": { + "present": [ + 1, + 2, + 3, + 4, + 5, + 6 + ], + "FAN1": { + "direction": 0 + }, + "FAN2": { + "direction": 0 + }, + "FAN3": { + "direction": 0 + }, + "FAN4": { + "direction": 0 + }, + "FAN5": { + "direction": 0 + }, + "FAN6": { + "direction": 0 + } + }, + "MAC": + { + "MAC1":{ + "ifname": "eth0", + "macaddr": "3c:2c:99:2e:d9:75" + } + }, + "SYSLED": + { + "FANTRAY":{ + "FANTRAY1":{ + "color":"GREEN", + "state" : "SOLID" + }, + "FANTRAY2":{ + "color":"GREEN", + "state" : "SOLID" + }, + "FANTRAY3":{ + "color":"GREEN", + "state" : "SOLID" + }, + "FANTRAY4":{ + "color":"GREEN", + "state" : "SOLID" + } + }, + "PSU":{ + "PSU1":{ + "color":"GREEN", + "state" : "SOLID" + }, + "PSU2":{ + "color":"GREEN", + "state" : "SOLID" + } + }, + "FAN":{ + "color":"GREEN", + "state" : "SOLID" + }, + "SYS":{ + "color":"GREEN", + "state" : "SOLID" + }, + "LOC":{ + "color":"GREEN", + "state" : "SOLID" + } + }, + "OS": + { + "flooding": { + "dmesg": [ + "error" + ], + "syslog": [ + "i2c", + "usb", + "pci" + ] + } + }, + "CONFIG": + { + "required": { + "config.bcm": [ + "parity_enable=1" + ] + } + } + } +} diff --git a/sonic-pde-tests/sonic_pde_tests/data/platform/test-x86_64-accton_as7726_32x-r0-config.json b/sonic-pde-tests/sonic_pde_tests/data/platform/test-x86_64-accton_as7726_32x-r0-config.json new file mode 100644 index 0000000..db38c7f --- /dev/null +++ b/sonic-pde-tests/sonic_pde_tests/data/platform/test-x86_64-accton_as7726_32x-r0-config.json @@ -0,0 +1,195 @@ +{ + "PLATFORM": { + "powercontrol": false, + "THERMAL_POLICY": { + "service_name": "false" + }, + "PSU": { + "present": [ + 1, + 2 + ], + "status": [ + false, + true + ], + "PSU1": { + "psu_serial_num": "AAAA" + }, + "PSU2": { + "psu_serial_num": "SA070V581905000496", + "model":"YM-2651Y", + "output_voltage":12093 + } + }, + "SFP": { + "present": [ + 8, + 16, + 32, + 36, + 40, + 52, + 56 + ] + }, + "USB": { + "enable": "no", + "device": "sdb", + "mountpoint": "/media/usb-storage" + }, + "EEPROM": { + "mac": "80:a2:35:46:3f:99", + "ser": "772632X1911067", + "model": "7726-32X-O-AC-F" + }, + "CPLD": { + "CPLD1": { + "version": "2" + }, + "CPLD2": { + "version": "1" + } + }, + "FAN": { + "present": [ + 1, + 2, + 3, + 4, + 5, + 6 + ], + "FAN1": { + "direction": "INTAKE" + }, + "FAN2": { + "direction": "INTAKE" + }, + "FAN3": { + "direction": "INTAKE" + }, + "FAN4": { + "direction": "INTAKE" + }, + "FAN5": { + "direction": "INTAKE" + }, + "FAN6": { + "direction": "INTAKE" + } + }, + "MAC": + { + "MAC1":{ + "ifname": "eth0", + "macaddr": "80:a2:35:46:3f:99" + } + }, + "SYSLED": + { + "FANTRAY":{ + "FANTRAY1":{ + "color":"GREEN", + "state" : "SOLID" + }, + "FANTRAY2":{ + "color":"GREEN", + "state" : "SOLID" + }, + "FANTRAY3":{ + "color":"GREEN", + "state" : "SOLID" + }, + "FANTRAY4":{ + "color":"GREEN", + "state" : "SOLID" + }, + "FANTRAY5":{ + "color":"GREEN", + "state" : "SOLID" + }, + "FANTRAY6":{ + "color":"GREEN", + "state" : "SOLID" + } + }, + "PSU":{ + "PSU1":{ + "color":"GREEN", + "state" : "SOLID" + }, + "PSU2":{ + "color":"GREEN", + "state" : "SOLID" + } + }, + "FAN":{ + "color":"GREEN", + "state" : "SOLID" + }, + "SYS":{ + "color":"GREEN", + "state" : "SOLID" + }, + "LOC":{ + "color":"GREEN", + "state" : "SOLID" + }, + "DIAG":{ + "color":"GREEN", + "state" : "SOLID" + } + }, + "OS": + { + "flooding": { + "dmesg": [ + "error" + ], + "syslog": [ + "i2c", + "usb", + "pci" + ] + } + }, + "CONFIG": + { + "required": { + "config.bcm": [ + "parity_enable=0" + ] + } + }, + "TRAFFIC": + { + "port_pairs":[ + { + "src_front_portnum":"3", + "src_logical_portnum":"xe0", + "dst_front_portnum":"4", + "dst_logical_portnum":"xe1" + }, + { + "src_front_portnum":"4", + "src_logical_portnum":"xe1", + "dst_front_portnum":"3", + "dst_logical_portnum":"xe0" + }, + { + "src_front_portnum":"12", + "src_logical_portnum":"ce11", + "dst_front_portnum":"13", + "dst_logical_portnum":"ce12" + }, + { + "src_front_portnum":"13", + "src_logical_portnum":"ce12", + "dst_front_portnum":"12", + "dst_logical_portnum":"ce11" + } + ] + } + } +} diff --git a/sonic-pde-tests/sonic_pde_tests/data/platform/test-x86_64-accton_as7816_64x-r0-config.json b/sonic-pde-tests/sonic_pde_tests/data/platform/test-x86_64-accton_as7816_64x-r0-config.json new file mode 100644 index 0000000..37212ab --- /dev/null +++ b/sonic-pde-tests/sonic_pde_tests/data/platform/test-x86_64-accton_as7816_64x-r0-config.json @@ -0,0 +1,133 @@ +{ + "PLATFORM": { + "powercontrol": true, + "PSU": { + "present": [ + 1, + 2 + ], + "PSU1": { + "psu_serial_num": "AAAA" + }, + "PSU2": { + "psu_serial_num": "BBBB" + } + }, + "SFP": { + "present": [ + 6, + 9, + 15, + 24, + 36, + 39, + 48, + 56, + 64, + 68, + 72 + ] + }, + "USB": { + "enable": "yes", + "device": "sdb", + "mountpoint": "/media/usb-storage" + }, + "EEPROM": { + "mac": "00:11:22:33:44:55", + "ser": "AABBCCDDEEFF", + "model": "AAAA" + }, + "CPLD": { + "CPLD1": { + "version": "2" + }, + "CPLD2": { + "version": "1" + } + }, + "FAN": { + "present": [ + 1, + 2, + 3, + 4 + ], + "FAN1": { + "direction": 0 + }, + "FAN2": { + "direction": 0 + }, + "FAN3": { + "direction": 0 + }, + "FAN4": { + "direction": 0 + } + }, + "MAC": + { + "MAC1":{ + "ifname": "eth0", + "macaddr": "XX:XX:XX:XX:XX:XX" + } + }, + "SYSLED": + { + "FANTRAY":{ + "FANTRAY1":{ + "color":"GREEN", + "state" : "SOLID" + }, + "FANTRAY2":{ + "color":"GREEN", + "state" : "SOLID" + }, + "FANTRAY3":{ + "color":"GREEN", + "state" : "SOLID" + }, + "FANTRAY4":{ + "color":"GREEN", + "state" : "SOLID" + } + }, + "PSU":{ + "PSU1":{ + "color":"GREEN", + "state" : "SOLID" + }, + "PSU2":{ + "color":"GREEN", + "state" : "SOLID" + } + }, + "FAN":{ + "color":"GREEN", + "state" : "SOLID" + }, + "SYS":{ + "color":"GREEN", + "state" : "SOLID" + }, + "LOC":{ + "color":"GREEN", + "state" : "SOLID" + } + }, + "OS": + { + "flooding": { + "dmesg": [ + "error" + ], + "syslog": [ + "i2c", + "usb", + "pci" + ] + } + } + } +} diff --git a/sonic-pde-tests/sonic_pde_tests/data/platform/test-x86_64-quanta_ix8_rglbmc-r0-config.json b/sonic-pde-tests/sonic_pde_tests/data/platform/test-x86_64-quanta_ix8_rglbmc-r0-config.json new file mode 100644 index 0000000..6a24ab3 --- /dev/null +++ b/sonic-pde-tests/sonic_pde_tests/data/platform/test-x86_64-quanta_ix8_rglbmc-r0-config.json @@ -0,0 +1,112 @@ +{ + "PLATFORM": { + "powercontrol": false, + "PSU": { + "present": [ + 1, + 2 + ], + "status": [ + true, + true + ] + }, + "SFP": { + "present": [ + 0, + 1, + 48, + 49 + ] + }, + "USB": { + "enable": "yes", + "device": "sdb", + "mountpoint": "/media/usb-storage" + }, + "EEPROM": { + "mac": "d8:c4:97:28:30:a8", + "ser": "QTFCU38030006", + "model": "T4048-IX8" + }, + "MAC": + { + "MAC1":{ + "ifname": "eth0", + "macaddr": "54:ab:3a:9c:17:e5" + } + }, + "SYSLED": + { + "FAN":{ + "color":"Green", + "state" : "SOLID" + }, + "SYS":{ + "color":"Green", + "state" : "SOLID" + }, + "LOC":{ + "color":"Green", + "state" : "SOLID" + } + }, + "OS": + { + "flooding": { + "dmesg": [ + "error" + ], + "syslog": [ + "i2c", + "usb", + "pci" + ] + } + }, + "CONFIG": + { + "required": { + "config.bcm": [ + "parity_enable=1" + ] + } + }, + "PMON": + { + "syslog": [ + "psud", + "fand" + ] + }, + "TRAFFIC": + { + "port_pairs":[ + { + "src_front_portnum":"1", + "src_logical_portnum":"xe0", + "dst_front_portnum":"2", + "dst_logical_portnum":"xe1" + }, + { + "src_front_portnum":"2", + "src_logical_portnum":"xe1", + "dst_front_portnum":"1", + "dst_logical_portnum":"xe0" + }, + { + "src_front_portnum":"49", + "src_logical_portnum":"ce3", + "dst_front_portnum":"50", + "dst_logical_portnum":"ce4" + }, + { + "src_front_portnum":"50", + "src_logical_portnum":"ce4", + "dst_front_portnum":"49", + "dst_logical_portnum":"ce3" + } + ] + } + } +} diff --git a/sonic-pde-tests/sonic_pde_tests/data/platform/test-x86_64-quanta_ix9_bwde-r0-config.json b/sonic-pde-tests/sonic_pde_tests/data/platform/test-x86_64-quanta_ix9_bwde-r0-config.json new file mode 100644 index 0000000..5be7c5a --- /dev/null +++ b/sonic-pde-tests/sonic_pde_tests/data/platform/test-x86_64-quanta_ix9_bwde-r0-config.json @@ -0,0 +1,123 @@ +{ + "PLATFORM": { + "powercontrol": false, + "PSU": { + "present": [ + 1, + 2 + ], + "status": [ + true, + false + ], + "PSU1": { + "mfr_id":"ChiconyPower", + "model":"R17-1K6P1AA", + "output_voltage":12000, + "psu_serial_num": "F387881844001008" + } + }, + "SFP": { + "present": [ + 0, + 2, + 31 + ] + }, + "USB": { + "enable": "yes", + "device": "sda", + "mountpoint": "/media/usb-storage" + }, + "EEPROM": { + "mac": "d8:c4:97:cd:e7:d6", + "ser": "123456789", + "model": "T9032-IX9", + "platform": "x86_64-quanta_bwde-r0" + }, + "MAC": + { + "MAC1":{ + "ifname": "eth0", + "macaddr": "d8:c4:97:cd:e7:d6" + } + }, + "FAN": { + "present": [ + 2, + 3, + 4, + 5, + 6 + ], + "FAN2": { + "direction": "EXHAUST" + }, + "FAN3": { + "direction": "EXHAUST" + }, + "FAN4": { + "direction": "EXHAUST" + }, + "FAN5": { + "direction": "EXHAUST" + }, + "FAN6": { + "direction": "EXHAUST" + } + }, + "SYSLED": + { + "FAN":{ + "color":"Green", + "state" : "SOLID" + }, + "SYS":{ + "color":"Green", + "state" : "SOLID" + }, + "LOC":{ + "color":"Green", + "state" : "SOLID" + } + }, + "OS": + { + "flooding": { + "dmesg": [ + "error" + ], + "syslog": [ + "i2c", + "usb", + "pci" + ] + } + }, + "CONFIG": + { + "required": { + "config.bcm": [ + "parity_enable=1" + ] + } + }, + "TRAFFIC": + { + "port_pairs":[ + { + "src_front_portnum":"1", + "src_logical_portnum":"cd0", + "dst_front_portnum":"32", + "dst_logical_portnum":"cd31" + }, + { + "src_front_portnum":"32", + "src_logical_portnum":"cd31", + "dst_front_portnum":"1", + "dst_logical_portnum":"cd0" + } + ] + } + } +} diff --git a/sonic-pde-tests/sonic_pde_tests/data/template/platform-config.json b/sonic-pde-tests/sonic_pde_tests/data/template/platform-config.json new file mode 100644 index 0000000..863a6b8 --- /dev/null +++ b/sonic-pde-tests/sonic_pde_tests/data/template/platform-config.json @@ -0,0 +1,101 @@ +{ + "PLATFORM": { + "num_psus": 0, + "num_cplds": 0, + "num_syseeproms": 0, + "num_fans": 0, + "num_ports": 0, + "num_temps": 0, + "num_serviceports": 0, + "serviceport": "eth0", + "thermal_policy_support": "false", + "modules" : { + "FAN": { + "support" : "true/false", + "path": "XXXX", + "name": "XXXX", + "class": "XXXX" + }, + "CPLD" : { + "support" : "true/false", + "path" :"XXXX", + "name" :"XXXX", + "class" : "XXXX" + }, + "SYSLED" : { + "support" : "true/false", + "path" :"XXXX", + "name" :"XXXX", + "class" : "XXXX" + }, + "TEMP" : { + "support" : "true/false", + "path" :"XXXX", + "name" :"XXXX", + "class" : "XXXX" + }, + "PSU" : { + "support" : "true/false" + } + }, + "drivers": { + "CPLD": { + "driver_info": { + "support": "true/false", + "type": "ODM/GENERIC/PDDF", + "name": "xxxx" + } + }, + "PSU": { + "driver_info": { + "support": "true/false", + "type": "ODM/GENERIC/PDDF", + "name": "xxxx" + } + }, + "FAN": { + "driver_info": { + "support": "true/false", + "type": "ODM/GENERIC/PDDF", + "name": "xxxx" + } + }, + "SFP": { + "driver_info": { + "support": "true/false", + "type": "ODM/GENERIC/PDDF", + "name": "xxxx" + } + }, + "TEMP": { + "driver_info": { + "support": "true/false", + "type": "ODM/GENERIC/PDDF", + "name": "xxxx" + } + }, + "SYSLED": { + "driver_info": { + "support": "true/false", + "type": "ODM/GENERIC/PDDF", + "name": "xxxx" + } + }, + "EEPROM": { + "driver_info": { + "support": "true/false", + "type": "ODM/GENERIC/PDDF", + "name": "xxxx" + } + }, + "MAC" : { + "driver_info": { + "support": "true/false", + "type": "ODM/GENERIC/PDDF", + "name": "xxxx" + } + } + } + } +} + diff --git a/sonic-pde-tests/sonic_pde_tests/data/template/test-config.json b/sonic-pde-tests/sonic_pde_tests/data/template/test-config.json new file mode 100644 index 0000000..2320c3c --- /dev/null +++ b/sonic-pde-tests/sonic_pde_tests/data/template/test-config.json @@ -0,0 +1,197 @@ +{ + "PLATFORM": { + "powercontrol": "TRUE/FALSE", + "PSU": { + "present": [ + 1, + 2 + ], + "status": [ + true, + false + ], + "PSU#X": { + "mfr_id":"ChiconyPower", + "model":"R17-1K6P1AA", + "output_voltage":"12000", + "psu_serial_num": "F387881844001008" + }, + "PSU#X+1": { + "mfr_id":"ChiconyPower", + "model":"R17-1K6P1AA", + "output_voltage":"12000", + "psu_serial_num": "F387881844001008" + } + }, + "SFP": { + "present": [ + 1, + 3, + 5, + 7 + ], + "SFP#X": { + "lpmode": "ON/OFF" + } + }, + "EEPROM": { + "mac": "XX:XX:XX:XX:XX:XX", + "ser": "XXXXXXXXXX", + "model": "XXXXXXXX" + }, + "CPLD": { + "CPLD#X": { + "version": "XX" + }, + "CPLD#X+1": { + "version": "XX" + }, + "CPLD#X+2": { + "version": "XX" + } + }, + "FAN": { + "present": [ + 1, + 2 + ], + "FAN#X": { + "direction": "exhaust/intake" + }, + "FAN#X+1": { + "direction": "exhaust/intake" + } + }, + "THERMAL_POLICY": + { + "service_name": "xxxx.service", + "POLICY_NUM":4, + "F2B": + { + "0": [0,34000,32], + "1": [35000,39000,50], + "2": [40000,44000,63], + "3": [45000,100000,100] + }, + "B2F": + { + "0": [0,34000,44], + "1": [35000,39000,63], + "2": [40000,44000,75], + "3": [45000,100000,100] + }, + "FAN_REMOVED_DUTY":100 + }, + "USB": { + "enable": "yes/no", + "device": "sd#X", + "mountpoint": "/xxxx/xxxxxxx" + }, + "MAC": { + "MAC#X": { + "ifname": "XXX", + "macaddr": "XX:XX:XX:XX:XX:XX" + } + }, + "SYSLED": + { + "FANTRAY":{ + "FANTRAY1":{ + "color":"GREEN/RED/AMBER", + "state" : "SOLID/BLINKING" + }, + "FANTRAY2":{ + "color":"GREEN/RED/AMBER", + "state" : "SOLID/BLINKING" + } + }, + "PSU":{ + "PSU1":{ + "color":"GREEN/RED/AMBER", + "state" : "SOLID/BLINKING" + }, + "PSU2":{ + "color":"GREEN/RED/AMBER", + "state" : "SOLID/BLINKING" + } + }, + "FAN":{ + "color":"GREEN/RED/AMBER", + "state" : "SOLID/BLINKING" + }, + "SYS":{ + "color":"GREEN/RED/AMBER", + "state" : "SOLID/BLINKING" + }, + "LOC":{ + "color":"GREEN/RED/AMBER", + "state" : "SOLID/BLINKING" + } + }, + "OS": + { + "flooding": { + "dmesg": [ + "error" + ], + "syslog": [ + "i2c", + "usb", + "pci" + ] + } + }, + "CONFIG": + { + "required": { + "config.bcm": [ + "parity_enable=1" + ] + } + }, + "PMON": + { + "syslog": [ + "psud", + "fand" + ] + }, + "TRAFFIC": + { + "port_pairs":[ + { + "src_front_portnum":"1", + "src_logical_portnum":"xe0", + "dst_front_portnum":"2", + "dst_logical_portnum":"xe1" + }, + { + "src_front_portnum":"2", + "src_logical_portnum":"xe1", + "dst_front_portnum":"1", + "dst_logical_portnum":"xe0" + }, + { + "src_front_portnum":"49", + "src_logical_portnum":"ce3", + "dst_front_portnum":"50", + "dst_logical_portnum":"ce4" + }, + { + "src_front_portnum":"50", + "src_logical_portnum":"ce4", + "dst_front_portnum":"49", + "dst_logical_portnum":"ce3" + } + ] + }, + "PORT_BREAKOUT" : { + "Ethernet128" : "1x100,4x25,4x10", + "Ethernet136" : "1x100,4x25,4x10" + }, + "SELF_LOOPS" : [ + "Ethernet48:Ethernet56", + "Ethernet64:Ethernet72" + ] + } +} diff --git a/sonic-pde-tests/sonic_pde_tests/sai-shell b/sonic-pde-tests/sonic_pde_tests/sai-shell new file mode 100755 index 0000000..2a3e80d --- /dev/null +++ b/sonic-pde-tests/sonic_pde_tests/sai-shell @@ -0,0 +1,17 @@ +#!/usr/bin/python + +import os.path +import sys +import saiut + +SONIC_PLATFORM_PATH='/usr/share/sonic/platform' + +rv = saiut.switchInitialize("00:11:22:33:44:55") +if rv != saiut.SAI_STATUS_SUCCESS: + print("Error: Unable to initialize the switch, rv={}".format(rv)) + sys.exit(1) + +if os.path.exists(SONIC_PLATFORM_PATH + '/led_proc_init.soc'): + saiut.bcmDiagCommand('rcload ' + SONIC_PLATFORM_PATH + '/led_proc_init.soc') + +saiut.switchShell(True) diff --git a/sonic-pde-tests/sonic_pde_tests/test_bmc.py b/sonic-pde-tests/sonic_pde_tests/test_bmc.py new file mode 100644 index 0000000..84bd29e --- /dev/null +++ b/sonic-pde-tests/sonic_pde_tests/test_bmc.py @@ -0,0 +1,11 @@ +import pytest +import sys +import imp + + +def test_for_bmc(json_config_data): + pytest.skip("Not supported") + +if __name__ == '__main__': + unittest.main() + diff --git a/sonic-pde-tests/sonic_pde_tests/test_config.py b/sonic-pde-tests/sonic_pde_tests/test_config.py new file mode 100644 index 0000000..ef98d44 --- /dev/null +++ b/sonic-pde-tests/sonic_pde_tests/test_config.py @@ -0,0 +1,73 @@ +#!/usr/bin/python + +try: + import pytest + import json + import time + import os + import sys + import subprocess +except ImportError as e: + raise ImportError("%s - required module not found" % str(e)) + +def test_for_required_bcm_config_file(json_test_data): + """ Test Purpose: Verify the SAI config.bcm file (sai.profile) is present. + + Args: + arg1 (json): test--config.json + + Example: + No test or platform JSON changes necesssary. + """ + + with open('/etc/sai.d/sai.profile') as data: + for line in data: + if line.find("SAI_PROFILE") == -1: + contents = line.strip().split("=") + config_file = contents[1] + + assert config_file != {}, "Chipset configuration file not found" + +def test_for_required_bcm_config_settings(json_test_data): + """Test Purpose: Verify that the platform config.bcm file contains mandatory Silicon supported features. + + Args: + arg1 (json): test--config.json + + Example: + Parity should always be enabled for Broadcom switching silicon. + + "PLATFORM": { + "CONFIG": { + "required": { + "config.bcm": [ + "parity_enable=1" + ] + } + } + """ + + with open('/etc/sai.d/sai.profile') as data: + for line in data: + if line.find("SAI_PROFILE") == -1: + contents = line.strip().split("=") + config_file = contents[1] + + assert config_file != {}, "Chipset configuration file not found" + + pat = json_test_data["PLATFORM"]["CONFIG"]["required"]["config.bcm"] + # sampling pattern counts - start point + for idx in range(len(pat)): + cmd = "cat " + config_file + " | grep -c -i " + pat[idx] + pin = subprocess.Popen(cmd, + shell=True, + close_fds=True, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + cnt = pin.communicate()[0] + print cnt + + assert int(cnt)==1, "Required configuration property [" + pat[idx] + "] not detected" + + + diff --git a/sonic-pde-tests/sonic_pde_tests/test_cpld.py b/sonic-pde-tests/sonic_pde_tests/test_cpld.py new file mode 100644 index 0000000..9cf3fc3 --- /dev/null +++ b/sonic-pde-tests/sonic_pde_tests/test_cpld.py @@ -0,0 +1,90 @@ +import pytest +import sys +import imp +import subprocess +import time + + +# Global platform-specific cpldutil class instance +platform_cpldutil = None + +# Loads platform specific cpldutil module from source +def load_platform_cpldutil(json_config_data): + global platform_cpldutil + + if platform_cpldutil is not None: + return + + try: + if json_config_data['PLATFORM']['modules']['CPLD']['support'] == "false": + pytest.skip("Skip the testing due to the module is not supported in BSP") + + modules_dir = json_config_data['PLATFORM']['modules']['CPLD']['path'] + modules_name = json_config_data['PLATFORM']['modules']['CPLD']['name'] + class_name = json_config_data['PLATFORM']['modules']['CPLD']['class'] + cpld_module = "/usr/share/sonic/classes/" + modules_dir + "/" + modules_name + '.py' + platform_cpldutil_module = imp.load_source(modules_name,cpld_module) + platform_cpldutil_class = getattr(platform_cpldutil_module,class_name) + platform_cpldutil = platform_cpldutil_class() + + except AttributeError, e: + print("Failed to instantiate '%s' class: %s" % (class_name, str(e)), True) + + return + + +def test_for_num_cpld(json_config_data): + """Test Purpose: Verify that the numer of CPLD reported as supported + by the CPLD plugin matches what the platform supports + + Args: + arg1 (json): platform--config.json + + Example: + For a system that physically supports 2 CPLD + + platform--config.json + { + "PLATFORM": { + "num_cplds": 2 + } + } + """ + + load_platform_cpldutil(json_config_data) + assert platform_cpldutil.get_num_cplds() == json_config_data['PLATFORM']['num_cplds'],\ + "verify CPLD numbers {} not matching with platform JSON".format(platform_cpldutil.get_num_cplds()) + +def test_for_cpld_read(json_config_data,json_test_data): + """Test Purpose: Test Purpose: Verify that the CPLD version able to read and value + is matching with the value defined in test config JSON + + Args: + arg1 (json): platform--config.json + arg2 (json): test--config.json + + Example: + For a system that physically supports 2 CPLD, the CPLD version defined in the + test--config.json + + "CPLD": { + "CPLD1": { + "version": "2" + }, + "CPLD2": { + "version": "1" + } + }, + + + """ + + load_platform_cpldutil(json_config_data) + for key in json_config_data: + for x in range(json_config_data[key]['num_cplds']): + assert platform_cpldutil.get_cpld_version(x+1).strip() == json_test_data[key]['CPLD']['CPLD'+str(x+1)]['version'], \ + "verify" + " CPLD"+str(x+1)+" version={} is False".format(platform_cpldutil.get_cpld_version(x+1)) + +if __name__ == '__main__': + unittest.main() + diff --git a/sonic-pde-tests/sonic_pde_tests/test_eeprom.py b/sonic-pde-tests/sonic_pde_tests/test_eeprom.py new file mode 100644 index 0000000..ee9b4fc --- /dev/null +++ b/sonic-pde-tests/sonic_pde_tests/test_eeprom.py @@ -0,0 +1,130 @@ +import pytest +import sys +import imp +import subprocess +import time + +PLATFORM_SPECIFIC_CLASS_NAME = "board" + +def test_for_eeprom_read(): + """Test Purpose: Verify that the EEPROM read is ok and chcksum is valid + """ + + module = imp.load_source("eeprom","/usr/share/sonic/platform/plugins/eeprom.py") + board = getattr(module, PLATFORM_SPECIFIC_CLASS_NAME) + eeprom = board('',0,'',True) + assert eeprom.is_checksum_valid(eeprom.read_eeprom()),\ + "verify checksum is invalid".format(eeprom.read_eeprom()) + + +def test_for_eeprom_mac(json_config_data,json_test_data): + """Test Purpose: Verify that the MAC read from EEPROM is matching with the + test config JSON setting + + Args: + arg1 (json): platform--config.json + arg2 (json): test--config.json + + Example: + For a system that physically supports 1 syseeprom, the MAC address is + configured in the test--config.json + + test--config.json + "EEPROM": { + "mac": "00:11:22:33:44:55", + "ser": "AABBCCDDEEFF", + "model": "AAAA" + }, + """ + + module = imp.load_source("eeprom","/usr/share/sonic/platform/plugins/eeprom.py") + board = getattr(module, PLATFORM_SPECIFIC_CLASS_NAME) + eeprom = board('',0,'',True) + for key in json_config_data: + assert eeprom.base_mac_addr(eeprom.read_eeprom()) == json_test_data[key]['EEPROM']['mac'],\ + "verify MAC is invalid".format(eeprom.read_eeprom()) + + +def test_for_eeprom_SER(json_config_data,json_test_data): + """Test Purpose: Verify that the SERIAL read from EEPROM is matching with the + test config JSON setting + + Args: + arg1 (json): platform--config.json + arg2 (json): test--config.json + + Example: + For a system that physically supports 1 syseeprom, the SERIAL number is + configured in the test--config.json + + test--config.json + "EEPROM": { + "mac": "00:11:22:33:44:55", + "ser": "AABBCCDDEEFF", + "model": "AAAA" + }, + """ + + module = imp.load_source("eeprom","/usr/share/sonic/platform/plugins/eeprom.py") + board = getattr(module, PLATFORM_SPECIFIC_CLASS_NAME) + eeprom = board('',0,'',True) + + for key in json_config_data: + assert eeprom.serial_number_str(eeprom.read_eeprom()) == json_test_data[key]['EEPROM']['ser'],\ + "verify SER NUMBER is invalid".format(eeprom.read_eeprom()) + + +def test_for_eeprom_MODEL(json_config_data,json_test_data): + """Test Purpose: Verify that the MODEL read from EEPROM is matching with the + test config JSON setting + + Args: + arg1 (json): platform--config.json + arg2 (json): test--config.json + + Example: + For a system that physically supports 1 syseeprom, the MODEL is + configured in the test--config.json + + test--config.json + "EEPROM": { + "mac": "00:11:22:33:44:55", + "ser": "AABBCCDDEEFF", + "model": "AAAA" + }, + """ + module = imp.load_source("eeprom","/usr/share/sonic/platform/plugins/eeprom.py") + board = getattr(module, PLATFORM_SPECIFIC_CLASS_NAME) + eeprom = board('',0,'',True) + + for key in json_config_data: + assert eeprom.modelstr(eeprom.read_eeprom()) == json_test_data[key]['EEPROM']['model'],\ + "verify Model Name is invalid".format(eeprom.read_eeprom()) + + +def test_for_platform_id(json_config_data,json_test_data): + module = imp.load_source("eeprom","/usr/share/sonic/platform/plugins/eeprom.py") + board = getattr(module, PLATFORM_SPECIFIC_CLASS_NAME) + eeprom = board('',0,'',True) + + valid, t = eeprom.get_tlv_field(eeprom.read_eeprom(), \ + eeprom._TLV_CODE_PLATFORM_NAME) + assert valid, "Unable to get platform name from EEPROM" + + cmd = "cat /host/machine.conf | grep onie_platform | cut -d '=' -f 2" + pin = subprocess.Popen(cmd, + shell=True, + close_fds=True, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + id = pin.communicate()[0] + id = id.strip() + assert id == t[2], "platform id mismatch" + return + + + + +if __name__ == '__main__': + unittest.main() + diff --git a/sonic-pde-tests/sonic_pde_tests/test_fan.py b/sonic-pde-tests/sonic_pde_tests/test_fan.py new file mode 100644 index 0000000..2854363 --- /dev/null +++ b/sonic-pde-tests/sonic_pde_tests/test_fan.py @@ -0,0 +1,251 @@ +import pytest +import sys +import imp +import subprocess +import time + +DUTY_MIN = 50 +DUTY_MAX = 100 + + +PLATFORM_PATH = "/usr/share/sonic/platform" +PLATFORM_SPECIFIC_MODULE_NAME = "fanutil" +PLATFORM_SPECIFIC_CLASS_NAME = "FanUtil" + +# Global platform-specific fanutil class instance +platform_fanutil = None +platform_chassis = None + +# Loads platform specific module from source +def _wrapper_init(): + global platform_chassis + global platform_fanutil + + # Load new platform api class + if platform_chassis is None: + try: + import sonic_platform.platform + platform_chassis = sonic_platform.platform.Platform().get_chassis() + except Exception as e: + print("Failed to load chassis due to {}".format(repr(e))) + + + # Load platform-specific fanutil class + if platform_chassis is None: + try: + module_file = "/".join([PLATFORM_PATH, "plugins", PLATFORM_SPECIFIC_MODULE_NAME + ".py"]) + module = imp.load_source(PLATFORM_SPECIFIC_MODULE_NAME, module_file) + platform_fanutil_class = getattr(module, PLATFORM_SPECIFIC_CLASS_NAME) + platform_fanutil = platform_fanutil_class() + except Exception as e: + print("Failed to load fanutil due to {}".format(repr(e))) + + assert (platform_chassis is not None) or (platform_fanutil is not None), "Unable to load platform module" + +# wrappers that are compliable with both new platform api and old-style plugin +def _wrapper_get_num_fans(): + _wrapper_init() + if platform_chassis is not None: + try: + return platform_chassis.get_num_fans() + except NotImplementedError: + pass + return platform_fanutil.get_num_fans() + +def _wrapper_get_fan_direction(index): + _wrapper_init() + if platform_chassis is not None: + try: + return platform_chassis.get_fan(index).get_direction() + except NotImplementedError: + pass + return platform_fanutil.get_direction(index+1) + +def _wrapper_get_fan_status(index): + _wrapper_init() + if platform_chassis is not None: + try: + return platform_chassis.get_fan(index).get_status() + except NotImplementedError: + pass + return platform_fanutil.get_status(index+1) + +def _wrapper_get_fan_presence(index): + _wrapper_init() + if platform_chassis is not None: + try: + return platform_chassis.get_fan(index).get_presence() + except NotImplementedError: + pass + return platform_fanutil.get_presence(index+1) + +def _wrapper_get_fan_duty(index): + _wrapper_init() + if platform_chassis is not None: + try: + return platform_chassis.get_fan(index).get_speed() + except NotImplementedError: + pass + return platform_fanutil.get_speed(index+1) + +def _wrapper_set_fan_duty(index, duty): + _wrapper_init() + if platform_chassis is not None: + try: + return platform_chassis.get_fan(index).set_speed(duty) + except NotImplementedError: + pass + return platform_fanutil.set_speed(index+1) + +# test cases +def test_for_num_fans(json_config_data): + """Test Purpose: Verify that the numer of FANs reported as supported + by the FAN plugin matches what the platform supports + + Args: + arg1 (json): platform--config.json + + Example: + For a system that physically supports 4 FAN + + platform--config.json + { + "PLATFORM": { + "num_fans": 4 + } + } + """ + if json_config_data['PLATFORM']['modules']['FAN']['support'] == "false": + pytest.skip("Skip the testing due to the python module is not supported in BSP") + + assert _wrapper_get_num_fans() == json_config_data['PLATFORM']['num_fans'],\ + "The number of FAN does not match the platform JSON" + +def test_for_fans_dir(json_config_data, json_test_data): + """Test Purpose: Verify that the FAN direction reported as supported + by the FAN plugin matches with test config JSON + + Args: + arg1 (json): platform--config.json + arg2 (json): test--config.json + + Example: + Test config JSON setting for FAN direction + + "FAN": { + "FAN1": { + "direction": "exhaust" + }, + "FAN2": { + "direction": "exhaust" + } + } + """ + if json_config_data['PLATFORM']['modules']['FAN']['support'] == "false": + pytest.skip("Skip the testing due to the python module is not supported in BSP") + + for key in json_config_data: + for x in json_test_data[key]['FAN']['present']: + assert _wrapper_get_fan_direction(x-1) == json_test_data[key]['FAN']['FAN'+str(x)]['direction'],\ + "FAN{}: DIR mismatched".format(x) + +def test_for_fans_status(json_config_data, json_test_data): + + """Test Purpose: Verify that the FAN status of each present FAN + reported as supported by the FAN plugin matches + with test config JSON + + Args: + arg1 (json): platform--config.json + arg2 (json): test--config.json + + Example: + Test config JSON setting for FAN direction + + "FAN": { + "present": [ + 1, + 2, + 3, + 4 + ], + }, + """ + if json_config_data['PLATFORM']['modules']['FAN']['support'] == "false": + pytest.skip("Skip the testing due to the python module is not supported in BSP") + + for key in json_config_data: + for x in json_test_data[key]['FAN']['present']: + assert _wrapper_get_fan_status(x-1) == True,\ + "FAN{}: status is False".format(x) + + +def test_for_fans_present(json_config_data, json_test_data): + """Test Purpose: Verify that the FAN present reported as supported by the + FAN plugin matches with test config JSON + + Args: + arg1 (json): platform--config.json + arg2 (json): test--config.json + + Example: + Test config JSON setting for FAN present + + "FAN": { + "present": [ + 1, + 2, + 3, + 4 + ], + }, + """ + if json_config_data['PLATFORM']['modules']['FAN']['support'] == "false": + pytest.skip("Skip the testing due to the python module is not supported in BSP") + + for key in json_config_data: + list = json_test_data[key]['FAN']['present'] + for x in range(json_config_data['PLATFORM']['num_fans']): + if x + 1 in list: + assert _wrapper_get_fan_presence(x) == True,\ + "FAN{}: is not present unexpectedly".format(x + 1) + else: + assert _wrapper_get_fan_presence(x) == False,\ + "FAN{}: is present unexpectedly".format(x + 1) + + +def test_for_fans_duty(json_config_data, json_test_data): + """Test Purpose:Verify that the FAN Duty Set is working fine + + args: + arg1 (json): platform--config.json + + example: + For a system that physically supports 4 FAN + + platform--config.json + { + "PLATFORM": { + "num_fans": 4 + } + } + """ + if json_config_data['PLATFORM']['modules']['FAN']['support'] == "false": + pytest.skip("Skip the testing due to the python module is not supported in BSP") + + # Only verify FAN Duty set ;; FAN Read will be verified in Thermal Test + # start FAN speed/duty test + for key in json_config_data: + for x in range(0, _wrapper_get_num_fans()): + if _wrapper_get_fan_presence(x) == False: + continue; + # low speed test + assert _wrapper_set_fan_duty(x, DUTY_MIN), \ + "FAN{}: Unable to update fan speed".format(x+1) + + # high speed test + assert _wrapper_set_fan_duty(x, DUTY_MAX), \ + "FAN{}: Unable to update fan speed".format(x+1) + + + diff --git a/sonic-pde-tests/sonic_pde_tests/test_leds.py b/sonic-pde-tests/sonic_pde_tests/test_leds.py new file mode 100644 index 0000000..929fe7b --- /dev/null +++ b/sonic-pde-tests/sonic_pde_tests/test_leds.py @@ -0,0 +1,217 @@ +import pytest +import sys +import imp +import subprocess +import time + + +# Global platform-specific sysledutil class instance +platform_sysledutil = None + +# Loads platform specific sysledutil module from source +def load_platform_sysledutil(json_config_data): + global platform_sysledutil + + if platform_sysledutil is not None: + return + + try: + + if json_config_data['PLATFORM']['modules']['SYSLED']['support'] == "false": + pytest.skip("Skip the testing due to the python module is not supported") + + modules_dir = json_config_data['PLATFORM']['modules']['SYSLED']['path'] + modules_name = json_config_data['PLATFORM']['modules']['SYSLED']['name'] + class_name = json_config_data['PLATFORM']['modules']['SYSLED']['class'] + sysledutil_module = "/usr/share/sonic/classes/" + modules_dir + "/" + modules_name + '.py' + platform_sysledutil_module = imp.load_source(modules_name,sysledutil_module) + platform_sysledutil_class = getattr(platform_sysledutil_module,class_name) + platform_sysledutil = platform_sysledutil_class() + + except AttributeError, e: + print("Failed to instantiate '%s' class: %s" % (class_name, str(e)), True) + + return + + +def test_for_set_fan_sysled(json_config_data, json_test_data): + + """Test Purpose: Verify that the SYS FAN LED is able to set per the color and state + defined in the test config JSON + + Args: + arg1 (json): platform--config.json + arg2 (json): test--config.json + + Example: + SYSLED Color state setting for the FAN defined in JSON + configured in the test--config.json + + "SYSLED": + { + "FAN":{ + "color":"GREEN/RED/AMBER", + "state" : "SOLID/BLINKING" + }, + + """ + + load_platform_sysledutil(json_config_data) + for key in json_config_data: + color = json_test_data[key]['SYSLED']['FAN']['color'] + state = json_test_data[key]['SYSLED']['FAN']['state'] + index = 0 + platform_sysledutil.set_status_led('fan', index, color, state) + + assert platform_sysledutil.get_status_led('fan', index) == state,\ + "fan"+str(index)+" sys led color is fail to changed, status = {}".format(get_status_led('fan', index)) + +def test_for_set_fantray_sysled(json_config_data, json_test_data): + + """Test Purpose: Verify that the SYS FANTRAY LED is able to set per the color and state + defined in the test config JSON + + Args: + arg1 (json): platform--config.json + arg2 (json): test--config.json + + Example: + SYSLED Color state setting for the FANTRAY defined in JSON + configured in the test--config.json + + + "SYSLED": + { + "FANTRAY":{ + "FANTRAY1":{ + "color":"GREEN/RED/AMBER", + "state" : "SOLID/BLINKING" + }, + "FANTRAY2":{ + "color":"GREEN/RED/AMBER", + "state" : "SOLID/BLINKING" + } + }, + + + """ + + + + load_platform_sysledutil(json_config_data) + for key in json_config_data: + for x in range(json_config_data['PLATFORM']['num_fans']): + index = x+1 + color = json_test_data[key]['SYSLED']['FANTRAY']['FANTRAY'+str(index)]['color'] + state = json_test_data[key]['SYSLED']['FANTRAY']['FANTRAY'+str(index)]['state'] + platform_sysledutil.set_status_led('fantray', index, color, state) + assert platform_sysledutil.get_status_led('fantray', index) == state,\ + "fantray"+str(index)+" sys led color is fail to changed, status = {}".format(get_status_led('fantray', index)) + +def test_for_set_psu_sysled(json_config_data, json_test_data): + """Test Purpose: Verify that the SYS PSU LED is able to set per the color and state + defined in the test config JSON + + + Args: + arg1 (json): platform--config.json + arg2 (json): test--config.json + + Example: + SYSLED Color state setting for the FANTRAY configured in the test--config.json + + + "SYSLED": + { + "PSU":{ + "PSU1":{ + "color":"GREEN/RED/AMBER", + "state" : "SOLID/BLINKING" + }, + "PSU2":{ + "color":"GREEN/RED/AMBER", + "state" : "SOLID/BLINKING" + } + }, + + + """ + + + load_platform_sysledutil(json_config_data) + for key in json_config_data: + for x in range(json_config_data['PLATFORM']['num_psus']): + index = x+1 + color = json_test_data[key]['SYSLED']['PSU']['PSU'+str(index)]['color'] + state = json_test_data[key]['SYSLED']['PSU']['PSU'+str(index)]['state'] + platform_sysledutil.set_status_led('psu', index, color, state) + assert platform_sysledutil.get_status_led('psu', index) == state,\ + "psu"+str(index)+" sys led color is fail to changed, status = {}".format(get_status_led('psu', index)) + + +def test_for_set_sys_sysled(json_config_data, json_test_data): + """Test Purpose: Verify that the SYS LED is able to set per the color and stated + defined in the test config JSON + + Args: + arg1 (json): platform--config.json + arg2 (json): test--config.json + + Example: + SYSLED Color state setting configured in the test--config.json + + "SYSLED": + { + "SYS":{ + "color":"GREEN/RED/AMBER", + "state" : "SOLID/BLINKING" + }, + + + """ + load_platform_sysledutil(json_config_data) + for key in json_config_data: + color = json_test_data[key]['SYSLED']['SYS']['color'] + state = json_test_data[key]['SYSLED']['SYS']['state'] + index = 0 + platform_sysledutil.set_status_led('sys', index, color, state) + + assert platform_sysledutil.get_status_led('sys', index) == state,\ + "fan"+str(index)+" sys led color is fail to changed, status = {}".format(get_status_led('sys', index)) + + +def test_for_set_loc_sysled(json_config_data, json_test_data): + + """Test Purpose: Verify that the SYS LOC LED is able to set per the color and state + defined in the test config JSON + + Args: + arg1 (json): platform--config.json + arg2 (json): test--config.json + + Example: + SYS LOC LED Color state setting configured in the test--config.json + + + "SYSLED": + { + "LOC":{ + "color":"GREEN/RED/AMBER", + "state" : "SOLID/BLINKING" + } + + + """ + + load_platform_sysledutil(json_config_data) + for key in json_config_data: + color = json_test_data[key]['SYSLED']['LOC']['color'] + state = json_test_data[key]['SYSLED']['LOC']['state'] + index = 0 + platform_sysledutil.set_status_led('loc', index, color, state) + + assert platform_sysledutil.get_status_led('loc', index) == state,\ + "fan"+str(index)+" sys led color is fail to changed, status = {}".format(get_status_led('sys', index)) + + + diff --git a/sonic-pde-tests/sonic_pde_tests/test_os.py b/sonic-pde-tests/sonic_pde_tests/test_os.py new file mode 100644 index 0000000..bc52b9e --- /dev/null +++ b/sonic-pde-tests/sonic_pde_tests/test_os.py @@ -0,0 +1,192 @@ +#!/usr/bin/python + +try: + import pytest + import json + import time + import os + import sys + import subprocess +except ImportError as e: + raise ImportError("%s - required module not found" % str(e)) + +# Global platform specific service port +service_port = None + +# Init platform specific service port +def init_service_port(json_config_data): + global service_port + + if service_port is not None: + return service_port + + service_port = json_config_data["PLATFORM"].get("serviceport") + if service_port is None: + service_port = "eth0" + + return service_port + +def test_for_service_port_presence(json_config_data): + """Test Purpose: Verify that if the service port is present on the DUT + + Args: + arg1 (json): platform--config.json + + Example: + For a system that physically supports 1 service port + + platform--config.json + { + "PLATFORM": { + "num_serviceports": 1, + "serviceport": "eth0" + } + } + """ + init_service_port(json_config_data) + path = "/sys/class/net/" + service_port + assert os.path.isdir(path), service_port + ": no such device" + return + +def test_for_service_port_dhcp(json_config_data): + """Test Purpose: Verify that if the service port is able to obtain IP address via DHCP + + Args: + arg1 (json): platform--config.json + + Example: + For a system that physically supports 1 service port + + platform--config.json + { + "PLATFORM": { + "num_serviceports": 1, + "serviceport": "eth0" + } + } + """ + init_service_port(json_config_data) + # This is for test only, the IP of the interafce will not be changed + # As the udhcpc script is not available in PDE docker, and it's intentional + cmd = "busybox udhcpc -i " + service_port + ret = subprocess.call(cmd + " > /dev/null 2>&1", shell=True) + assert ret == 0, service_port + ": Unable to acquire DHCP address" + return + +def test_for_flooding_dmesg(json_test_data): + """Test Purpose: Verify that if the flooding dmesg message detected + + Args: + arg1 (json): test--config.json + + Example: + To scan for the flooding dmesg message by keywords: error, i2c, usb, pci + + test--config.json + { + "PLATFORM": { + "OS": + { + "flooding": { + "dmesg": [ + "error", + "i2c", + "usb", + "pci" + ] + } + } + } + } + """ + cp1 = [] + cp2 = [] + pat = json_test_data["PLATFORM"]["OS"]["flooding"]["dmesg"] + # sampling pattern counts - start point + for idx in range(len(pat)): + cmd = "dmesg | grep -c -i " + pat[idx] + pin = subprocess.Popen(cmd, + shell=True, + close_fds=True, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + cnt = pin.communicate()[0] + cp1.append(int(cnt)) + + # sampling period + time.sleep(3) + + # sampling pattern counts - end point + for idx in range(len(pat)): + cmd = "dmesg | grep -c -i " + pat[idx] + pin = subprocess.Popen(cmd, + shell=True, + close_fds=True, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + cnt = pin.communicate()[0] + cp2.append(int(cnt)) + + for idx in range(len(pat)): + assert cp2[idx] == cp1[idx], "flooding dmesg [" + pat[idx] + "] detected" + + return + +def test_for_flooding_syslog(json_test_data): + """Test Purpose: Verify that if the flooding syslog message detected + + Args: + arg1 (json): test--config.json + + Example: + To scan for the flooding syslog message by keywords: error, i2c, usb, pci + + test--config.json + { + "PLATFORM": { + "OS": + { + "flooding": { + "syslog": [ + "error", + "i2c", + "usb", + "pci" + ] + } + } + } + } + """ + cp1 = [] + cp2 = [] + pat = json_test_data["PLATFORM"]["OS"]["flooding"]["syslog"] + # sampling pattern counts - start point + for idx in range(len(pat)): + cmd = "cat /var/log/syslog | grep -c -i " + pat[idx] + pin = subprocess.Popen(cmd, + shell=True, + close_fds=True, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + cnt = pin.communicate()[0] + cp1.append(int(cnt)) + + # sampling period + time.sleep(3) + + # sampling pattern counts - end point + for idx in range(len(pat)): + cmd = "cat /var/log/syslog | grep -c -i " + pat[idx] + pin = subprocess.Popen(cmd, + shell=True, + close_fds=True, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + cnt = pin.communicate()[0] + cp2.append(int(cnt)) + + for idx in range(len(pat)): + assert cp2[idx] == cp1[idx], "flooding syslog [" + pat[idx] + "] detected" + + return diff --git a/sonic-pde-tests/sonic_pde_tests/test_platform.py b/sonic-pde-tests/sonic_pde_tests/test_platform.py new file mode 100644 index 0000000..ce613df --- /dev/null +++ b/sonic-pde-tests/sonic_pde_tests/test_platform.py @@ -0,0 +1,578 @@ +try: + import pytest + import json + import time + import os + import imp + import sys + import subprocess +except ImportError as e: + raise ImportError("%s - required module not found" % str(e)) + + +# Get Proc module info +PLATFORM_PATH = "/proc/modules" + + +def get_proc_module_info(): + file = open(PLATFORM_PATH, "r") + str = file.read() + file.close() + return str + +def getMacAddress(ifname): + ETHERNET_PATH = "/sys/class/net/"+ifname+"/address" + file = open(ETHERNET_PATH, "r") + macaddr= file.read().strip() + file.close + return macaddr + +def driver_unload(driver_name): + cmd = "rmmod "+ driver_name + os.system(cmd) + +def driver_load(driver_name): + cmd = "modprobe "+ driver_name + os.system(cmd) + + +def test_for_cpld_driver_loading(json_config_data): + + """Test Purpose: Verify that the cpld driver defined in platform config JSON + is successfully loaded in PDE + + Args: + arg1 (json): platform--config.json + + Example: + + "drivers": { + "CPLD": { + "driver_info": { + "support": "true", + "type": "ODM", + "name": "xxxx" + } + }, + } + + """ + + if json_config_data['PLATFORM']['drivers']['CPLD']['driver_info']['support'] == "false": + pytest.skip("Skip the testing due to the driver not supported") + + module_info = get_proc_module_info() + cpld_driver_name = json_config_data['PLATFORM']['drivers']['CPLD']['driver_info']['name'] + + assert module_info.find(cpld_driver_name) >= 0, \ + "Find {} driver is not loading".format(cpld_driver_name) + +def test_for_psu_driver_loading(json_config_data): + + """Test Purpose: Verify that the PSU driver defined in platform config JSON + is successfully loaded in PDE + + Args: + arg1 (json): platform--config.json + + Example: + + "drivers": { + "PSU": { + "driver_info": { + "support": "true", + "type": "ODM", + "name": "xxxx" + } + }, + } + + """ + + if json_config_data['PLATFORM']['drivers']['PSU']['driver_info']['support'] == "false": + pytest.skip("Skip the testing due to the driver not supported") + + module_info = get_proc_module_info() + psu_driver_name = json_config_data['PLATFORM']['drivers']['PSU']['driver_info']['name'] + + assert module_info.find(psu_driver_name) >= 0, \ + "Find {} driver is not loading successfully".format(psu_driver_name) + +def test_for_psu_driver_unloading(json_config_data): + + """Test Purpose: Verify that the PSU driver defined in platform config JSON + is successfully UNloaded in PDE + + Args: + arg1 (json): platform--config.json + + Example: + + "drivers": { + "PSU": { + "driver_info": { + "support": "true", + "type": "ODM", + "name": "xxxx" + } + }, + } + + """ + + if json_config_data['PLATFORM']['drivers']['PSU']['driver_info']['support'] == "false": + pytest.skip("Skip the testing due to the driver not supported") + + psu_driver_name = json_config_data['PLATFORM']['drivers']['PSU']['driver_info']['name'] + if get_proc_module_info().find(psu_driver_name) < 0: + pytest.skip("Skip the testing due to the driver not loading") + + driver_unload(psu_driver_name) + module_info = get_proc_module_info() + + if module_info.find(psu_driver_name) < 0: + driver_load(psu_driver_name) + + assert module_info.find(psu_driver_name) < 0, \ + "Find {} driver is not unloading successfully".format(psu_driver_name) + + +def test_for_fan_driver_loading(json_config_data): + + """Test Purpose: Verify that the FAN driver defined in platform config JSON + is successfully loaded in PDE + + Args: + arg1 (json): platform--config.json + + Example: + + "drivers": { + "FAN": { + "driver_info": { + "support": "true", + "type": "ODM", + "name": "xxxx" + } + }, + } + + """ + + if json_config_data['PLATFORM']['drivers']['FAN']['driver_info']['support'] == "false": + pytest.skip("Skip the testing due to the driver not supported") + + module_info = get_proc_module_info() + fan_driver_name = json_config_data['PLATFORM']['drivers']['FAN']['driver_info']['name'] + + assert module_info.find(fan_driver_name) >= 0, \ + "Find {} driver is not loading".format(fan_driver_name) + +def test_for_fan_driver_unloading(json_config_data): + + """Test Purpose: Verify that the FAN driver defined in platform config JSON + is successfully unloaded in PDE + + Args: + arg1 (json): platform--config.json + + Example: + + "drivers": { + "FAN": { + "driver_info": { + "support": "true", + "type": "ODM", + "name": "xxxx" + } + }, + } + + """ + + if json_config_data['PLATFORM']['drivers']['FAN']['driver_info']['support'] == "false": + pytest.skip("Skip the testing due to the driver not supported") + + fan_driver_name = json_config_data['PLATFORM']['drivers']['FAN']['driver_info']['name'] + if get_proc_module_info().find(fan_driver_name) < 0: + pytest.skip("Skip the testing due to the driver not loading") + + driver_unload(fan_driver_name) + module_info = get_proc_module_info() + + if module_info.find(fan_driver_name) < 0: + driver_load(fan_driver_name) + + assert module_info.find(fan_driver_name) < 0, \ + "Find {} driver is not unloading successfully".format(fan_driver_name) + + +def test_for_sfp_driver_loading(json_config_data): + + """Test Purpose: Verify that the sfp driver defined in platform config JSON + is successfully loaded in PDE + + Args: + arg1 (json): platform--config.json + + Example: + + "drivers": { + "SFP": { + "driver_info": { + "support": "true", + "type": "ODM", + "name": "xxxx" + } + }, + } + + """ + + if json_config_data['PLATFORM']['drivers']['SFP']['driver_info']['support'] == "false": + pytest.skip("Skip the testing due to the driver not supported") + + module_info = get_proc_module_info() + sfp_driver_name = json_config_data['PLATFORM']['drivers']['SFP']['driver_info']['name'] + + assert module_info.find(sfp_driver_name) >= 0, \ + "Find {} driver is not loading".format(sfp_driver_name) + + +def test_for_sfp_driver_unloading(json_config_data): + + """Test Purpose: Verify that the sfp driver defined in platform config JSON + is successfully unloaded in PDE + + Args: + arg1 (json): platform--config.json + + Example: + + "drivers": { + "SFP": { + "driver_info": { + "support": "true", + "type": "ODM", + "name": "xxxx" + } + }, + } + + """ + + if json_config_data['PLATFORM']['drivers']['SFP']['driver_info']['support'] == "false": + pytest.skip("Skip the testing due to the driver not supported") + + sfp_driver_name = json_config_data['PLATFORM']['drivers']['SFP']['driver_info']['name'] + if get_proc_module_info().find(sfp_driver_name) < 0: + pytest.skip("Skip the testing due to the driver not loading") + + driver_unload(sfp_driver_name) + module_info = get_proc_module_info() + + if module_info.find(sfp_driver_name) < 0: + driver_load(sfp_driver_name) + + assert module_info.find(sfp_driver_name) < 0, \ + "Find {} driver is not unloading successfully".format(sfp_driver_name) + + + +def test_for_temp_driver_loading(json_config_data): + + """Test Purpose: Verify that the temperature sensor driver defined in platform config JSON + is successfully loaded in PDE + + Args: + arg1 (json): platform--config.json + + Example: + + "drivers": { + "TEMP": { + "driver_info": { + "support": "true", + "type": "ODM", + "name": "xxxx" + } + }, + } + + """ + + if json_config_data['PLATFORM']['drivers']['TEMP']['driver_info']['support'] == "false": + pytest.skip("Skip the testing due to the driver not supported") + + module_info = get_proc_module_info() + temp_driver_name = json_config_data['PLATFORM']['drivers']['TEMP']['driver_info']['name'] + + assert module_info.find(temp_driver_name) >= 0, \ + "Find {} driver is not loading".format(temp_driver_name) + + +def test_for_temp_driver_unloading(json_config_data): + + """Test Purpose: Verify that the temperature driver defined in platform config JSON + is successfully unloaded in PDE + + Args: + arg1 (json): platform--config.json + + Example: + + "drivers": { + "TEMP": { + "driver_info": { + "support": "true", + "type": "ODM", + "name": "xxxx" + } + }, + } + + """ + + if json_config_data['PLATFORM']['drivers']['TEMP']['driver_info']['support'] == "false": + pytest.skip("Skip the testing due to the driver not supported") + + temp_driver_name = json_config_data['PLATFORM']['drivers']['TEMP']['driver_info']['name'] + if get_proc_module_info().find(temp_driver_name) < 0: + pytest.skip("Skip the testing due to the driver not loading") + + driver_unload(temp_driver_name) + module_info = get_proc_module_info() + + if module_info.find(temp_driver_name) < 0: + driver_load(temp_driver_name) + + assert module_info.find(temp_driver_name) < 0, \ + "Find {} driver is not unloading successfully".format(temp_driver_name) + + + +def test_for_led_driver_loading(json_config_data): + + """Test Purpose: Verify that the SYSLED driver defined in platform config JSON + is successfully loaded in PDE + + Args: + arg1 (json): platform--config.json + + Example: + + "drivers": { + "SYSLED": { + "driver_info": { + "support": "true", + "type": "ODM", + "name": "xxxx" + } + }, + } + + """ + + if json_config_data['PLATFORM']['drivers']['SYSLED']['driver_info']['support'] == "false": + pytest.skip("Skip the testing due to the driver not supported") + + module_info = get_proc_module_info() + led_driver_name = json_config_data['PLATFORM']['drivers']['SYSLED']['driver_info']['name'] + + assert module_info.find(led_driver_name) >= 0, \ + "Find {} driver is not loading".format(led_driver_name) + + + +def test_for_led_driver_unloading(json_config_data): + + """Test Purpose: Verify that the SYSLED driver defined in platform config JSON + is successfully loaded in PDE + + Args: + arg1 (json): platform--config.json + + Example: + + "drivers": { + "SYSLED": { + "driver_info": { + "support": "true", + "type": "ODM", + "name": "xxxx" + } + }, + } + + """ + + if json_config_data['PLATFORM']['drivers']['SYSLED']['driver_info']['support'] == "false": + pytest.skip("Skip the testing due to the driver not supported") + + led_driver_name = json_config_data['PLATFORM']['drivers']['SYSLED']['driver_info']['name'] + if get_proc_module_info().find(led_driver_name) < 0: + pytest.skip("Skip the testing due to the driver not loading") + + driver_unload(led_driver_name) + module_info = get_proc_module_info() + + if module_info.find(led_driver_name) < 0: + driver_load(led_driver_name) + + assert module_info.find(led_driver_name) < 0, \ + "Find {} driver is not unloading successfully".format(led_driver_name) + + + +def test_for_eeprom_driver_loading(json_config_data): + + """Test Purpose: Verify that the EEPROM driver defined in platform config JSON + is successfully loaded in PDE + + Args: + arg1 (json): platform--config.json + + Example: + + "drivers": { + "EEPROM": { + "driver_info": { + "support": "true", + "type": "ODM", + "name": "xxxx" + } + }, + } + + """ + + if json_config_data['PLATFORM']['drivers']['EEPROM']['driver_info']['support'] == "false": + pytest.skip("Skip the testing due to the driver not supported") + + module_info = get_proc_module_info() + eeprom_driver_name = json_config_data['PLATFORM']['drivers']['EEPROM']['driver_info']['name'] + + assert module_info.find(eeprom_driver_name) >= 0, \ + "Find {} driver is not loading".format(eeprom_driver_name) + + +def test_for_eeprom_driver_unloading(json_config_data): + + """Test Purpose: Verify that the EEPROM driver defined in platform config JSON + is successfully unloaded in PDE + + Args: + arg1 (json): platform--config.json + + Example: + + "drivers": { + "EEPROM": { + "driver_info": { + "support": "true", + "type": "ODM", + "name": "xxxx" + } + }, + } + + """ + + if json_config_data['PLATFORM']['drivers']['EEPROM']['driver_info']['support'] == "false": + pytest.skip("Skip the testing due to the driver not supported") + + eeprom_driver_name = json_config_data['PLATFORM']['drivers']['EEPROM']['driver_info']['name'] + if get_proc_module_info().find(eeprom_driver_name) < 0: + pytest.skip("Skip the testing due to the driver not loading") + + driver_unload(eeprom_driver_name) + module_info = get_proc_module_info() + + if module_info.find(eeprom_driver_name) < 0: + driver_load(eeprom_driver_name) + + assert module_info.find(eeprom_driver_name) < 0, \ + "Find {} driver is not unloading successfully".format(eeprom_driver_name) + + + +def test_for_mac_driver_loading(json_config_data): + + """Test Purpose: Verify that the MAC driver defined in platform config JSON + is successfully loaded in PDE + + Args: + arg1 (json): platform--config.json + + Example: + + "drivers": { + "MAC": { + "driver_info": { + "support": "true", + "type": "ODM", + "name": "xxxx" + } + }, + } + + """ + + if json_config_data['PLATFORM']['drivers']['MAC']['driver_info']['support'] == "false": + pytest.skip("Skip the testing due to the driver not supported") + + module_info = get_proc_module_info() + mac_driver_name = json_config_data['PLATFORM']['drivers']['MAC']['driver_info']['name'] + + assert module_info.find(mac_driver_name) >= 0, \ + "Find {} driver is not loading".format(mac_driver_name) + +def test_for_mac_driver_unloading(json_config_data): + + """Test Purpose: Verify that the MAC driver defined in platform config JSON + is successfully unloaded in PDE + + Args: + arg1 (json): platform--config.json + + Example: + + "drivers": { + "MAC": { + "driver_info": { + "support": "true", + "type": "ODM", + "name": "xxxx" + } + }, + } + + """ + + if json_config_data['PLATFORM']['drivers']['MAC']['driver_info']['support'] == "false": + pytest.skip("Skip the testing due to the driver not supported") + + mac_driver_name = json_config_data['PLATFORM']['drivers']['MAC']['driver_info']['name'] + if get_proc_module_info().find(mac_driver_name) < 0: + pytest.skip("Skip the testing due to the driver not loading") + + driver_unload(mac_driver_name) + module_info = get_proc_module_info() + + if module_info.find(mac_driver_name) < 0: + driver_load(mac_driver_name) + + assert module_info.find(mac_driver_name) < 0, \ + "Find {} driver is not unloading successfully".format(mac_driver_name) + + +def test_for_ethernet_mac_address(json_config_data,json_test_data): + + for key in json_config_data: + for x in range(json_config_data[key]['num_serviceports']): + ifname = json_test_data[key]['MAC']['MAC'+str(x+1)]['ifname'] + assert getMacAddress(ifname) == json_test_data['PLATFORM']['MAC']['MAC'+str(x+1)]['macaddr'], \ + "Service MAC address {} not matching with JSON configuration".format(getMacAddress(ifname)) + + + diff --git a/sonic-pde-tests/sonic_pde_tests/test_port.py b/sonic-pde-tests/sonic_pde_tests/test_port.py new file mode 100644 index 0000000..5217f05 --- /dev/null +++ b/sonic-pde-tests/sonic_pde_tests/test_port.py @@ -0,0 +1,11 @@ +import pytest +import sys +import imp + + +def test_for_port(json_config_data): + pytest.skip("Not supported") + +if __name__ == '__main__': + unittest.main() + diff --git a/sonic-pde-tests/sonic_pde_tests/test_psu.py b/sonic-pde-tests/sonic_pde_tests/test_psu.py new file mode 100644 index 0000000..01b057d --- /dev/null +++ b/sonic-pde-tests/sonic_pde_tests/test_psu.py @@ -0,0 +1,353 @@ +import pytest +import sys +import imp +import subprocess +import time + +PLATFORM_PATH = "/usr/share/sonic/platform" +PLATFORM_SPECIFIC_MODULE_NAME = "psuutil" +PLATFORM_SPECIFIC_CLASS_NAME = "PsuUtil" + +platform_psuutil = None +platform_chassis = None + +# Loads platform specific module from source +def _wrapper_init(): + global platform_psuutil + global platform_chassis + + # Load new platform api class + if platform_chassis is None: + try: + import sonic_platform.platform + platform_chassis = sonic_platform.platform.Platform().get_chassis() + except Exception as e: + print("Failed to load chassis due to {}".format(repr(e))) + + # Load platform-specific psuutil class + if platform_chassis is None: + try: + module_file = "/".join([PLATFORM_PATH, "plugins", PLATFORM_SPECIFIC_MODULE_NAME + ".py"]) + module = imp.load_source(PLATFORM_SPECIFIC_MODULE_NAME, module_file) + platform_psuutil_class = getattr(module, PLATFORM_SPECIFIC_CLASS_NAME) + platform_psuutil = platform_psuutil_class() + except Exception as e: + print("Failed to load psuutil due to {}".format(repr(e))) + + assert (platform_chassis is not None) or (platform_psuutil is not None), "Unable to load platform module" + +# wrappers that are compliable with both new platform api and old-style plugin +def _wrapper_get_num_psus(): + _wrapper_init() + if platform_chassis is not None: + try: + return platform_chassis.get_num_psus() + except NotImplementedError: + pass + return platform_psuutil.get_num_psus() + +def _wrapper_get_psus_presence(psu_index): + _wrapper_init() + if platform_chassis is not None: + try: + return platform_chassis.get_psu(psu_index).get_presence() + except NotImplementedError: + pass + return platform_psuutil.get_psu_presence(psu_index+1) + +def _wrapper_get_psus_status(psu_index): + _wrapper_init() + if platform_chassis is not None: + try: + return platform_chassis.get_psu(psu_index).get_powergood_status() + except NotImplementedError: + pass + return platform_psuutil.get_psu_status(psu_index+1) + +def _wrapper_get_psus_serial(psu_index): + _wrapper_init() + if platform_chassis is not None: + try: + return platform_chassis.get_psu(psu_index).get_serial() + except NotImplementedError: + pass + return platform_psuutil.get_serial(psu_index+1) + +def _wrapper_get_psus_model(psu_index): + _wrapper_init() + if platform_chassis is not None: + try: + return platform_chassis.get_psu(psu_index).get_model() + except NotImplementedError: + pass + return platform_psuutil.get_model(psu_index+1) + +def _wrapper_get_psus_power(psu_index): + _wrapper_init() + if platform_chassis is not None: + try: + return platform_chassis.get_psu(psu_index).get_power() + except NotImplementedError: + pass + return platform_psuutil.get_output_power(psu_index+1) + +def _wrapper_get_psus_current(psu_index): + _wrapper_init() + if platform_chassis is not None: + try: + return platform_chassis.get_psu(psu_index).get_current() + except NotImplementedError: + pass + return platform_psuutil.get_output_current(psu_index+1) + +def _wrapper_get_psus_voltage(psu_index): + _wrapper_init() + if platform_chassis is not None: + try: + return platform_chassis.get_psu(psu_index).get_voltage() + except NotImplementedError: + pass + return platform_psuutil.get_output_voltage(psu_index+1) + + + + +def test_for_num_psus(json_config_data): + """Test Purpose: Verify that the numer of PSUs reported as supported by the PSU plugin matches what the platform supports. + + Args: + arg1 (json): platform--config.json + + Example: + For a system that physically supports 2 power supplies + + platform--config.json + { + "PLATFORM": { + "num_psus": 2 + } + } + """ + assert _wrapper_get_num_psus() == json_config_data['PLATFORM']['num_psus'],"System plugin reports that {} PSUs are supported in platform".format(platform_psuutil.get_num_psus()) + +def test_for_psu_present(json_config_data, json_test_data): + """Test Purpose: Test Purpose: Verify that the PSUs that are present report as present in the PSU plugin. + + Args: + arg1 (json): platform--config.json + arg2 (json): test--config.json + + Example: + For a system that has 2 power supplies present + + test--config.json + { + "PLATFORM": { + "PSU": { + "present": [ + 1, + 2 + ], + } + } + } + + """ + for key in json_config_data: + psupresentlist = json_test_data[key]['PSU']['present'] + for x in psupresentlist: + assert _wrapper_get_psus_presence(x-1) == True, "System plugin reported PSU {} was not present".format(x) + +def test_for_psu_notpresent(json_config_data, json_test_data): + """Test Purpose: Verify that the PSUs that are not present report as not present in the PSU plugin. + + Args: + arg1 (json): platform--config.json + arg2 (json): test--config.json + + Example: + For a system that only has power supply 2 present + + { + "PLATFORM": { + "PSU": { + "present": [ + 2 + ] + } + } + } + + """ + num_psus = _wrapper_get_num_psus() + for key in json_config_data: + for x in range (1, num_psus): + if _wrapper_get_psus_presence(x-1) == True: + Found = False; + for y in json_test_data[key]['PSU']['present']: + if x == y: + Found = True + assert (Found == True), "System plugin reported PSU {} was present".format(x) + +def test_for_psu_status(json_config_data, json_test_data): + """Test Purpose: Verify that the PSUs that are not present report proper status (True if operating properly, False if not operating properly) + + Args: + arg1 (json): platform--config.json + arg2 (json): test--config.json + + Example: + For a system that only has power supply 2 present and both are operating properly + + test--config.json + { + "PLATFORM": { + "PSU": { + "present": [ + 1, + 2 + ], + "status": [ + true, + true + ] + } + } + + """ + for key in json_config_data: + psupresentlist = json_test_data[key]['PSU']['present'] + for x in psupresentlist: + assert _wrapper_get_psus_status(x-1) == json_test_data[key]['PSU']['status'][x-1], "System plugin reported PSU {} state did not match test state {}".format(x, json_test_data[key]['PSU']['status']) + + + +def test_for_psu_serial_num(json_config_data, json_test_data): + """Test Purpose: Verify that the PSUs serial num is valid + + Args: + arg1 (json): platform--config.json + arg2 (json): test--config.json + + Example: + For a system that only has power supply 1 present + + test--config.json + { + "PLATFORM": { + "PSU1": { + "psu_serial_num": "AAAA" + } + """ + if json_config_data['PLATFORM']['modules']['PSU']['support'] == "false": + pytest.skip("Skip the testing due to the openconfig API in python module is not supported in BSP") + + + for key in json_config_data: + psupresentlist = json_test_data[key]['PSU']['present'] + for x in psupresentlist: + if _wrapper_get_psus_status(x-1) : + assert _wrapper_get_psus_serial(x-1) == json_test_data[key]['PSU']['PSU'+str(x)]['psu_serial_num'], \ + "Verify PSU{} Serail number is invalid".format(x, _wrapper_get_psus_serial(x-1)) + + +def test_for_psu_model(json_config_data, json_test_data): + """Test Purpose: Verify that the PSUs Model is valid + + Args: + arg1 (json): platform--config.json + arg2 (json): test--config.json + + Example: + For a system that only has power supply 1 present + + test--config.json + { + "PLATFORM": { + "PSU1": { + "model":"R17-1K6P1AA", + } + """ + + if json_config_data['PLATFORM']['modules']['PSU']['support'] == "false": + pytest.skip("Skip the testing due to the openconfig API in python module is not supported in BSP") + + for key in json_config_data: + psupresentlist = json_test_data[key]['PSU']['present'] + for x in psupresentlist: + if _wrapper_get_psus_status(x-1): + assert _wrapper_get_psus_model(x-1) == json_test_data[key]['PSU']['PSU'+str(x)]['model'], \ + "Verify PSU{} Model ID is invalid".format(x, _wrapper_get_psus_model(x-1)) + +def test_for_psu_voltage(json_config_data, json_test_data): + """Test Purpose: Verify that the PSUs Output voltage is valid + + Args: + arg1 (json): platform--config.json + arg2 (json): test--config.json + + Example: + For a system that only has power supply 1 present + + test--config.json + { + "PLATFORM": { + "PSU1": { + "output_voltage":"12000" + } + """ + + if json_config_data['PLATFORM']['modules']['PSU']['support'] == "false": + pytest.skip("Skip the testing due to the openconfig API in python module is not supported in BSP") + + for key in json_config_data: + psupresentlist = json_test_data[key]['PSU']['present'] + for x in psupresentlist: + if _wrapper_get_psus_status(x-1): + assert _wrapper_get_psus_voltage(x-1) <= json_test_data[key]['PSU']['PSU'+str(x)]['output_voltage'] * 1.1, \ + "Verify PSU{} Output voltage is invalid too high".format(x, _wrapper_get_psus_voltage(x-1)) + + assert _wrapper_get_psus_voltage(x-1) >= json_test_data[key]['PSU']['PSU'+str(x)]['output_voltage'] * 0.9, \ + "Verify PSU{} Output voltage is invalid too low".format(x, _wrapper_get_psus_voltage(x-1)) + + +def test_for_psu_current(json_config_data, json_test_data): + """Test Purpose: Verify that the PSUs output current is able to read + + Args: + arg1 (json): platform--config.json + arg2 (json): test--config.json + + """ + + if json_config_data['PLATFORM']['modules']['PSU']['support'] == "false": + pytest.skip("Skip the testing due to the openconfig API in python module is not supported in BSP") + + for key in json_config_data: + psupresentlist = json_test_data[key]['PSU']['present'] + for x in psupresentlist: + if _wrapper_get_psus_status(x-1): + assert _wrapper_get_psus_current(x-1), \ + "Verify PSU{} output current is fail to read".format(x, _wrapper_get_psus_current(x-1)) + + +def test_for_psu_power(json_config_data, json_test_data): + """Test Purpose: Verify that the PSUs output Power is able to read + + Args: + arg1 (json): platform--config.json + arg2 (json): test--config.json + + """ + + if json_config_data['PLATFORM']['modules']['PSU']['support'] == "false": + pytest.skip("Skip the testing due to the openconfig API in python module is not supported in BSP") + + for key in json_config_data: + psupresentlist = json_test_data[key]['PSU']['present'] + for x in psupresentlist: + if _wrapper_get_psus_status(x-1): + assert _wrapper_get_psus_power(x-1), \ + "Verify PSU{} output power is fail to read".format(x, _wrapper_get_psus_power(x-1)) + + diff --git a/sonic-pde-tests/sonic_pde_tests/test_rtc.py b/sonic-pde-tests/sonic_pde_tests/test_rtc.py new file mode 100644 index 0000000..1a792ea --- /dev/null +++ b/sonic-pde-tests/sonic_pde_tests/test_rtc.py @@ -0,0 +1,30 @@ +#!/usr/bin/python + +try: + import pytest + import sys + import subprocess +except ImportError as e: + raise ImportError("%s - required module not found" % str(e)) + +# Test for RTC read +def test_for_rtc_read(): + """Test Purpose: Verify that if the RTC is readable on the DUT + + Args: + None + """ + rc = subprocess.call("hwclock > /dev/null 2>&1", shell=True) + assert rc == 0, "RTC read failed" + return + +# Test for RTC write +def test_for_rtc_write(): + """Test Purpose: Verify that if the RTC is writable on the DUT + + Args: + None + """ + rc = subprocess.call("hwclock -w > /dev/null 2>&1", shell=True) + assert rc == 0, "RTC write failed" + return diff --git a/sonic-pde-tests/sonic_pde_tests/test_sai.py b/sonic-pde-tests/sonic_pde_tests/test_sai.py new file mode 100644 index 0000000..02edfb2 --- /dev/null +++ b/sonic-pde-tests/sonic_pde_tests/test_sai.py @@ -0,0 +1,273 @@ +#!/usr/bin/python + +import sys +import time +import pytest +import subprocess +import os.path + +import saiut + +PLATFORM_PATH = "/usr/share/sonic/platform" +HWSKU_PATH = "/usr/share/sonic/hwsku" + +# Global switch core initialization flag +core_init = False + +# Global port dictionaries +port_dict = None + +# Load the platform specific port dictionaries +def load_platform_portdict(): + global port_dict + + if port_dict is not None: + return port_dict + + port_dict = {} + file = open(HWSKU_PATH + '/port_config.ini', 'r') + line = file.readline() + while line is not None and len(line) > 0: + line = line.strip() + if not line.startswith("#"): + lst = line.split() + if len(lst) >= 2: + key = lst[0]; + val = int(lst[1].split(',')[0], 10) + port_dict[key] = val + line = file.readline() + file.close() + + return port_dict + +# Reload the platform specific port dictionaries +def reload_platform_portdict(): + global port_dict + + port_dict = None + return load_platform_portdict() + +# Start the switch core +def start_switch_core(): + global core_init + + rv = saiut.SAI_STATUS_SUCCESS + if core_init: + return rv + + rv = saiut.switchInitialize("00:11:22:33:44:55") + if rv != saiut.SAI_STATUS_SUCCESS: + return rv + + core_init = True + if os.path.exists(PLATFORM_PATH + '/led_proc_init.soc'): + saiut.bcmDiagCommand('rcload ' + PLATFORM_PATH + '/led_proc_init.soc') + return rv + +# Stop the switch core +def stop_switch_core(): + global core_init + + saiut.switchShutdown() + core_init = False + return saiut.SAI_STATUS_SUCCESS + +# Test for switch port enumeration +def test_for_switch_port_enumeration(): + """ + Test Purpose: + Verify the SONiC port enumeration to ensure all the SONiC ports + are mapped to SAI ports with valid object ids + + Args: + None + """ + rv = load_platform_portdict() + assert rv is not None, "Unable to load the port dictionary" + + rv = start_switch_core() + assert rv == saiut.SAI_STATUS_SUCCESS, "Unable to initialize the switch" + + for key in port_dict: + port = saiut.portGetId(port_dict[key]) + assert port != 0, "{}: port id not found".format(key) + return + +# Test for switch port traffic +def test_for_switch_port_traffic(json_test_data): + """ + Test Purpose: Verify the per port packet transmission + + Args: + arg1 (json): test--config.json + + Example: + For a system with 2 back-to-back self-loops + + test--config.json + { + "PLATFORM": { + "SELF_LOOPS" : [ + "Ethernet0:Ethernet24", + "Ethernet4:Ethernet28" + ] + } + } + """ + try: + lnks = json_test_data['PLATFORM']['SELF_LOOPS'] + except KeyError: + pytest.skip("test configuration not found") + + rv = load_platform_portdict() + assert rv is not None, "Unable to load the port dictionary" + + rv = start_switch_core() + assert rv == saiut.SAI_STATUS_SUCCESS, "Unable to initialize the switch" + + # Enable all the switch ports + for key in port_dict: + port = saiut.portGetId(port_dict[key]) + assert port != 0, "{}: port id not found".format(key) + saiut.portSetAdminState(port, True) + time.sleep(3) + + lnks = json_test_data['PLATFORM']['SELF_LOOPS'] + for idx in range(0, len(lnks)): + p1 = lnks[idx].split(':')[0] + p2 = lnks[idx].split(':')[1] + pid1 = saiut.portGetId(port_dict[p1]) + pid2 = saiut.portGetId(port_dict[p2]) + + print("xmit: {} --> {}".format(p1, p2)); + saiut.portClearCounter(pid1, saiut.SAI_PORT_STAT_ETHER_OUT_PKTS_512_TO_1023_OCTETS) + saiut.portClearCounter(pid2, saiut.SAI_PORT_STAT_ETHER_IN_PKTS_512_TO_1023_OCTETS) + saiut.bcmSendPackets(pid1, 9, 512) + time.sleep(3) + c1 = saiut.portGetCounter(pid1, saiut.SAI_PORT_STAT_ETHER_OUT_PKTS_512_TO_1023_OCTETS) + c2 = saiut.portGetCounter(pid2, saiut.SAI_PORT_STAT_ETHER_IN_PKTS_512_TO_1023_OCTETS) + assert c1 >= 9, "{} --> {}: tx failed".format(p1, p2) + assert c2 >= 9, "{} --> {}: rx failed".format(p1, p2) + + print("xmit: {} <-- {}".format(p1, p2)); + saiut.portClearCounter(pid1, saiut.SAI_PORT_STAT_ETHER_IN_PKTS_512_TO_1023_OCTETS) + saiut.portClearCounter(pid2, saiut.SAI_PORT_STAT_ETHER_OUT_PKTS_512_TO_1023_OCTETS) + saiut.bcmSendPackets(pid2, 9, 512) + time.sleep(3) + c1 = saiut.portGetCounter(pid1, saiut.SAI_PORT_STAT_ETHER_IN_PKTS_512_TO_1023_OCTETS) + c2 = saiut.portGetCounter(pid2, saiut.SAI_PORT_STAT_ETHER_OUT_PKTS_512_TO_1023_OCTETS) + assert c1 >= 9, "{} <-- {}: rx failed".format(p1, p2) + assert c2 >= 9, "{} <-- {}: tx failed".format(p1, p2) + +# Test for switch port breakout modes +def test_for_switch_port_breakout(json_test_data): + """ + Test Purpose: Verify the QSFP port breakout support + + Args: + arg1 (json): test--config.json + + Example: + For a system with 2 expandable ports + + test--config.json + { + "PLATFORM": { + "PORT_BREAKOUT" : { + # port Name port modes ,, + "Ethernet128" : "1x100,4x10,4x25", + "Ethernet136" : "1x100,4x10,4x25" + } + } + } + """ + try: + intf = json_test_data['PLATFORM']['PORT_BREAKOUT'] + except KeyError: + pytest.skip("test configuration not found") + + # load key-value-pairs from sai.profile + kvp = {} + try: + file = open(HWSKU_PATH + '/sai.profile', 'r') + except: + assert False, "Unable to open sai.profile" + line = file.readline() + while line is not None and len(line) > 0: + line = line.strip() + if not line.startswith("#"): + lst = line.split('=') + if len(lst) != 2: + continue + kvp[lst[0]] = lst[1] + line = file.readline() + file.close() + + # make a backup of config.bcm and port_config.ini + file = kvp['SAI_INIT_CONFIG_FILE'] + rc = subprocess.call("cp -f {} {}.orig >/dev/null 2>&1".format(file, file), shell=True) + assert rc == 0, "Unable to make a backup of the config.bcm" + file = HWSKU_PATH + '/port_config.ini' + rc = subprocess.call("cp -f {} {}.orig >/dev/null 2>&1".format(file, file), shell=True) + assert rc == 0, "Unable to make a backup of the port_config.ini" + + # perform port breakout test + for intf in json_test_data['PLATFORM']['PORT_BREAKOUT']: + # mode = ,, + mode = json_test_data['PLATFORM']['PORT_BREAKOUT'][intf] + list = mode.split(',') + for i in range(1, len(list)): + print("port_breakout.py -p {} -o {}".format(intf, list[i])); + # root port mode + rc = subprocess.call("port_breakout.py -p {} -o {} >/dev/null 2>&1".format(intf, list[0]), shell=True) + assert rc == 0, "{}: Unable to do {}".format(intf, list[i]) + # target breakout mode + rc = subprocess.call("port_breakout.py -p {} -o {} >/dev/null 2>&1".format(intf, list[i]), shell=True) + assert rc == 0, "{}: Unable to do {}".format(intf, list[i]) + + # load sonic portmap + intf_dict = {} + file = open(HWSKU_PATH + '/port_config.ini', 'r') + line = file.readline() + while line is not None and len(line) > 0: + line = line.strip() + if line.startswith("#"): + line = file.readline() + continue + tok = line.split() + if len(tok) >= 2: + key = tok[0]; + val = int(tok[1].split(',')[0], 10) + assert key not in intf_dict, "Duplicated interface in port_config.ini" + intf_dict[key] = val + line = file.readline() + file.close() + + # load bcm portmap + brcm_dict = {} + file = open(kvp['SAI_INIT_CONFIG_FILE'], 'r') + line = file.readline() + while line is not None and len(line) > 0: + line = line.strip() + if line.startswith("#") or ("portmap_" not in line): + line = file.readline() + continue + # portmap_=:: + tok = line.split('=') + lport = int(tok[0].split('_')[1], 10) + pport = int(tok[1].split(':')[0], 10) + brcm_dict[pport] = lport + line = file.readline() + file.close() + + for port in intf_dict: + lane = intf_dict[port] + assert lane in brcm_dict, "{}: portmap not found".format(port) + + # restore the config.bcm and port_config.ini + file = kvp['SAI_INIT_CONFIG_FILE'] + rc = subprocess.call("cp -f {}.orig {} >/dev/null 2>&1".format(file, file), shell=True) + assert rc == 0, "Unable to restore the config.bcm" + file = HWSKU_PATH + '/port_config.ini' + rc = subprocess.call("cp -f {}.orig {} >/dev/null 2>&1".format(file, file), shell=True) + assert rc == 0, "Unable to restore the port_config.ini" diff --git a/sonic-pde-tests/sonic_pde_tests/test_sfp.py b/sonic-pde-tests/sonic_pde_tests/test_sfp.py new file mode 100644 index 0000000..66d6483 --- /dev/null +++ b/sonic-pde-tests/sonic_pde_tests/test_sfp.py @@ -0,0 +1,271 @@ +#!/usr/bin/env python + +try: + import pytest + import os + import sys + import subprocess + import imp + import json + from natsort import natsorted +except ImportError as e: + raise ImportError("%s - required module not found" % str(e)) + +PLATFORM_PATH = "/usr/share/sonic/platform" +PLATFORM_SPECIFIC_MODULE_NAME = "sfputil" +PLATFORM_SPECIFIC_CLASS_NAME = "SfpUtil" + +# Global platform-specific sfputil class instance +platform_sfputil = None + +# Global port dictionaries +port_dict = None + +# Loads platform specific sfputil module from source +def load_platform_sfputil(): + global platform_sfputil + + if platform_sfputil is not None: + return + + try: + module_file = "/".join([PLATFORM_PATH, "plugins", PLATFORM_SPECIFIC_MODULE_NAME + ".py"]) + module = imp.load_source(PLATFORM_SPECIFIC_MODULE_NAME, module_file) + except IOError, e: + print("Failed to load platform module '%s': %s" % (PLATFORM_SPECIFIC_MODULE_NAME, str(e)), True) + + assert module is not None + + try: + platform_sfputil_class = getattr(module, PLATFORM_SPECIFIC_CLASS_NAME) + platform_sfputil = platform_sfputil_class() + except AttributeError, e: + print("Failed to instantiate '%s' class: %s" % (PLATFORM_SPECIFIC_CLASS_NAME, str(e)), True) + + assert platform_sfputil is not None + return + +# Get platform specific HwSKU path +def get_hwsku_path(): + file = open(PLATFORM_PATH + "/default_sku", "r") + line = file.readline() + list = line.split() + file.close() + return PLATFORM_PATH + "/" + list[0] + +# Loads platform port dictionaries +def load_platform_portdict(): + global port_dict + + if port_dict is not None: + return + + port_dict = {} + idx = 0 + file = open(get_hwsku_path() + "/port_config.ini", "r") + line = file.readline() + while line is not None and len(line) > 0: + line = line.strip() + if line.startswith("#"): + line = file.readline() + continue + list = line.split() + if len(list) >= 4: + idx = int(list[3]) + port_dict[list[0]] = { "index": str(idx) } + idx += 1 + line = file.readline() + + return port_dict + +# Test for SFP port number +def test_for_sfp_number(json_config_data): + """Test Purpose: Verify that the numer of SFPs reported as supported by the SFP plugin matches what the platform supports. + + Args: + arg1 (json): platform--config.json + + Example: + For a system that physically supports 32 (Q)SFP transceivers + + platform--config.json + { + "PLATFORM": { + "num_sfps": 32 + } + } + """ + load_platform_sfputil() + load_platform_portdict() + num = 0 + for intf in natsorted(port_dict.keys()): + port = int(port_dict[intf]['index']) + if not platform_sfputil._is_valid_port(port): + continue + num += 1 + + for plat in json_config_data: + assert num == int(json_config_data[plat]["num_sfps"]) + + return + +# Test for SFP presence +def test_for_sfp_present(json_config_data, json_test_data): + """Test Purpose: Verify that the presence of SFPs reported by the SFP plugin matches the physical states of the DUT. + + Args: + arg1 (json): platform--config.json + arg2 (json): test--config.json + + Example: + For a system with 4 (Q)SFP transceivers attached on index 13,17,52,68 + + platform--config.json + { + "PLATFORM": { + "num_sfps": 32 + } + } + + test--config.json + { + "PLATFORM": { + "present": [ + 13, + 17, + 52, + 68 + ] + } + } + """ + load_platform_sfputil() + load_platform_portdict() + for intf in natsorted(port_dict.keys()): + port = int(port_dict[intf]['index']) + if not platform_sfputil._is_valid_port(port): + continue + bool = platform_sfputil.get_presence(port) + for plat in json_config_data: + list = json_test_data[plat]['SFP']['present'] + if port in list: + assert bool == True, "SFP{} is not present unexpectedly".format(port) + else: + assert bool == False, "SFP{} is present unexpectedly".format(port) + return + +# Test for SFP EEPROM +def test_for_sfp_eeprom(json_config_data, json_test_data): + """Test Purpose: Verify that the content of SFP EEPROMs pass the check code test. + + Args: + arg1 (json): platform--config.json + arg2 (json): test--config.json + + Example: + For a system with 4 (Q)SFP transceivers attached on index 13,17,52,68 + + platform--config.json + { + "PLATFORM": { + "num_sfps": 32 + } + } + + test--config.json + { + "PLATFORM": { + "present": [ + 13, + 17, + 52, + 68 + ] + } + } + """ + load_platform_sfputil() + load_platform_portdict() + for intf in natsorted(port_dict.keys()): + port = int(port_dict[intf]['index']) + if not platform_sfputil._is_valid_port(port): + continue + bool = platform_sfputil.get_presence(port) + for plat in json_config_data: + list = json_test_data[plat]['SFP']['present'] + if port in list: + assert bool == True, "SFP{} is not present unexpectedly".format(port) + code = 0 + data = platform_sfputil.get_eeprom_raw(port) + assert data != None, "SFP{}: unable to read EEPROM".format(port) + if port in platform_sfputil.osfp_ports: + #OSFP/QSFP-DD + for i in range(128, 222): + code += int(data[i], 16) + assert (code & 0xff) == int(data[222], 16), "check code error" + elif port in platform_sfputil.qsfp_ports: + #QSFP + for i in range(128, 191): + code += int(data[i], 16) + assert (code & 0xff) == int(data[191], 16), "check code error" + else: + #SFP/SFP+ + for i in range(0, 63): + code += int(data[i], 16) + assert (code & 0xff) == int(data[63], 16), "check code error" + else: + assert bool == False, "SFP{} is present".format(port) + return + +# Test for SFP LPMODE +def test_for_sfp_lpmode(): + """Test Purpose: Verify that the LPMODE of QSFP is manipulatable via SFP plugin + + Args: + None + """ + load_platform_sfputil() + load_platform_portdict() + for intf in natsorted(port_dict.keys()): + port = int(port_dict[intf]['index']) + if not platform_sfputil._is_valid_port(port): + continue + if port not in platform_sfputil.qsfp_ports: + continue + try: + bool = platform_sfputil.get_low_power_mode(port) + except NotImplementedError: + assert False, (intf + ': get_low_power_mode() is not implemented') + if bool: + try: + platform_sfputil.set_low_power_mode(port, False) + except NotImplementedError: + assert False, (intf + ': low power detected while ' + + 'set_low_power_mode() is not implemented,' + + 'link errors are expected on high power modules') + return + +# Test for SFP LPMODE +def test_for_sfp_reset(): + """Test Purpose: Verify that the RESET of QSFP is manipulatable via SFP plugin + + Args: + None + """ + load_platform_sfputil() + load_platform_portdict() + for intf in natsorted(port_dict.keys()): + port = int(port_dict[intf]['index']) + if not platform_sfputil._is_valid_port(port): + continue + if port not in platform_sfputil.qsfp_ports: + continue + try: + bool = platform_sfputil.reset(port) + assert bool, "reset failed" + except NotImplementedError: + # By defalt, it does no harm to have this unimplemented + # This failure will only be observed when users try to manually + # reset the module via CLI + pytest.skip(intf + ": reset() is not implemented") + return diff --git a/sonic-pde-tests/sonic_pde_tests/test_thermal.py b/sonic-pde-tests/sonic_pde_tests/test_thermal.py new file mode 100644 index 0000000..8e7cd02 --- /dev/null +++ b/sonic-pde-tests/sonic_pde_tests/test_thermal.py @@ -0,0 +1,356 @@ +import pytest +import sys +import imp +import subprocess +import time + +PLATFORM_PATH = "/usr/share/sonic/platform" +PLATFORM_SPECIFIC_PSU_MODULE_NAME = "psuutil" +PLATFORM_SPECIFIC_PSU_CLASS_NAME = "PsuUtil" +PLATFORM_SPECIFIC_FAN_MODULE_NAME = "fanutil" +PLATFORM_SPECIFIC_FAN_CLASS_NAME = "FanUtil" + +platform_psuutil = None +platform_chassis = None +platform_fanutil = None + +# wrappers that are compliable with both new platform api and old-style plugin +def _wrapper_init(): + global platform_chassis + global platform_psuutil + global platform_fanutil + + # Load new platform api class + if platform_chassis is None: + try: + import sonic_platform.platform + platform_chassis = sonic_platform.platform.Platform().get_chassis() + except Exception as e: + print("Failed to load chassis due to {}".format(repr(e))) + + # Load platform-specific psuutil class + if platform_chassis is None: + try: + module_file = "/".join([PLATFORM_PATH, "plugins", PLATFORM_SPECIFIC_PSU_MODULE_NAME + ".py"]) + module = imp.load_source(PLATFORM_SPECIFIC_PSU_MODULE_NAME, module_file) + platform_psuutil_class = getattr(module, PLATFORM_SPECIFIC_PSU_CLASS_NAME) + platform_psuutil = platform_psuutil_class() + except Exception as e: + print("Failed to load psuutil due to {}".format(repr(e))) + + # Load platform-specific fanutil class + try: + module_file = "/".join([PLATFORM_PATH, "plugins", PLATFORM_SPECIFIC_FAN_MODULE_NAME + ".py"]) + module = imp.load_source(PLATFORM_SPECIFIC_FAN_MODULE_NAME, module_file) + platform_fanutil_class = getattr(module, PLATFORM_SPECIFIC_FAN_CLASS_NAME) + platform_fanutil = platform_fanutil_class() + except Exception as e: + print("Failed to load fanutil due to {}".format(repr(e))) + + assert (platform_chassis is not None) or (platform_psuutil is not None) or \ + (platform_fanutil is not None) , "Unable to load platform module" + + +def _wrapper_get_num_temp(): + _wrapper_init() + if platform_chassis is not None: + try: + return platform_chassis.get_num_thermals() + except NotImplementedError: + pass + return 0 + +def _wrapper_get_temperature(index): + _wrapper_init() + if platform_chassis is not None: + try: + return platform_chassis.get_thermal(index).get_temperature() + except NotImplementedError: + pass + return -255 + +def _wrapper_get_fan_presence(index): + _wrapper_init() + if platform_chassis is not None: + try: + return platform_chassis.get_fan(index).get_presence() + except NotImplementedError: + pass + return platform_fanutil.get_presence(index+1) + +def _wrapper_get_fan_duty(index): + _wrapper_init() + if platform_chassis is not None: + try: + return platform_chassis.get_fan(index).get_target_speed() + except NotImplementedError: + pass + return platform_fanutil.get_speed(index+1) + +def _wrapper_get_fan_direction(index): + _wrapper_init() + if platform_chassis is not None: + try: + return platform_chassis.get_fan(index).get_direction() + except NotImplementedError: + pass + return platform_fanutil.get_direction(index+1) + +def _wrapper_get_psus_presence(index): + _wrapper_init() + if platform_chassis is not None: + try: + return platform_chassis.get_psu(index).get_presence() + except NotImplementedError: + pass + return platform_psuutil.get_psu_presence(index+1) + + + +# test cases +def test_for_num_temp(json_config_data): + """Test Purpose: Verify that the numer of Temp sensors reported as supported + by the Termal plugin matches what the platform supports + + Args: + arg1 (json): platform--config.json + + Example: + For a system that physically supports 4 TEMPs + + platform--config.json + { + "PLATFORM": { + "num_temps": 4 + } + } + """ + if json_config_data['PLATFORM']['modules']['TEMP']['support'] == "false": + pytest.skip("Skip the testing due to the python module is not supported") + + assert _wrapper_get_num_temp() == json_config_data['PLATFORM']['num_temps'] + + +def test_for_temp_read(json_config_data): + """Test Purpose: Verify that each of the Temp sensors defined in the platform config + josn is able to read + + + Args: + arg1 (json): platform--config.json + + Example: + For a system that physically supports 4 TEMPs + + platform--config.json + { + "PLATFORM": { + num_temps": 4 + } + } + """ + if json_config_data['PLATFORM']['modules']['TEMP']['support'] == "false": + pytest.skip("Skip the testing due to the python module is not supported") + + for x in range(json_config_data['PLATFORM']['num_temps']): + print("tmp{}: {}".format(x, _wrapper_get_temperature(x))) + assert _wrapper_get_temperature(x) != -255, "tmp{}: invalid temperature".format(x) + + +def test_for_thermal_daemon(json_config_data,json_test_data): + + if json_config_data['PLATFORM']['thermal_policy_support'] == "false": + pytest.skip("Skip the testing due to thermal policy not supported") + + cp1 = [] + app = json_test_data['PLATFORM']['THERMAL_POLICY']['service_name'] + cmd = "cat /var/log/syslog | grep -c -i " + app + ".service" + + # check for syslog messages + pin = subprocess.Popen(cmd, + shell=True, + close_fds=True, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + cnt = pin.communicate()[0] + cp1.append(int(cnt)) + assert cp1, "flooding syslog [" + app + "] not detected" + + +def test_for_thermal_policy(json_config_data,json_test_data): + + if json_config_data['PLATFORM']['thermal_policy_support'] == "false": + pytest.skip("Skip the testing due to thermal policy not supported") + + temp=0 + for x in range(json_config_data['PLATFORM']['num_temps']): + temp += _wrapper_get_temperature(x) + temp_avg = temp // json_config_data['PLATFORM']['num_temps'] + + dir = _wrapper_get_fan_direction(x) + for index in range(json_test_data['PLATFORM']['THERMAL_POLICY']['POLICY_NUM']): + if dir == "exhaust": + low = json_test_data['PLATFORM']['THERMAL_POLICY']['B2F'][str(index)][0] + high = json_test_data['PLATFORM']['THERMAL_POLICY']['B2F'][str(index)][1] + duty = json_test_data['PLATFORM']['THERMAL_POLICY']['B2F'][str(index)][2] + else: + low = json_test_data['PLATFORM']['THERMAL_POLICY']['F2B'][str(index)][0] + high = json_test_data['PLATFORM']['THERMAL_POLICY']['F2B'][str(index)][1] + duty = json_test_data['PLATFORM']['THERMAL_POLICY']['F2B'][str(index)][2] + + + if temp > high : + continue + else : + assert duty == _wrapper_get_fan_duty(x), \ + "FAN{}: duty mismatched".format(x+1) + return + +def test_for_thermal_policy_fan_removed(json_config_data,json_test_data): + + """Test Purpose: Verify that DUTY change to full speed if any fan removed + The test require users to remove FAN before testing + + Args: + arg1 (json): platform--config.json + arg2 (json): test--config.json + Example: + For a system that FAN REMOVE DUTY = 100 + + test--config.json + { + "THERMAL_POLICY":: { + "FAN_REMOVED_DUTY":100 + } + } + """ + + if json_config_data['PLATFORM']['thermal_policy_support'] == "false": + pytest.skip("Skip the testing due to thermal policy not supported") + + + if _wrapper_init() is None: + pytest.skip("platform chassis not found") + return + + duty = json_test_data['PLATFORM']['THERMAL_POLICY']['FAN_REMOVED_DUTY'] + + # test if any one of FAN removed + Fan_removed = False + for x in range(json_config_data['PLATFORM']['num_fans']): + if _wrapper_get_fan_presence(x) == False: + Fan_removed = True + break + + if Fan_removed == False: + pytest.skip("Skip the test due to All FAN are present") + + for x in range(json_config_data['PLATFORM']['num_fans']): + if _wrapper_get_fan_presence(x) == True: + assert duty == _wrapper_get_fan_duty(x), \ + "FAN{}: duty mismatched".format(x+1) + + +def test_for_pmon_daemon(json_test_data): + + """Test Purpose: Verify that if the pmon syslog message detected + + Args: + arg1 (json): test--config.json + + Example: + To scan for the pmon syslog message by keywords: psud, fand + + test--config.json + { + "PLATFORM": { + "PMON": + { + "syslog": [ + "psud", + "fand" + ] + } + } + } + """ + cp1 = [] + pat = json_test_data["PLATFORM"]["PMON"]["syslog"] + + for idx in range(len(pat)): + cmd = "cat /var/log/syslog | grep -c -i " + "'" + pat[idx] + \ + " entered RUNNING state" + "'" + pin = subprocess.Popen(cmd, + shell=True, + close_fds=True, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + cnt = pin.communicate()[0] + cp1.append(int(cnt)) + + for idx1 in range(len(pat)): + assert cp1[idx1] != 0, "pmon syslog [" + pat[idx1] + "] not detected" + +def test_for_pmon_fan_removed_event_log(json_config_data,json_test_data): + + """Test Purpose: Verify PMON event log if any fan removed + The test require users to remove FAN before testing + + Args: + arg1 (json): platform--config.json + arg2 (json): test--config.json + + """ + Fan_removed = False + + if json_config_data['PLATFORM']['modules']['FAN']['support'] == "false": + pytest.skip("Skip the testing due to the python module is not supported in BSP") + + for x in range(json_config_data['PLATFORM']['num_fans']): + if _wrapper_get_fan_presence(x) == False: + Fan_removed = True + cmd = "cat /var/log/syslog | grep -c -i " + "'" + "FAN " + str(x+1) + \ + " removed" + "'" + pin = subprocess.Popen(cmd, + shell=True, + close_fds=True, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + cnt = pin.communicate()[0] + assert int(cnt) != 0,\ + "FAN" + str(x+1)+ "removed event log not detected" + + if Fan_removed == False: + pytest.skip("Skip the test due to All FAN are present") + + + +def test_for_pmon_psu_removed_event_log(json_config_data,json_test_data): + + """Test Purpose: Verify PMON event log if any psu removed + The test require users to remove PSU before testing + + Args: + arg1 (json): platform--config.json + arg2 (json): test--config.json + + """ + Psu_removed = False + + for x in range(json_config_data['PLATFORM']['num_psus']): + if _wrapper_get_psus_presence(x) == False: + Psu_removed == True + cmd = "cat /var/log/syslog | grep -c -i " + "'" + "PSU " + str(x+1) + \ + " removed" + "'" + pin = subprocess.Popen(cmd, + shell=True, + close_fds=True, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + cnt = pin.communicate()[0] + assert int(cnt) != 0,\ + "PSU" + str(x+1)+ "removed event log not detected" + + if Psu_removed == False: + pytest.skip("Skip the test due to All PSU are present") + diff --git a/sonic-pde-tests/sonic_pde_tests/test_usb.py b/sonic-pde-tests/sonic_pde_tests/test_usb.py new file mode 100644 index 0000000..a823c5a --- /dev/null +++ b/sonic-pde-tests/sonic_pde_tests/test_usb.py @@ -0,0 +1,153 @@ +#!/usr/bin/python + +try: + import os + import sys + import json + import time + import pytest + import subprocess +except ImportError as e: + raise ImportError("%s - required module not found" % str(e)) + +# Test for USB storage support +def test_for_usb_storage(): + """Test Purpose: Verify that if the USB storage device support is enable in the kernel + + Args: + None + """ + cmd = "cat /boot/config-* | grep ^CONFIG_USB_STORAGE=" + ret = subprocess.call(cmd + " > /dev/null 2>&1", shell=True) + assert ret == 0, "USB storage support is disabled in the kernel" + return + +# Test for FAT filesystem support +def test_for_usb_fat(): + """Test Purpose: Verify that if the MSDOS/VFAT/FAT filesystem support is enable in the kernel + + Args: + None + """ + cmd = "cat /boot/config-* | grep ^CONFIG_FAT_FS=" + ret = subprocess.call(cmd + " > /dev/null 2>&1", shell=True) + assert ret == 0, "FAT support is disabled in the kernel" + cmd = "cat /boot/config-* | grep ^CONFIG_VFAT_FS=" + ret = subprocess.call(cmd + " > /dev/null 2>&1", shell=True) + assert ret == 0, "VFAT support is disabled in the kernel" + cmd = "cat /boot/config-* | grep ^CONFIG_MSDOS_FS=" + ret = subprocess.call(cmd + " > /dev/null 2>&1", shell=True) + assert ret == 0, "MSDOS support is disabled in the kernel" + return + +# Test for NTFS filesystem support +def test_for_usb_ntfs(): + """Test Purpose: Verify that if the NTFS filesystem support is enable in the kernel + + Args: + None + """ + cmd = "cat /boot/config-* | grep ^CONFIG_NTFS_FS=" + ret = subprocess.call(cmd + " > /dev/null 2>&1", shell=True) + assert ret == 0, "NTFS support is disabled in the kernel" + return + +# Test for EXT4 filesystem support +def test_for_usb_ext4(): + """Test Purpose: Verify that if the EXT4 filesystem support is enable in the kernel + + Args: + None + """ + cmd = "cat /boot/config-* | grep ^CONFIG_EXT4_FS=" + ret = subprocess.call(cmd + " > /dev/null 2>&1", shell=True) + assert ret == 0, "EXT4 support is disabled in the kernel" + return + +# Test for the presence of external USB storage +def test_for_usb_presence(json_test_data): + """Test Purpose: Verify that the attached USB storage is detected on the DUT + + Args: + arg1 (json): test--config.json + + Example: + To enable the external USB storage test + + test--config.json + { + "PLATFORM": { + "USB": { + "enable": "yes", + "device": "sdb", + "mountpoint": "/media/usb-storage" + }, + } + } + """ + doit = json_test_data["PLATFORM"]["USB"]["enable"] + if doit is None or "yes" != doit: + pytest.skip("USB disabled") + return + + node = json_test_data["PLATFORM"]["USB"]["device"] + assert node is not None and node.startswith("sd"), "invalid device node" + + path = "/sys/class/block/" + node + assert os.path.isdir(path), node + ": no such device" + +# Test for mounting external USB storage (i.e. filesystem read) +def test_for_usb_mount(json_test_data): + """Test Purpose: Verify that the attached USB storage is able to be mounted on the DUT + + Args: + arg1 (json): test--config.json + + Example: + To enable the external USB storage test + + test--config.json + { + "PLATFORM": { + "USB": { + "enable": "yes", + "device": "sdb", + "mountpoint": "/media/usb-storage" + }, + } + } + """ + doit = json_test_data["PLATFORM"]["USB"]["enable"] + if doit is None or "yes" != doit: + pytest.skip("USB disabled") + return + + device = json_test_data["PLATFORM"]["USB"]["device"] + assert device is not None and device.startswith("sd"), "invalid device node" + + mountpoint = json_test_data["PLATFORM"]["USB"]["mountpoint"] + assert mountpoint is not None and mountpoint.startswith("/media"), "invalid mount point" + + # umount the usb if it's still there + rc = subprocess.call("mount | grep " + mountpoint + " > /dev/null 2>&1", shell=True) + if rc == 0: + rc = subprocess.call("umount " + mountpoint + " > /dev/null 2>&1", shell=True) + time.sleep(3) + + # create mount point + rc = subprocess.call("mkdir -p " + mountpoint + " > /dev/null 2>&1", shell=True) + assert rc == 0, "Unable to create mount point" + + # mount the USB (try to mount partition 1 and then partition 0) + if os.path.isdir("/sys/class/block/" + device + "1"): + cmd = "mount /dev/" + device + "1 " + mountpoint + " > /dev/null 2>&1" + elif os.path.isdir("/sys/class/block/" + device): + cmd = "mount /dev/" + device + " " + mountpoint + " > /dev/null 2>&1" + else: + cmd = "false" + rc = subprocess.call(cmd, shell=True) + assert rc == 0, "Unable to mount the external USB" + + # umount the USB + rc = subprocess.call("umount " + mountpoint + " > /dev/null 2>&1", shell=True) + return diff --git a/sonic-pde-tests/stdeb.cfg b/sonic-pde-tests/stdeb.cfg new file mode 100644 index 0000000..db4574b --- /dev/null +++ b/sonic-pde-tests/stdeb.cfg @@ -0,0 +1 @@ +[DEFAULT]