Skip to content

Commit

Permalink
Merge effc174 into c2d0d38
Browse files Browse the repository at this point in the history
  • Loading branch information
acsauk authored Feb 18, 2025
2 parents c2d0d38 + effc174 commit 6d09bde
Show file tree
Hide file tree
Showing 7 changed files with 227 additions and 29 deletions.
2 changes: 1 addition & 1 deletion .codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ coverage:
- "**/*_test.go"
- "**/enum_*.go"
- "./cmd/create-s3-replication-job/main.go"
- "./cmd/event-logger/main.go"
- "./cmd/event-logger/*"
- "./cmd/event-received/main.go"
- "./cmd/mlpa/main.go"
- "./cmd/mock-notify/main.go"
Expand Down
20 changes: 6 additions & 14 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -210,22 +210,14 @@ emit-object-tags-added-without-virus: ##@events emits a ObjectTagging:Put event
--payload '{"Records":[{"eventSource":"aws:s3","eventTime":"2023-10-23T15:58:33.081Z","eventName":"ObjectTagging:Put","s3":{"bucket":{"name":"uploads-opg-modernising-lpa-eu-west-1"},"object":{"key":"$(key)"}}}]}'

emit-immaterial-change-confirmed: ##@events emits a immaterial-change-confirmed event with the given LpaUID, actor type an actor UID e.g. emit-immaterial-change-confirmed uid=abc-123 actorType=donor actorUid=def-456
$(eval BODY := $(shell echo '{"version":"0","id":"63eb7e5f-1f10-4744-bba9-e16d327c3b98","detail-type":"immaterial-change-confirmed","source":"opg.poas.sirius","account":"653761790766","time":"2023-08-30T13:40:30Z","region":"eu-west-1","resources":[],"detail":{"uid":"$(uid)","actorType":"$(actorType)","actorUid":"$(actorUid)","sentDate":"2024-01-02T12:13:14.000006Z"}}' | sed 's/"/\\"/g'))

docker compose -f docker/docker-compose.yml exec localstack awslocal lambda invoke \
--endpoint-url=http://localhost:4566 \
--region eu-west-1 \
--function-name event-received text \
--payload '{"Records": [{"messageId": "19dd0b57-b21e-4ac1-bd88-01bbb068cb78", "body": "$(BODY)"}]}'
curl -X POST "localhost:9001/emit/immaterial-change-confirmed" \
-H "Content-Type: application/json" \
-d '{"uid": "'$${uid}'", "actorType": "'$${actorType}'", "actorUID": "'$${actorUID}'"}'

emit-material-change-confirmed: ##@events emits a material-change-confirmed event with the given LpaUID, actor type an actor UID e.g. emit-material-change-confirmed uid=abc-123 actorType=donor actorUid=def-456
$(eval BODY := $(shell echo '{"version":"0","id":"63eb7e5f-1f10-4744-bba9-e16d327c3b98","detail-type":"material-change-confirmed","source":"opg.poas.sirius","account":"653761790766","time":"2023-08-30T13:40:30Z","region":"eu-west-1","resources":[],"detail":{"uid":"$(uid)","actorType":"$(actorType)","actorUid":"$(actorUid)","sentDate":"2024-01-02T12:13:14.000006Z"}}' | sed 's/"/\\"/g'))

docker compose -f docker/docker-compose.yml exec localstack awslocal lambda invoke \
--endpoint-url=http://localhost:4566 \
--region eu-west-1 \
--function-name event-received text \
--payload '{"Records": [{"messageId": "19dd0b57-b21e-4ac1-bd88-01bbb068cb78", "body": "$(BODY)"}]}'
curl -X POST "localhost:9001/emit/material-change-confirmed" \
-H "Content-Type: application/json" \
-d '{"uid": "'$${uid}'", "actorType": "'$${actorType}'", "actorUID": "'$${actorUID}'"}'

set-uploads-clean: ##@events calls emit-object-tags-added-without-virus for all documents on a given lpa e.g. set-uploads-clean lpaId=abc
for k in $$(docker compose -f docker/docker-compose.yml exec localstack awslocal dynamodb --region eu-west-1 query --table-name lpas --key-condition-expression 'PK = :pk and begins_with(SK, :sk)' --expression-attribute-values '{":pk": {"S": "LPA#$(lpaId)"}, ":sk": {"S": "DOCUMENT#"}}' | jq -c -r '.Items[] | .Key[]'); do \
Expand Down
54 changes: 54 additions & 0 deletions cmd/event-logger/event_sender.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package main

import (
"context"
"encoding/json"
"fmt"
"time"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/sqs"
)

type sqsClient struct {
svc *sqs.Client
queueURL string
}

type CloudWatchEvent struct {
Version string `json:"version"`
ID string `json:"id"`
DetailType string `json:"detail-type"`
Source string `json:"source"`
Account string `json:"account"`
Time time.Time `json:"time"`
Region string `json:"region"`
Resources []string `json:"resources"`
Detail json.RawMessage `json:"detail"`
}

func (c sqsClient) SendMessage(ctx context.Context, detailType string, detail json.RawMessage) error {
v, err := json.Marshal(CloudWatchEvent{
Version: "0",
ID: "63eb7e5f-1f10-4744-bba9-e16d327c3b98",
DetailType: detailType,
Source: "opg.poas.sirius",
Account: "653761790766",
Time: time.Now().UTC(),
Region: "eu-west-1",
Resources: []string{},
Detail: detail,
})
if err != nil {
return err
}

if _, err = c.svc.SendMessage(ctx, &sqs.SendMessageInput{
QueueUrl: aws.String(c.queueURL),
MessageBody: aws.String(string(v)),
}); err != nil {
return fmt.Errorf("failed to send %s message: %w", detailType, err)
}

return nil
}
49 changes: 44 additions & 5 deletions cmd/event-logger/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import (
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/sqs"
"github.com/aws/aws-sdk-go-v2/service/sqs/types"
sqstypes "github.com/aws/aws-sdk-go-v2/service/sqs/types"
"github.com/ministryofjustice/opg-go-common/env"
)

Expand All @@ -41,6 +41,8 @@ type message struct {
Source string
}

var cfg aws.Config

func main() {
var (
awsBaseURL = env.Get("AWS_BASE_URL", "")
Expand All @@ -52,7 +54,8 @@ func main() {
messages []message
)

cfg, err := config.LoadDefaultConfig(ctx)
var err error
cfg, err = config.LoadDefaultConfig(ctx)
if err != nil {
log.Fatal(fmt.Errorf("unable to load SDK config: %w", err))
}
Expand All @@ -77,7 +80,7 @@ func main() {
}

messageResponse, err := client.ReceiveMessage(ctx, &sqs.ReceiveMessageInput{
MessageAttributeNames: []string{string(types.QueueAttributeNameAll)},
MessageAttributeNames: []string{string(sqstypes.QueueAttributeNameAll)},
QueueUrl: aws.String(queueURL),
MaxNumberOfMessages: 10, // may as well ask for as many as possible
VisibilityTimeout: 5,
Expand All @@ -92,10 +95,10 @@ func main() {
continue
}

var toDelete []types.DeleteMessageBatchRequestEntry
var toDelete []sqstypes.DeleteMessageBatchRequestEntry

for _, m := range messageResponse.Messages {
toDelete = append(toDelete, types.DeleteMessageBatchRequestEntry{Id: m.MessageId, ReceiptHandle: m.ReceiptHandle})
toDelete = append(toDelete, sqstypes.DeleteMessageBatchRequestEntry{Id: m.MessageId, ReceiptHandle: m.ReceiptHandle})

var v message
if err := json.Unmarshal([]byte(*m.Body), &v); err != nil {
Expand Down Expand Up @@ -167,5 +170,41 @@ func main() {
fmt.Fprint(w, "</tbody></table></body>")
})

http.HandleFunc("/emit/{detailType}", func(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodPost {
sqsClient := &sqsClient{
svc: sqs.NewFromConfig(cfg),
queueURL: "http://localhost:4566/000000000000/event-bus-queue",
}

detailType := r.PathValue("detailType")
if detailType == "" {
log.Println("missing detail type from path")
}

var detail json.RawMessage
if err := json.NewDecoder(r.Body).Decode(&detail); err != nil {
log.Printf("failed to unmarshal %s: %v", detailType, err)
}

var sendErr error

switch detailType {
case "immaterial-change-confirmed":
sendErr = sqsClient.SendMessage(r.Context(), detailType, detail)
case "material-change-confirmed":
sendErr = sqsClient.SendMessage(r.Context(), detailType, detail)
default:
log.Println("unsupported event type:", detailType)
}

if sendErr != nil {
log.Printf("failed to send %s: %v", detailType, err)
} else {
log.Println("successfully handled", detailType)
}
}
})

http.ListenAndServe(":"+port, nil)
}
89 changes: 80 additions & 9 deletions cypress/e2e/donor/progress.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -259,14 +259,85 @@ describe('Progress', () => {
cy.contains('You do not need to take any action');
});

// TODO add test when we can send events during test runs (or some other work around)
// it('when identity mismatch resolved as immaterial', () => {
//
// });

// TODO add test when we can send events during test runs (or some other work around)
// it('when identity mismatch resolved as material', () => {
//
// });
it('when identity mismatch resolved as immaterial', () => {
cy.visit(`/fixtures?redirect=/task-list&progress=signTheLpa&idStatus=donor:mismatch`);
cy.visitLpa('/progress');

cy.checkA11yApp();
cy.contains('Important: 2 notifications from OPG');

cy.contains('Confirmation of identity pending');
cy.contains('You do not need to take any action');

cy.contains('.govuk-summary-list__row', 'Reference number').find('.govuk-summary-list__value')
.invoke('text')
.then((uid) => {
cy.request({
method: 'POST',
url: 'http://localhost:9001/emit/immaterial-change-confirmed',
body: {
uid: uid.trim(),
actorType: 'donor',
actorUid: 'abc',
},
}).then((response) => {
expect(response.status).to.eq(200);

cy.visitLpa('/progress')
cy.waitForTextByReloading('main', 'Success: 1 notification from OPG')

cy.checkA11yApp();

cy.contains('Your identity has been confirmed');
cy.contains('You do not need to take any action.');

cy.reload()

cy.contains('Success: 1 notification from OPG').should('not.exist');
});
});
});

it('when identity mismatch resolved as material', () => {
cy.visit(`/fixtures?redirect=/task-list&progress=signTheLpa&idStatus=donor:mismatch`);
cy.visitLpa('/progress');

cy.checkA11yApp();
cy.contains('Important: 2 notifications from OPG');

cy.contains('Confirmation of identity pending');
cy.contains('You do not need to take any action');

cy.contains('.govuk-summary-list__row', 'Reference number').find('.govuk-summary-list__value')
.invoke('text')
.then((uid) => {
cy.request({
method: 'POST',
url: 'http://localhost:9001/emit/material-change-confirmed',
body: {
uid: uid.trim(),
actorType: 'donor',
actorUid: 'abc',
},
}).then((response) => {
expect(response.status).to.eq(200);

cy.visitLpa('/progress')
cy.waitForTextByReloading('main', 'Your LPA cannot be registered by the Office of the Public Guardian (OPG)')

cy.checkA11yApp();

cy.reload()

const date = new Date().toLocaleDateString('en-GB', {
day: 'numeric',
month: 'long',
year: 'numeric'
});

cy.contains(`We contacted you on ${date} with guidance about what to do next.`);
});
});
});
});
});
31 changes: 31 additions & 0 deletions cypress/support/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,34 @@ Cypress.Commands.add('checkA11yApp', (options= {}) => {
Cypress.Commands.add('visitLpa', (path, opts = {}) => {
cy.url().then(u => cy.visit(u.split('/').slice(3, -1).join('/') + path, opts));
});

// Function to poll a page until element contains text or timeout occurs
Cypress.Commands.add('waitForTextByReloading', (selector, expectedText) => {
const options = {
timeout: 6000,
interval: 500,
};

const startTime = Date.now();

const checkTextAndReload = () => {
return cy.get('body').then($body => {
const $el = $body.find(selector);
const found = $el.length > 0 && $el.text().includes(expectedText);

if (found) {
return;
}

if (Date.now() - startTime >= options.timeout) {
throw new Error(`Timed out after ${options.timeout}ms waiting for "${selector}" to contain "${expectedText}"`);
}

cy.reload();
cy.wait(options.interval);
cy.then(checkTextAndReload);
});
};

return cy.then(checkTextAndReload);
});
11 changes: 11 additions & 0 deletions internal/page/fixtures/donor.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ func Donor(
identity.StatusExpired.String(),
"post-office",
"vouched",
"mismatch",
},
})
}
Expand Down Expand Up @@ -519,6 +520,16 @@ func updateLPAProgress(
if err = voucherStore.Put(r.Context(), voucherDetails); err != nil {
return nil, nil, fmt.Errorf("error persisting voucher: %v", err)
}
case "mismatch":
userData = identity.UserData{
Status: identity.StatusConfirmed,
CheckedAt: time.Now(),
FirstNames: donorDetails.Donor.FirstNames + " 1",
LastName: donorDetails.Donor.LastName + " 2",
DateOfBirth: donorDetails.Donor.DateOfBirth,
}
donorDetails.Tasks.ConfirmYourIdentity = task.IdentityStatePending
donorDetails.ContinueWithMismatchedIdentity = true
default:
userData = identity.UserData{
Status: identity.StatusConfirmed,
Expand Down

0 comments on commit 6d09bde

Please sign in to comment.