From b94abb44d9d0f92a527dfa1ecf2e4d3c1be6178c Mon Sep 17 00:00:00 2001
From: Ghanshyam Mann <gmann@ghanshyammann.com>
Date: Mon, 9 Jan 2023 13:25:50 -0600
Subject: [PATCH] Fix tox4 error and use python >=3.8

tox.ini started failing with tox4 which had some
incompatible changes. One of them is to allow
external command to run by adding them into allowlist_externals
and make passenv in new lines.

Fixing tox.ini for tox4 changes.

Minimal python version is now 3.8

Other minor fixes:
* Use devstack-alt-member in tests instead of devstack-alt, as
  the later is having admin role now.
* Fix some of the functional tests not working anymore with the
  latest mistral changes.
* Removing standard actions tests as they are not standard anymore (they
  are in mistral-extra)

Change-Id: Ic0620135c286855dd4befb52eb55522b605eb863
Signed-off-by: Arnaud Morin <arnaud.morin@ovhcloud.com>
---
 .zuul.yaml                                    |  2 +-
 mistralclient/tests/functional/cli/base.py    |  2 +-
 .../cli/v2/test_cli_multi_tenancy.py          | 43 --------
 .../tests/functional/cli/v2/test_cli_v2.py    | 99 +++++++++++++------
 setup.cfg                                     |  5 +-
 tox.ini                                       | 14 ++-
 6 files changed, 84 insertions(+), 81 deletions(-)

diff --git a/.zuul.yaml b/.zuul.yaml
index d411fb30..39d513e5 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -29,7 +29,7 @@
 - project:
     templates:
       - check-requirements
-      - openstack-python3-xena-jobs
+      - openstack-python3-jobs
       - openstackclient-plugin-jobs
       - publish-openstack-docs-pti
       - release-notes-jobs-python3
diff --git a/mistralclient/tests/functional/cli/base.py b/mistralclient/tests/functional/cli/base.py
index 6cd0b400..6415a0e3 100644
--- a/mistralclient/tests/functional/cli/base.py
+++ b/mistralclient/tests/functional/cli/base.py
@@ -108,7 +108,7 @@ class MistralCLIAltAuth(base.ClientTestBase):
     _mistral_url = None
 
     def _get_alt_clients(self):
-        creds = credentials('devstack-alt')
+        creds = credentials('devstack-alt-member')
 
         clients = base.CLIClient(
             username=creds['username'],
diff --git a/mistralclient/tests/functional/cli/v2/test_cli_multi_tenancy.py b/mistralclient/tests/functional/cli/v2/test_cli_multi_tenancy.py
index 69970e3c..a8e82526 100644
--- a/mistralclient/tests/functional/cli/v2/test_cli_multi_tenancy.py
+++ b/mistralclient/tests/functional/cli/v2/test_cli_multi_tenancy.py
@@ -17,49 +17,6 @@ from tempest.lib import exceptions
 from mistralclient.tests.functional.cli.v2 import base_v2
 
 
-class StandardItemsAvailabilityCLITests(base_v2.MistralClientTestBase):
-
-    def test_std_workflows_availability(self):
-        wfs = self.mistral_admin("workflow-list")
-
-        self.assertTableStruct(
-            wfs,
-            ["Name", "Tags", "Input", "Created at", "Updated at"]
-        )
-        self.assertPartIn("create_instance",
-                          [workflow["Name"] for workflow in wfs])
-
-        wfs = self.mistral_alt_user("workflow-list")
-
-        self.assertTableStruct(
-            wfs,
-            ["Name", "Tags", "Input", "Created at", "Updated at"]
-        )
-        self.assertPartIn("create_instance",
-                          [workflow["Name"] for workflow in wfs])
-
-    def test_std_actions_availability(self):
-        acts = self.mistral_admin("action-list")
-
-        self.assertTableStruct(
-            acts,
-            ["Name", "Is system", "Input", "Description",
-             "Tags", "Created at", "Updated at"]
-        )
-        self.assertIn("glance.images_list",
-                      [action["Name"] for action in acts])
-
-        acts = self.mistral_alt_user("action-list")
-
-        self.assertTableStruct(
-            acts,
-            ["Name", "Is system", "Input", "Description",
-             "Tags", "Created at", "Updated at"]
-        )
-        self.assertIn("glance.images_list",
-                      [action["Name"] for action in acts])
-
-
 class WorkbookIsolationCLITests(base_v2.MistralClientTestBase):
 
     def test_workbook_name_uniqueness(self):
diff --git a/mistralclient/tests/functional/cli/v2/test_cli_v2.py b/mistralclient/tests/functional/cli/v2/test_cli_v2.py
index f5602bbb..87b0cb6b 100644
--- a/mistralclient/tests/functional/cli/v2/test_cli_v2.py
+++ b/mistralclient/tests/functional/cli/v2/test_cli_v2.py
@@ -13,6 +13,8 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
+import time
+
 from tempest.lib import exceptions
 
 from mistralclient.tests.functional.cli import base
@@ -558,6 +560,7 @@ class WorkflowCLITests(base_v2.MistralClientTestBase):
         self.assertNotEqual('None', wf_error)
 
     def test_workflow_list_with_filter(self):
+        self.workflow_create(self.wf_def)
         workflows = self.parser.listing(self.mistral('workflow-list'))
 
         self.assertTableStruct(
@@ -566,14 +569,14 @@ class WorkflowCLITests(base_v2.MistralClientTestBase):
              'Updated at']
         )
 
-        # We know that we have more than one workflow by default.
-        self.assertGreater(len(workflows), 1)
+        # We created 2 workflows, so we should have at least 2
+        self.assertGreaterEqual(len(workflows), 2)
 
         # Now let's provide a filter to the list command.
         workflows = self.parser.listing(
             self.mistral(
                 'workflow-list',
-                params='--filter name=in:std.create_instance,create_instance'
+                params='--filter name=eq:wf1'
             )
         )
 
@@ -585,7 +588,7 @@ class WorkflowCLITests(base_v2.MistralClientTestBase):
 
         self.assertEqual(1, len(workflows))
 
-        self.assertIn('create_instance', workflows[0]['Name'])
+        self.assertEqual('wf1', workflows[0]['Name'])
 
 
 class ExecutionCLITests(base_v2.MistralClientTestBase):
@@ -794,76 +797,114 @@ class ExecutionCLITests(base_v2.MistralClientTestBase):
         self.assertEqual(wrapping_task_id, wf_exec['Task Execution ID'])
 
     def test_executions_list_with_pagination(self):
-        self.execution_create(
+        # Create 2 executions
+        ex1 = self.execution_create(
             params='{0} -d "a"'.format(self.direct_wf['Name'])
         )
-
-        self.execution_create(
+        # We need to sleep at least one sec between the creation of the two
+        # executions because the default sort is by created_at descending
+        # (newest first)
+        # And the tests may fail if the created_at are identical (some sort
+        # of race condition)
+        time.sleep(1)
+        ex2 = self.execution_create(
             params='{0} -d "b"'.format(self.direct_wf['Name'])
         )
 
-        all_wf_execs = self.mistral_cli(True, 'execution-list')
+        all_wf_ids = [
+            self.get_field_value(ex1, 'ID'),
+            self.get_field_value(ex2, 'ID'),
+        ]
 
-        self.assertEqual(2, len(all_wf_execs))
+        # List all executions
+        wf_execs = self.mistral_cli(True, 'execution-list')
 
+        # We are supposed to have 2
+        self.assertEqual(2, len(wf_execs))
+
+        # We are supposed to have the correct IDs
+        self.assertEqual(
+            set(all_wf_ids),
+            set([ex['ID'] for ex in wf_execs])
+        )
+
+        # List executions with limit 1
+        # NOTE(arnaud) mistral client is returning newest first by default
+        # even if it say differently in help message
+        # See change: I002edd1b10ab281072cfa7501cfa763073a7781c
+        # So here, for the test with marker to work, we need to
+        # specificaly ask for ascending execution list using --oldest
         wf_execs = self.mistral_cli(
             True,
             'execution-list',
-            params="--limit 1"
+            params="--oldest --limit 1"
         )
 
+        # We are supposed to have one
         self.assertEqual(1, len(wf_execs))
 
-        wf_ex1_id = all_wf_execs[0]['ID']
-        wf_ex2_id = all_wf_execs[1]['ID']
-
+        # List executions starting after the one we received before
+        not_expected = wf_execs[0]['ID']
+        expected = [ex for ex in all_wf_ids if ex != wf_execs[0]['ID']][0]
         wf_execs = self.mistral_cli(
             True,
             'execution-list',
-            params="--marker %s" % wf_ex1_id
+            params="--marker %s" % not_expected
         )
 
-        self.assertNotIn(wf_ex1_id, [ex['ID'] for ex in wf_execs])
-        self.assertIn(wf_ex2_id, [ex['ID'] for ex in wf_execs])
+        # Check if we have correct ex ID
+        self.assertNotIn(
+            not_expected,
+            [ex['ID'] for ex in wf_execs]
+        )
+        self.assertIn(
+            expected,
+            [ex['ID'] for ex in wf_execs]
+        )
 
+        # List sorted by Description
         wf_execs = self.mistral_cli(
             True,
             'execution-list',
             params="--sort_keys Description"
         )
 
-        self.assertIn(wf_ex1_id, [ex['ID'] for ex in wf_execs])
-        self.assertIn(wf_ex2_id, [ex['ID'] for ex in wf_execs])
+        # We are supposed to have both
+        self.assertEqual(
+            set(all_wf_ids),
+            set([ex['ID'] for ex in wf_execs])
+        )
 
+        # Now check if they are correctly ordered
+        # Ascending by default
         wf_ex1_index = -1
         wf_ex2_index = -1
-
         for idx, ex in enumerate(wf_execs):
-            if ex['ID'] == wf_ex1_id:
+            if ex['ID'] == all_wf_ids[0]:
                 wf_ex1_index = idx
-            elif ex['ID'] == wf_ex2_id:
+            elif ex['ID'] == all_wf_ids[1]:
                 wf_ex2_index = idx
-
         self.assertLess(wf_ex1_index, wf_ex2_index)
 
+        # Check if descending is working also
         wf_execs = self.mistral_cli(
             True,
             'execution-list',
             params="--sort_keys Description --sort_dirs=desc"
         )
 
-        self.assertIn(wf_ex1_id, [ex['ID'] for ex in wf_execs])
-        self.assertIn(wf_ex2_id, [ex['ID'] for ex in wf_execs])
+        self.assertEqual(
+            set(all_wf_ids),
+            set([ex['ID'] for ex in wf_execs])
+        )
 
         wf_ex1_index = -1
         wf_ex2_index = -1
-
         for idx, ex in enumerate(wf_execs):
-            if ex['ID'] == wf_ex1_id:
+            if ex['ID'] == all_wf_ids[0]:
                 wf_ex1_index = idx
-            elif ex['ID'] == wf_ex2_id:
+            elif ex['ID'] == all_wf_ids[1]:
                 wf_ex2_index = idx
-
         self.assertGreater(wf_ex1_index, wf_ex2_index)
 
     def test_execution_list_with_filter(self):
@@ -2360,7 +2401,7 @@ class NegativeCLITests(base_v2.MistralClientTestBase):
             '--os-target-password="{password}" '
             '--os-target-auth-url="{auth_url}" '
             '--target_insecure '
-            'run-action heat.stacks_list'
+            'run-action std.noop'
         ).format(
             tenantname=self.clients.tenant_name,
             username=self.clients.username,
diff --git a/setup.cfg b/setup.cfg
index fa1942f9..04cf2c11 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -3,15 +3,14 @@ name = python-mistralclient
 summary = Mistral Client Library
 description-file = README.rst
 license = Apache Software License
-python-requires = >=3.6
+python-requires = >=3.8
 classifiers =
     Programming Language :: Python
     Programming Language :: Python :: Implementation :: CPython
     Programming Language :: Python :: 3 :: Only
     Programming Language :: Python :: 3
-    Programming Language :: Python :: 3.6
-    Programming Language :: Python :: 3.7
     Programming Language :: Python :: 3.8
+    Programming Language :: Python :: 3.9
     Environment :: OpenStack
     Intended Audience :: Information Technology
     Intended Audience :: System Administrators
diff --git a/tox.ini b/tox.ini
index 0641de53..a1e27a3d 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,7 +1,6 @@
 [tox]
 envlist = py3,pep8
 minversion = 3.1.1
-skipsdist = True
 ignore_basepython_conflict = True
 
 [testenv]
@@ -12,7 +11,13 @@ setenv =
     VIRTUAL_ENV={envdir}
     PYTHONDONTWRITEBYTECODE = 1
     PYTHONWARNINGS=default::DeprecationWarning
-passenv = http_proxy HTTP_PROXY https_proxy HTTPS_PROXY no_proxy NO_PROXY
+passenv =
+  http_proxy
+  HTTP_PROXY
+  https_proxy
+  HTTPS_PROXY
+  no_proxy
+  NO_PROXY
 deps =
     -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
     -r{toxinidir}/requirements.txt
@@ -21,8 +26,9 @@ commands =
     rm -f .testrepository/times.dbm
     find . -type f -name "*.pyc" -delete
     stestr run --concurrency 1 --slowest {posargs}
-whitelist_externals = find
-                      rm
+Allowlist_externals =
+  find
+  rm
 [testenv:cover]
 setenv =
     {[testenv]setenv}