public inbox for passt-dev@passt.top
 help / color / mirror / code / Atom feed
From: David Gibson <david@gibson.dropbear.id.au>
To: passt-dev@passt.top, Stefano Brivio <sbrivio@redhat.com>
Cc: jarichte@redhat.com, Cleber Rosa <crosa@redhat.com>,
	David Gibson <david@gibson.dropbear.id.au>
Subject: [PATCH v2 06/21] avocado/tasst: Helper functions for executing commands in different places
Date: Tue, 16 May 2023 12:01:20 +1000	[thread overview]
Message-ID: <20230516020135.1901256-7-david@gibson.dropbear.id.au> (raw)
In-Reply-To: <20230516020135.1901256-1-david@gibson.dropbear.id.au>

Add a library "tasst" for use in avocado tests of passt & pasta.  We start
by adding the outline of logic to run commands in various places (e.g.
namespaces, VMs).  We add some avocado tests for the test library itself,
tagged 'meta' to distinguish it from tests for passt/pasta proper.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 Makefile                  |  11 +++-
 avocado/.gitignore        |   1 +
 avocado/tasst/__init__.py |  27 ++++++++++
 avocado/tasst/site.py     | 104 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 141 insertions(+), 2 deletions(-)
 create mode 100644 avocado/.gitignore
 create mode 100644 avocado/tasst/__init__.py
 create mode 100644 avocado/tasst/site.py

diff --git a/Makefile b/Makefile
index d2daaa1..fc83cd2 100644
--- a/Makefile
+++ b/Makefile
@@ -135,6 +135,7 @@ clean:
 	$(RM) $(BIN) *~ *.o seccomp.h pasta.1 \
 		passt.tar passt.tar.gz *.deb *.rpm \
 		passt.pid README.plain.md
+	$(RM) -r avocado/__pycache__
 
 install: $(BIN) $(MANPAGES) docs
 	mkdir -p $(DESTDIR)$(bindir) $(DESTDIR)$(man1dir)
@@ -297,9 +298,15 @@ cppcheck: $(SRCS) $(HEADERS)
 
 AVOCADO = avocado
 
+avocado-%:
+	PYTHONPATH=./avocado $(AVOCADO) run avocado --filter-by-tags=$*
+
+avocado-all:
+	PYTHONPATH=./avocado $(AVOCADO) run avocado
+
+# Default avocado tests to run, everything except the "meta" tests
 .PHONY: avocado
-avocado:
-	$(AVOCADO) run avocado
+avocado: avocado--meta
 
 check: avocado
 	$(MAKE) -C test check
diff --git a/avocado/.gitignore b/avocado/.gitignore
new file mode 100644
index 0000000..c18dd8d
--- /dev/null
+++ b/avocado/.gitignore
@@ -0,0 +1 @@
+__pycache__/
diff --git a/avocado/tasst/__init__.py b/avocado/tasst/__init__.py
new file mode 100644
index 0000000..bd7994c
--- /dev/null
+++ b/avocado/tasst/__init__.py
@@ -0,0 +1,27 @@
+#! /usr/bin/python3
+
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# tasst - Test A Simple Socket Transport
+#         library of test helpers for passt & pasta
+#
+# Copyright Red Hat
+# Author: David Gibson <david@gibson.dropbear.id.au>
+
+import avocado
+
+
+# Base class for avocado-based passt/pasta tests
+class Tasst(avocado.Test):
+    # Fairly short default timeout
+    timeout = 10.0
+
+    def subsetup(self, class_, subdata):
+        assert isinstance(self, class_)
+        setattr(self, class_.__name__, subdata)
+
+    def get_subsetup(self, class_):
+        assert hasattr(self, class_.__name__), \
+            "{}.setUp() needs to call {}.subsetup()".format(self.__class__.__name__,
+                                                            class_.__name__)
+        return getattr(self, class_.__name__)
diff --git a/avocado/tasst/site.py b/avocado/tasst/site.py
new file mode 100644
index 0000000..682baee
--- /dev/null
+++ b/avocado/tasst/site.py
@@ -0,0 +1,104 @@
+#! /usr/bin/python3
+
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# tasst - Test A Simple Socket Transport
+#         library of test helpers for passt & pasta
+#
+# tasst/site.py - Manage simulated network sites for testing
+#
+# Copyright Red Hat
+# Author: David Gibson <david@gibson.dropbear.id.au>
+
+import avocado
+from avocado.utils.process import CmdError
+
+from tasst import Tasst
+
+
+class Site:
+    """
+    A (usually virtual or simulated) location where we can execute
+    commands and configure networks.
+
+    """
+
+    def __init__(self, name):
+        self.name = name # For debugging
+
+    # Shut down the site and release any resources it's using.  We
+    # can't use __del__() for this (RAII like), because Python doesn't
+    # guarantee that will get called, and that's pretty easy to hit in
+    # practice.  The modern Pythonic way of doing this is 'with' and
+    # ContextManagers, but that doesn't work with Avocado's jUnit
+    # derived format for setUp() and tearDown().  Oh well, do it
+    # manually.
+    def close(self):
+        pass
+
+    def output(self, cmd, **kwargs):
+        raise NotImplementedError
+
+    def fg(self, cmd, **kwargs):
+        self.output(cmd, **kwargs)
+
+    def require_cmds(self, *cmds):
+        missing = [c for c in cmds
+                   if self.fg('type {}'.format(c), ignore_status=True) != 0]
+        if missing:
+            raise avocado.TestCancel("Missing commands {} on {}"
+                                     .format(', '.join(missing), self.name))
+
+
+class BaseSiteTasst(Tasst):
+    """
+    Basic tests for executing commands on sites
+
+    :avocado: disable
+    :avocado: tags=meta
+    """
+    timeout = 1.0
+
+    # Derived classes must call this from setUp()
+    def subsetup(self, site):
+        assert isinstance(site, Site)
+        site.require_cmds('true', 'false', 'echo')
+        Tasst.subsetup(self, BaseSiteTasst, site)
+
+    def test_true(self):
+        site = self.get_subsetup(BaseSiteTasst)
+        site.fg('true')
+
+    def test_false(self):
+        site = self.get_subsetup(BaseSiteTasst)
+        self.assertRaises(CmdError, site.fg, 'false')
+
+    def test_echo(self):
+        site = self.get_subsetup(BaseSiteTasst)
+        s = 'Hello tasst'
+        out = site.output('echo {}'.format(s))
+        self.assertEquals(out, s.encode('utf-8'))
+
+
+# Represents the host on which the tests are running, as opposed to
+# some simulated host created by the tests
+class RealHost(Site):
+    def __init__(self):
+        super().__init__('REAL_HOST')
+
+    def output(self, cmd, sudo=False, **kwargs):
+        assert not sudo, "BUG: Shouldn't run commands with privilege on host"
+        return avocado.utils.process.system_output(cmd, **kwargs)
+
+    def fg(self, cmd, sudo=False, **kwargs):
+        assert not sudo, "BUG: Shouldn't run commands with privilege on host"
+        return avocado.utils.process.system(cmd, **kwargs)
+
+
+REAL_HOST = RealHost()
+
+
+class RealHostTasst(BaseSiteTasst):
+    def setUp(self):
+        super().setUp()
+        BaseSiteTasst.subsetup(self, REAL_HOST)
-- 
@@ -0,0 +1,104 @@
+#! /usr/bin/python3
+
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# tasst - Test A Simple Socket Transport
+#         library of test helpers for passt & pasta
+#
+# tasst/site.py - Manage simulated network sites for testing
+#
+# Copyright Red Hat
+# Author: David Gibson <david@gibson.dropbear.id.au>
+
+import avocado
+from avocado.utils.process import CmdError
+
+from tasst import Tasst
+
+
+class Site:
+    """
+    A (usually virtual or simulated) location where we can execute
+    commands and configure networks.
+
+    """
+
+    def __init__(self, name):
+        self.name = name # For debugging
+
+    # Shut down the site and release any resources it's using.  We
+    # can't use __del__() for this (RAII like), because Python doesn't
+    # guarantee that will get called, and that's pretty easy to hit in
+    # practice.  The modern Pythonic way of doing this is 'with' and
+    # ContextManagers, but that doesn't work with Avocado's jUnit
+    # derived format for setUp() and tearDown().  Oh well, do it
+    # manually.
+    def close(self):
+        pass
+
+    def output(self, cmd, **kwargs):
+        raise NotImplementedError
+
+    def fg(self, cmd, **kwargs):
+        self.output(cmd, **kwargs)
+
+    def require_cmds(self, *cmds):
+        missing = [c for c in cmds
+                   if self.fg('type {}'.format(c), ignore_status=True) != 0]
+        if missing:
+            raise avocado.TestCancel("Missing commands {} on {}"
+                                     .format(', '.join(missing), self.name))
+
+
+class BaseSiteTasst(Tasst):
+    """
+    Basic tests for executing commands on sites
+
+    :avocado: disable
+    :avocado: tags=meta
+    """
+    timeout = 1.0
+
+    # Derived classes must call this from setUp()
+    def subsetup(self, site):
+        assert isinstance(site, Site)
+        site.require_cmds('true', 'false', 'echo')
+        Tasst.subsetup(self, BaseSiteTasst, site)
+
+    def test_true(self):
+        site = self.get_subsetup(BaseSiteTasst)
+        site.fg('true')
+
+    def test_false(self):
+        site = self.get_subsetup(BaseSiteTasst)
+        self.assertRaises(CmdError, site.fg, 'false')
+
+    def test_echo(self):
+        site = self.get_subsetup(BaseSiteTasst)
+        s = 'Hello tasst'
+        out = site.output('echo {}'.format(s))
+        self.assertEquals(out, s.encode('utf-8'))
+
+
+# Represents the host on which the tests are running, as opposed to
+# some simulated host created by the tests
+class RealHost(Site):
+    def __init__(self):
+        super().__init__('REAL_HOST')
+
+    def output(self, cmd, sudo=False, **kwargs):
+        assert not sudo, "BUG: Shouldn't run commands with privilege on host"
+        return avocado.utils.process.system_output(cmd, **kwargs)
+
+    def fg(self, cmd, sudo=False, **kwargs):
+        assert not sudo, "BUG: Shouldn't run commands with privilege on host"
+        return avocado.utils.process.system(cmd, **kwargs)
+
+
+REAL_HOST = RealHost()
+
+
+class RealHostTasst(BaseSiteTasst):
+    def setUp(self):
+        super().setUp()
+        BaseSiteTasst.subsetup(self, REAL_HOST)
-- 
2.40.1


  parent reply	other threads:[~2023-05-16  2:01 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-05-16  2:01 [PATCH v2 00/21] RFCv2: Proof-of-concept conversion of some tests to Avocado framework David Gibson
2023-05-16  2:01 ` [PATCH v2 01/21] test/nstool: Provide useful error if given a path that's too long David Gibson
2023-05-16  2:01 ` [PATCH v2 02/21] test/nstool: Fix fd leak in accept() loop David Gibson
2023-05-16  2:01 ` [PATCH v2 03/21] avocado: Make a duplicate copy of testsuite for comparison purposes David Gibson
2023-05-16  2:01 ` [PATCH v2 04/21] avocado: Don't double download assets for test/ and oldtest/ David Gibson
2023-05-16  2:01 ` [PATCH v2 05/21] avocado: Move static checkers to avocado David Gibson
2023-05-16  2:01 ` David Gibson [this message]
2023-05-16  2:01 ` [PATCH v2 07/21] avocado: Convert build tests " David Gibson
2023-05-16  2:01 ` [PATCH v2 08/21] avocado/tasst: Add helpers for running background commands on sites David Gibson
2023-05-16  2:01 ` [PATCH v2 09/21] avocado/tasst: Add helper to get network interface names for a site David Gibson
2023-05-16  2:01 ` [PATCH v2 10/21] avocado/tasst: Add helpers to run commands with nstool David Gibson
2023-05-16  2:01 ` [PATCH v2 11/21] avocado/tasst: Add ifup and network address helpers to Site David Gibson
2023-05-16  2:01 ` [PATCH v2 12/21] avocado/tasst: Helper for creating veth devices between namespaces David Gibson
2023-05-16  2:01 ` [PATCH v2 13/21] avocado/tasst: Add helper for getting MTU of a network interface David Gibson
2023-05-16  2:01 ` [PATCH v2 14/21] avocado/tasst: Add helper to wait for IP address to appear David Gibson
2023-05-16  2:01 ` [PATCH v2 15/21] avocado/tasst: Add helpers for getting a site's routes David Gibson
2023-05-16  2:01 ` [PATCH v2 16/21] avocado/tasst: Helpers for test transferring data between sites David Gibson
2023-05-16  2:01 ` [PATCH v2 17/21] avocado/tasst: IP address allocation helpers David Gibson
2023-05-16  2:01 ` [PATCH v2 18/21] avocado/tasst: Helpers for testing NDP behaviour David Gibson
2023-05-16  2:01 ` [PATCH v2 19/21] avocado/tasst: Helpers for testing DHCP & DHCPv6 behaviour David Gibson
2023-05-16  2:01 ` [PATCH v2 20/21] avocado/tasst: Helpers to construct a simple network environment for tests David Gibson
2023-05-16  2:01 ` [PATCH v2 21/21] avocado: Convert basic pasta tests David Gibson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230516020135.1901256-7-david@gibson.dropbear.id.au \
    --to=david@gibson.dropbear.id.au \
    --cc=crosa@redhat.com \
    --cc=jarichte@redhat.com \
    --cc=passt-dev@passt.top \
    --cc=sbrivio@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://passt.top/passt

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for IMAP folder(s).