Fix: Nexus release logic and naming, add unit test 06/68306/4 v0.35.3
authorEric Ball <eball@linuxfoundation.org>
Wed, 21 Jul 2021 23:13:45 +0000 (16:13 -0700)
committerEric Ball <eball@linuxfoundation.org>
Thu, 22 Jul 2021 00:47:25 +0000 (17:47 -0700)
nexus.release_staging_repos was failing with an error due to an
undeclared variable. Several other issues were identified and fixed
(see release note for details), and a unit test has been added to
help prevent similar issues in the future.

Issue: RELENG-3804
Change-Id: I8b7e4adf4561541acffa1dc81dbeba35d7783e51
Signed-off-by: Eric Ball <eball@linuxfoundation.org>
lftools/nexus/cmd.py
releasenotes/notes/fix-nexus-release-01c462b4c2ff2741.yaml [new file with mode: 0644]
tests/fixtures/nexus/staging_activities_closed.xml [new file with mode: 0644]
tests/fixtures/nexus/staging_activities_released.xml [new file with mode: 0644]
tests/test_nexus.py

index 1bd9843..d2d6c1f 100644 (file)
@@ -503,23 +503,24 @@ def release_staging_repos(repos, verify, nexus_url=""):
             else:
                 log.info("Nexus is now working on releasing {}".format(str(repo)))
 
-            # Hang out until the repo is fully closed
+            # Hang out until the repo is fully released
             log.info("Waiting for Nexus to complete releasing {}".format(str(repo)))
-            closed = False
+            released = False
             wait_seconds = 20
-            wait_itteration = 0
+            wait_iteration = 0
             activity_url = "{}/staging/repository/{}/activity".format(_nexus.baseurl, repo)
-            while closed is False:
-                sleep(wait_seconds)
-                wait_itteration = wait_itteration + 1
-                log.info("Still waiting... {:>4d} seconds gone".format(total_wait_seconds * wait_itteration))
-                if (wait_itteration % 2) != 0:
-                    response = requests.get(activity_url, auth=_nexus.auth).text
-                    root = et.fromstring(response)  # nosec
-                    events = root.findall("./stagingActivity")
-                    for event in events:
-                        name = event.find("name")
-                        if name.text == "close":
-                            stopped = event.find("stopped")
-                            log.info("Repo released and closed at: {}".format(stopped.text))
-                            closed = True
+            sleep(5)  # Quick sleep to allow small repos to release.
+            while released is False:
+                response = requests.get(activity_url, auth=_nexus.auth).text
+                root = et.fromstring(response)  # nosec
+                events = root.findall("./stagingActivity")
+                for event in events:
+                    name = event.find("name")
+                    if name.text == "release":
+                        stopped = event.find("stopped")
+                        log.info("Repo released at: {}".format(stopped.text))
+                        released = True
+                if not released:
+                    sleep(wait_seconds)
+                    wait_iteration += 1
+                    log.info("Still waiting... {:>4d} seconds gone".format(wait_seconds * wait_iteration))
diff --git a/releasenotes/notes/fix-nexus-release-01c462b4c2ff2741.yaml b/releasenotes/notes/fix-nexus-release-01c462b4c2ff2741.yaml
new file mode 100644 (file)
index 0000000..d4f66cd
--- /dev/null
@@ -0,0 +1,16 @@
+---
+fixes:
+  - |
+    nexus.release_staging_repos was failing with an error due to an undeclared
+    variable. Upon inspection, there were several other issues at play as well:
+    * No unit test (which would have caught an undeclared variable).
+    * Initial sleep of 20s is significantly longer than many repos take to
+    release.
+    * Only checked release status every 40s, while printing every 20s.
+    * Rather than checking release status, we were checking for "close"
+    status. Nexus closes repos before releasing them, so this is not the
+    correct status to look for when waiting for the repo to release.
+
+    A unit test has been added, several variables issues have been corrected,
+    timing was adjusted (waiting just 5 seconds before the initial check for
+    success), and the code will now check for "release" status.
diff --git a/tests/fixtures/nexus/staging_activities_closed.xml b/tests/fixtures/nexus/staging_activities_closed.xml
new file mode 100644 (file)
index 0000000..b94ea84
--- /dev/null
@@ -0,0 +1,34 @@
+<list>
+    <stagingActivity>
+        <name>open</name>
+        <events>
+            <stagingActivityEvent>
+                <timestamp>2021-01-01T01:01:01.000Z</timestamp>
+                <name>repositoryCreated</name>
+                <severity>0</severity>
+                <properties>
+                    <stagingProperty>
+                        <name>id</name>
+                        <value>test-release-repo</value>
+                    </stagingProperty>
+                </properties>
+            </stagingActivityEvent>
+        </events>
+    </stagingActivity>
+    <stagingActivity>
+        <name>close</name>
+        <events>
+            <stagingActivityEvent>
+                <timestamp>2021-01-01T01:01:02.000Z</timestamp>
+                <name>repositoryClosed</name>
+                <severity>0</severity>
+                <properties>
+                    <stagingProperty>
+                        <name>id</name>
+                        <value>test-release-repo</value>
+                    </stagingProperty>
+                </properties>
+            </stagingActivityEvent>
+        </events>
+    </stagingActivity>
+</list>
diff --git a/tests/fixtures/nexus/staging_activities_released.xml b/tests/fixtures/nexus/staging_activities_released.xml
new file mode 100644 (file)
index 0000000..fc2025b
--- /dev/null
@@ -0,0 +1,56 @@
+<list>
+    <stagingActivity>
+        <name>open</name>
+        <started>2021-01-01T01:01:00.000Z</started>
+        <stopped>2021-01-01T01:01:01.000Z</stopped>
+        <events>
+            <stagingActivityEvent>
+                <timestamp>2021-01-01T01:01:01.000Z</timestamp>
+                <name>repositoryCreated</name>
+                <severity>0</severity>
+                <properties>
+                    <stagingProperty>
+                        <name>id</name>
+                        <value>test-release-repo</value>
+                    </stagingProperty>
+                </properties>
+            </stagingActivityEvent>
+        </events>
+    </stagingActivity>
+    <stagingActivity>
+        <name>close</name>
+        <started>2021-01-01T01:01:02.000Z</started>
+        <stopped>2021-01-01T01:01:03.000Z</stopped>
+        <events>
+            <stagingActivityEvent>
+                <timestamp>2021-01-01T01:01:02.000Z</timestamp>
+                <name>repositoryClosed</name>
+                <severity>0</severity>
+                <properties>
+                    <stagingProperty>
+                        <name>id</name>
+                        <value>test-release-repo</value>
+                    </stagingProperty>
+                </properties>
+            </stagingActivityEvent>
+        </events>
+    </stagingActivity>
+    <stagingActivity>
+       <name>release</name>
+       <started>2021-01-01T01:01:04.000Z</started>
+       <stopped>2021-01-01T01:01:05.000Z</stopped>
+       <events>
+           <stagingActivityEvent>
+               <timestamp>2021-01-01T01:01:04.000Z</timestamp>
+               <name>repositoryReleased</name>
+               <severity>0</severity>
+               <properties>
+                   <stagingProperty>
+                       <name>id</name>
+                       <value>test-release-repo</value>
+                   </stagingProperty>
+               </properties>
+           </stagingActivityEvent>
+       </events>
+   </stagingActivity>
+</list>
index 0d05ec8..7c3930c 100644 (file)
@@ -21,6 +21,13 @@ from lftools.nexus import util
 FIXTURE_DIR = os.path.join(os.path.dirname(os.path.realpath(__file__)), "fixtures")
 
 
+@pytest.fixture
+def mock_get_credentials(mocker):
+    rtn = {"nexus": "http://nexus.localhost", "user": "user", "password": "password"}
+    mocker.patch("lftools.nexus.cmd.get_credentials", return_value=rtn)
+    mocker.patch("time.sleep", return_value=True)
+
+
 @pytest.fixture
 def nexus2_obj_create(responses):
     """Create the proper responses for the init of a nexus object"""
@@ -50,6 +57,28 @@ def test_create_roles(datafiles, responses, nexus2_obj_create):
     cmd.create_roles("role_config-good.yaml", "settings.yaml")
 
 
+@pytest.mark.datafiles(os.path.join(FIXTURE_DIR, "nexus"))
+def test_release_staging_repos(datafiles, responses, nexus2_obj_create, mock_get_credentials):
+    """Test create_roles() method with good config."""
+    os.chdir(str(datafiles))
+    baseurl = "http://nexus.localhost/service/local"
+    repos = ["test-release-repo"]
+    activity_url = "{}/staging/repository/{}/activity".format(baseurl, repos[0])
+    request_url = "{}/staging/bulk/promote".format(baseurl)
+
+    closed_return = open("staging_activities_closed.xml", "r").read()
+    released_return = open("staging_activities_released.xml", "r").read()
+
+    responses.add(responses.GET, activity_url, closed_return, status=200)
+    responses.add(responses.POST, request_url, status=201)
+    # While checking for the "release" activity, we return once without it in
+    # order to exercise the code for "if not released".
+    responses.add(responses.GET, activity_url, closed_return, status=200)
+    responses.add(responses.GET, activity_url, released_return, status=200)
+
+    cmd.release_staging_repos(repos, False)
+
+
 def test_create_repo_target_regex():
     """Test create_repo_target_regex() command."""