From 3ff99619ac8bf20ca7ced587396aee1e07cf1990 Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Wed, 8 Jul 2026 10:24:54 +0000 Subject: [PATCH 1/3] =?UTF-8?q?Fire=20Abri=20flows=20on=20a=20test=20proje?= =?UTF-8?q?ct=20code=20via=20an=20override=20env=20var=20=F0=9F=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 --- etl/hubspot/tests/test_abri_flow_triggers.py | 27 ++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/etl/hubspot/tests/test_abri_flow_triggers.py b/etl/hubspot/tests/test_abri_flow_triggers.py index 0e7eb320b..e6f5631f6 100644 --- a/etl/hubspot/tests/test_abri_flow_triggers.py +++ b/etl/hubspot/tests/test_abri_flow_triggers.py @@ -2,6 +2,8 @@ from datetime import datetime, timezone from typing import Any, Dict import uuid +import pytest + from backend.app.db.models.hubspot_deal_data import HubspotDealData from etl.hubspot.hubspot_deal_differ import HubspotDealDiffer @@ -187,6 +189,31 @@ def test_no_message_for_a_non_abri_deal() -> None: assert message is None +def test_the_test_override_env_var_fires_a_deal_on_its_own_project_code( + monkeypatch: pytest.MonkeyPatch, +) -> None: + # Arrange: a sandbox deal on its own project code, with the test override + # pointing the gate at that code so it fires like a production Abri deal. + monkeypatch.setenv("TEST_ABRI_PROJECT_CODE_OVERRIDE", "TEST-SANDBOX-CODE") + old_deal = make_old_deal(project_code="TEST-SANDBOX-CODE", confirmed_survey_date=None) + new_deal = make_new_deal( + project_code="TEST-SANDBOX-CODE", confirmed_survey_date="2026-06-24" + ) + + # Act + message = HubspotDealDiffer.check_abri_triggers_and_construct_message( + hubspot_deal_id=DEAL_ID, + new_deal=new_deal, + new_project=None, + new_listing=LISTING, + old_deal=old_deal, + ) + + # Assert + assert message is not None + assert message["flows"] == ["log_job"] + + def test_a_deal_crossing_into_abandonment_builds_an_abandon_job_message() -> None: # Arrange: attempts reach the threshold with a negative outcome, so the # deal crosses into the abandoned state and the abandon flow fires. From 002f782905c7d28d599c3cb3bb12ed8312f0ecd5 Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Wed, 8 Jul 2026 10:25:45 +0000 Subject: [PATCH 2/3] =?UTF-8?q?Fire=20Abri=20flows=20on=20a=20test=20proje?= =?UTF-8?q?ct=20code=20via=20an=20override=20env=20var=20=F0=9F=9F=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 --- etl/hubspot/hubspot_deal_differ.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/etl/hubspot/hubspot_deal_differ.py b/etl/hubspot/hubspot_deal_differ.py index eb48fd464..22d7fb83c 100644 --- a/etl/hubspot/hubspot_deal_differ.py +++ b/etl/hubspot/hubspot_deal_differ.py @@ -1,3 +1,4 @@ +import os from typing import Any, Dict, List, Optional from backend.app.db.models.hubspot_deal_data import HubspotDealData @@ -344,8 +345,15 @@ class HubspotDealDiffer: == HubspotDealDiffer.ABRI_CONDITION_ASSOCIATED_PROJECT_ID ) + # TEST_ABRI_PROJECT_CODE_OVERRIDE lets a non-production deploy fire on a + # sandbox deal's own project code; unset (the production default) falls + # back to the real stock-condition code. + expected_code = ( + os.environ.get("TEST_ABRI_PROJECT_CODE_OVERRIDE") + or HubspotDealDiffer.ABRI_CONDITION_PROJECT_CODE + ) new_project_code = (new_deal.get("project_code") or "").lower() - return new_project_code == HubspotDealDiffer.ABRI_CONDITION_PROJECT_CODE.lower() + return new_project_code == expected_code.lower() @staticmethod def _has_valid_pashub_link(new_pashub_link: str) -> bool: From 8e880eea6fcf7cf1bece36700a91f066432e16cf Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Wed, 8 Jul 2026 10:28:48 +0000 Subject: [PATCH 3/3] =?UTF-8?q?Expose=20the=20Abri=20test=20project-code?= =?UTF-8?q?=20override=20to=20the=20scraper=20lambda=20=F0=9F=9F=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wires TEST_ABRI_PROJECT_CODE_OVERRIDE from an optional deploy-time tfvar through to the hubspot_deal_etl lambda env; unset keeps production behaviour. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/_deploy_lambda.yml | 3 +++ .github/workflows/deploy_terraform.yml | 4 ++++ .../terraform/lambda/hubspot_deal_etl/main.tf | 18 ++++++++++-------- .../lambda/hubspot_deal_etl/variables.tf | 8 ++++++++ 4 files changed, 25 insertions(+), 8 deletions(-) diff --git a/.github/workflows/_deploy_lambda.yml b/.github/workflows/_deploy_lambda.yml index e8e2de981..6a3d9c328 100644 --- a/.github/workflows/_deploy_lambda.yml +++ b/.github/workflows/_deploy_lambda.yml @@ -109,6 +109,8 @@ on: required: false TF_VAR_abri_relay_default_resource: required: false + TF_VAR_test_abri_project_code_override: + required: false jobs: deploy: runs-on: ubuntu-latest @@ -188,6 +190,7 @@ jobs: TF_VAR_abri_relay_username: ${{ secrets.TF_VAR_abri_relay_username }} TF_VAR_abri_relay_password: ${{ secrets.TF_VAR_abri_relay_password }} TF_VAR_abri_relay_default_resource: ${{ secrets.TF_VAR_abri_relay_default_resource }} + TF_VAR_test_abri_project_code_override: ${{ secrets.TF_VAR_test_abri_project_code_override }} run: | ECR_REPO_URL_VAR="" if [[ -n "${{ inputs.ecr_repo }}" ]]; then diff --git a/.github/workflows/deploy_terraform.yml b/.github/workflows/deploy_terraform.yml index 8b9418efc..7ddbd9c8e 100644 --- a/.github/workflows/deploy_terraform.yml +++ b/.github/workflows/deploy_terraform.yml @@ -837,3 +837,7 @@ jobs: AWS_ACCESS_KEY_ID: ${{ secrets.DEV_AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.DEV_AWS_SECRET_ACCESS_KEY }} AWS_REGION: ${{ secrets.DEV_AWS_REGION }} + # Temporary Abri end-to-end-test toggle. Unset ⇒ empty ⇒ the differ keeps + # the production stock-condition project code. Set this repo secret to a + # sandbox deal's project code to test, then delete it. + TF_VAR_test_abri_project_code_override: ${{ secrets.TF_VAR_test_abri_project_code_override }} diff --git a/deployment/terraform/lambda/hubspot_deal_etl/main.tf b/deployment/terraform/lambda/hubspot_deal_etl/main.tf index 0c06ea7c0..3467bf724 100644 --- a/deployment/terraform/lambda/hubspot_deal_etl/main.tf +++ b/deployment/terraform/lambda/hubspot_deal_etl/main.tf @@ -2,7 +2,7 @@ data "terraform_remote_state" "shared" { backend = "s3" config = { bucket = "assessment-model-terraform-state" - key = "env:/${var.stage}/terraform.tfstate" + key = "env:/${var.stage}/terraform.tfstate" region = "eu-west-2" } } @@ -57,18 +57,20 @@ module "hubspot_deal_etl" { batch_size = var.batch_size environment = { - STAGE = var.stage - LOG_LEVEL = "info" - DB_USERNAME = local.db_credentials.db_assessment_model_username - DB_PASSWORD = local.db_credentials.db_assessment_model_password - DB_HOST = var.db_host - DB_NAME = var.db_name - DB_PORT = var.db_port + STAGE = var.stage + LOG_LEVEL = "info" + DB_USERNAME = local.db_credentials.db_assessment_model_username + DB_PASSWORD = local.db_credentials.db_assessment_model_password + DB_HOST = var.db_host + DB_NAME = var.db_name + DB_PORT = var.db_port HUBSPOT_API_KEY = var.hubspot_api_key PASHUB_TO_ARA_SQS_URL = data.terraform_remote_state.pashub_to_ara.outputs.pashub_to_ara_queue_url MAGICPLAN_SQS_URL = data.terraform_remote_state.magic_plan.outputs.magic_plan_queue_url ABRI_SQS_URL = data.terraform_remote_state.abri.outputs.abri_api_queue_url + + TEST_ABRI_PROJECT_CODE_OVERRIDE = var.test_abri_project_code_override } } diff --git a/deployment/terraform/lambda/hubspot_deal_etl/variables.tf b/deployment/terraform/lambda/hubspot_deal_etl/variables.tf index 189822f04..cd8208543 100644 --- a/deployment/terraform/lambda/hubspot_deal_etl/variables.tf +++ b/deployment/terraform/lambda/hubspot_deal_etl/variables.tf @@ -52,4 +52,12 @@ variable "db_name" { variable "db_port" { type = string +} + +# Temporary end-to-end-test toggle: overrides the hardcoded Abri stock-condition +# project code the deal differ gates on, so a sandbox deal on its own project +# code fires the Abri flows. Empty (the default) keeps the production code. +variable "test_abri_project_code_override" { + type = string + default = "" } \ No newline at end of file