diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index a2d6b9d051f..96eaf7a33b4 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -104,7 +104,7 @@ jobs: run: ln -s docker-compose.override.integration_tests.yml docker-compose.override.yml - name: Start Dojo - run: docker compose up --no-deps -d postgres nginx celerybeat celeryworker mailhog uwsgi valkey + run: docker compose up --no-deps -d postgres nginx celerybeat celeryworker mailhog uwsgi valkey webhook.endpoint env: DJANGO_VERSION: ${{ matrix.os }} NGINX_VERSION: alpine diff --git a/docker-compose.override.integration_tests.yml b/docker-compose.override.integration_tests.yml index 611becefbec..71085eedd68 100644 --- a/docker-compose.override.integration_tests.yml +++ b/docker-compose.override.integration_tests.yml @@ -72,6 +72,8 @@ services: published: 1025 protocol: tcp mode: host + "webhook.endpoint": + image: mccutchen/go-httpbin:2.18.3@sha256:3992f3763e9ce5a4307eae0a869a78b4df3931dc8feba74ab823dd2444af6a6b volumes: defectdojo_postgres_integration_tests: {} defectdojo_media_integration_tests: {} diff --git a/tests/notification_webhook_test.py b/tests/notification_webhook_test.py index f5e9f202aa5..71daaa0ad45 100644 --- a/tests/notification_webhook_test.py +++ b/tests/notification_webhook_test.py @@ -3,10 +3,27 @@ from base_test_class import BaseTestCase, on_exception_html_source_logger from selenium.webdriver.common.by import By +from selenium.webdriver.support import expected_conditions +from selenium.webdriver.support.ui import WebDriverWait + +# Local go-httpbin mock wired into the integration-test stack (see +# docker-compose.override.integration_tests.yml). DefectDojo pings this URL +# synchronously when a webhook is saved, so it must resolve from the uwsgi +# container. Never point this at a public service (e.g. httpbin.org): that adds +# an external network dependency and makes this test flaky. +WEBHOOK_ENDPOINT_URL = "http://webhook.endpoint:8080/post" class NotificationWebhookTest(BaseTestCase): + def wait_for_alert(self): + """Wait for a Bootstrap alert to render after a form submit.""" + WebDriverWait(self.driver, 30).until( + expected_conditions.presence_of_element_located( + (By.CSS_SELECTOR, ".alert-success, .alert-danger"), + ), + ) + @on_exception_html_source_logger def test_enable_webhook_notifications(self): """Enable webhook notifications in system settings.""" @@ -22,10 +39,7 @@ def test_enable_webhook_notifications(self): def test_list_webhooks_page_loads(self): driver = self.driver driver.get(self.base_url + "notifications/webhooks") - self.assertTrue( - self.is_text_present_on_page(text="Notification Webhook") - or self.is_text_present_on_page(text="Webhook"), - ) + self.assertTrue(self.is_text_present_on_page(text="Webhook")) @on_exception_html_source_logger def test_add_notification_webhook(self): @@ -34,13 +48,13 @@ def test_add_notification_webhook(self): driver.find_element(By.ID, "id_name").clear() driver.find_element(By.ID, "id_name").send_keys("Test Webhook") driver.find_element(By.ID, "id_url").clear() - driver.find_element(By.ID, "id_url").send_keys("https://httpbin.org/post") + driver.find_element(By.ID, "id_url").send_keys(WEBHOOK_ENDPOINT_URL) driver.find_element(By.CSS_SELECTOR, "input.btn.btn-primary").click() - self.assertTrue( - self.is_text_present_on_page(text="Test Webhook") - or self.is_text_present_on_page(text="Webhook"), - ) + self.wait_for_alert() + self.assertFalse(self.is_error_message_present()) + self.assertTrue(self.is_success_message_present(text="Notification Webhook added successfully.")) + self.assertTrue(self.is_text_present_on_page(text="Test Webhook")) @on_exception_html_source_logger def test_edit_notification_webhook(self): @@ -48,17 +62,20 @@ def test_edit_notification_webhook(self): driver.get(self.base_url + "notifications/webhooks") # Click Edit link from the webhooks list (link text is "Edit / activate / deactivate") edit_links = driver.find_elements(By.CSS_SELECTOR, "a.btn.btn-warning") - if len(edit_links) > 0: - edit_links[0].click() - driver.find_element(By.ID, "id_name").clear() - driver.find_element(By.ID, "id_name").send_keys("Edited Test Webhook") - driver.find_element(By.CSS_SELECTOR, "input.btn.btn-primary").click() - self.assertTrue( - self.is_text_present_on_page(text="Edited Test Webhook") - or self.is_text_present_on_page(text="Webhook"), - ) - else: + if len(edit_links) == 0: self.fail("No Edit link found for webhook") + edit_links[0].click() + driver.find_element(By.ID, "id_name").clear() + driver.find_element(By.ID, "id_name").send_keys("Edited Test Webhook") + # Ensure the endpoint stays pointed at the local mock so the save-time ping succeeds. + driver.find_element(By.ID, "id_url").clear() + driver.find_element(By.ID, "id_url").send_keys(WEBHOOK_ENDPOINT_URL) + driver.find_element(By.CSS_SELECTOR, "input.btn.btn-primary").click() + + self.wait_for_alert() + self.assertFalse(self.is_error_message_present()) + self.assertTrue(self.is_success_message_present(text="Notification Webhook updated successfully.")) + self.assertTrue(self.is_text_present_on_page(text="Edited Test Webhook")) @on_exception_html_source_logger def test_delete_notification_webhook(self): @@ -66,15 +83,14 @@ def test_delete_notification_webhook(self): driver.get(self.base_url + "notifications/webhooks") # Click Delete link from the webhooks list delete_links = driver.find_elements(By.CSS_SELECTOR, "a.btn.btn-danger") - if len(delete_links) > 0: - delete_links[0].click() - driver.find_element(By.CSS_SELECTOR, "input.btn.btn-danger").click() - self.assertTrue( - self.is_text_present_on_page(text="Webhook") - or not self.is_error_message_present(), - ) - else: + if len(delete_links) == 0: self.fail("No Delete link found for webhook") + delete_links[0].click() + driver.find_element(By.CSS_SELECTOR, "input.btn.btn-danger").click() + + self.wait_for_alert() + self.assertFalse(self.is_error_message_present()) + self.assertTrue(self.is_success_message_present(text="Notification Webhook deleted successfully.")) @on_exception_html_source_logger def test_disable_webhook_notifications(self):