diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5d1e1af..02adaa2 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -73,4 +73,9 @@ jobs: run: | # Upgrade certi to fix SSL error due to the version installed in CKAN-2.8 image pip install --upgrade certifi - coveralls + # Run coveralls command with retry logic to handle potential transient issues + for attempt in 1 2 3; do + coveralls && break + echo "Attempt $attempt: Failed to submit coverage, retrying in 10 seconds..." + sleep 10 + done diff --git a/ckanext/subscribe/tests/test_action.py b/ckanext/subscribe/tests/test_action.py index b4ff683..f2d8e08 100644 --- a/ckanext/subscribe/tests/test_action.py +++ b/ckanext/subscribe/tests/test_action.py @@ -2,6 +2,7 @@ import datetime +import ckan.plugins.toolkit as tk import mock from ckan import model from ckan.plugins.toolkit import ValidationError @@ -223,102 +224,85 @@ def test_dataset_and_group_at_same_time(self, send_request_email): assert not send_request_email.called - # Adding the reCAPTCHA tests - @mock.patch("requests.post") - def test_verify_recaptcha_success(self, mock_post): - mock_post.return_value = mock.Mock(status_code=200) - mock_post.return_value.json.return_value = {"success": True} - - response = helpers.call_action( - "subscribe_signup", - {}, - email="bob@example.com", - dataset_id=factories.Dataset()["id"], - __extras={"g-recaptcha-response": "test-recaptcha-response"}, - ) - assert "email" in response - @mock.patch("requests.post") - def test_verify_recaptcha_failure(self, mock_post): - mock_post.return_value = mock.Mock(status_code=200) - mock_post.return_value.json.return_value = {"success": False} +# The reCAPTCHA tests +class TestRecaptchaOfSubscribeSignup(object): + def setup(self): + helpers.reset_db() + tk.config["ckanext.subscribe.apply_recaptcha"] = "true" - with assert_raises(ValidationError): - helpers.call_action( - "subscribe_signup", - {}, - email="bob@example.com", - dataset_id=factories.Dataset()["id"], - __extras={"g-recaptcha-response": "test-recaptcha-response"}, - ) + def teardown(self): + tk.config["ckanext.subscribe.apply_recaptcha"] = "false" + # mock the _verify_recaptcha function and test both + # successful and unsuccessful reCAPTCHA verification scenarios @mock.patch("requests.post") @mock.patch("ckanext.subscribe.email_verification.send_request_email") - def test_recaptcha_frontend_form(self, mock_post, send_request_email): - mock_post.return_value = mock.Mock(status_code=200) - mock_post.return_value.json.return_value = {"success": True} + @mock.patch("ckanext.subscribe.action._verify_recaptcha") + def test_verify_recaptcha_success( + self, mock_verify_recaptcha, send_request_email, mock_post + ): + # Mocking the reCAPTCHA verification to return True + mock_verify_recaptcha.return_value = True + mock_post.return_value = mock.Mock( + status_code=200, json=lambda: {"success": True} + ) dataset = factories.Dataset() + # Calling the subscribe_signup action with a mock reCAPTCHA response subscription = helpers.call_action( "subscribe_signup", {}, email="bob@example.com", dataset_id=dataset["id"], - __extras={"g-recaptcha-response": "test-recaptcha-response"}, + g_recaptcha_response="test-recaptcha-response", ) + # Asserting that the email verification function was called once send_request_email.assert_called_once() eq(send_request_email.call_args[0][0].object_type, "dataset") eq(send_request_email.call_args[0][0].object_id, dataset["id"]) eq(send_request_email.call_args[0][0].email, "bob@example.com") + + # Asserting that the subscription was created with the correct details eq(subscription["object_type"], "dataset") eq(subscription["object_id"], dataset["id"]) eq(subscription["email"], "bob@example.com") eq(subscription["verified"], False) assert "verification_code" not in subscription - subscription_obj = model.Session.query(Subscription).get(subscription["id"]) + + # Checking that the subscription object exists in the database + subscription_obj = model.Session.query(subscribe_model.Subscription).get( + subscription["id"] + ) assert subscription_obj - # Verify that 'g-recaptcha-response' was passed in __extras - extras = subscription["__extras"] - assert "g-recaptcha-response" in extras - eq(extras["g-recaptcha-response"], "test-recaptcha-response") - - -@mock.patch("requests.post") -@mock.patch("ckanext.subscribe.email_verification.send_request_email") -@mock.patch("ckan.plugins.toolkit.request") -def test_recaptcha_backend_form(self, mock_request, mock_post, send_request_email): - mock_post.return_value = mock.Mock(status_code=200) - mock_post.return_value.json.return_value = {"success": True} - - # Mock the request parameters to include g-recaptcha-response - mock_request.params = {"g-recaptcha-response": "test-recaptcha-response"} - - dataset = factories.Dataset() - - subscription = helpers.call_action( - "subscribe_signup", - {}, - email="bob@example.com", - dataset_id=dataset["id"], - ) - - send_request_email.assert_called_once() - eq(send_request_email.call_args[0][0].object_type, "dataset") - eq(send_request_email.call_args[0][0].object_id, dataset["id"]) - eq(send_request_email.call_args[0][0].email, "bob@example.com") - eq(subscription["object_type"], "dataset") - eq(subscription["object_id"], dataset["id"]) - eq(subscription["email"], "bob@example.com") - eq(subscription["verified"], False) - assert "verification_code" not in subscription - subscription_obj = model.Session.query(Subscription).get(subscription["id"]) - assert subscription_obj - - # Verify that 'g-recaptcha-response' was passed in request params - eq(mock_request.params.get("g-recaptcha-response"), "test-recaptcha-response") + @mock.patch("ckanext.subscribe.email_verification.send_request_email") + @mock.patch("ckanext.subscribe.action._verify_recaptcha") + def test_verify_recaptcha_failure(self, mock_verify_recaptcha, send_request_email): + # Mocking the reCAPTCHA verification to return False + mock_verify_recaptcha.return_value = False + + dataset = factories.Dataset() + + # Attempting to call subscribe_signup action with an invalid reCAPTCHA + try: + helpers.call_action( + "subscribe_signup", + {}, + email="bob@example.com", + dataset_id=dataset["id"], + g_recaptcha_response="wrong_recaptcha", + ) + except ValidationError as e: + # Asserting that the error is raised with the correct message + assert "Invalid reCAPTCHA. Please try again." in str(e.error_dict) + + # Ensuring the email is not sent due to invalid reCAPTCHA + assert not send_request_email.called + else: + assert False, "ValidationError not raised" class TestSubscribeVerify(object): diff --git a/test.ini b/test.ini index 2d61a4e..6f784b3 100644 --- a/test.ini +++ b/test.ini @@ -9,7 +9,7 @@ host = 0.0.0.0 port = 5000 [app:main] -use = config:/usr/lib/ckan/venv/src/ckan/test-core.ini +use = config:../ckan/test-core.ini # Insert any custom config settings to be used when running your extension's # tests here.