diff --git a/broker/client/client.go b/broker/client/client.go index cd9e08b4..62ecc582 100644 --- a/broker/client/client.go +++ b/broker/client/client.go @@ -31,8 +31,7 @@ const KindConfirmationError = "confirmation-error" const BrokerInfoStatus = iso18626.TypeStatusExpectToSupply -// TODO this must be removed and saved from the initial request -var BrokerSymbol = utils.GetEnv("BROKER_SYMBOL", "ISIL:BROKER") +var brokerSymbol = utils.GetEnv("BROKER_SYMBOL", "ISIL:BROKER") var appendSupplierInfo, _ = utils.GetEnvBool("SUPPLIER_INFO", true) var appendRequestingAgencyInfo, _ = utils.GetEnvBool("REQ_AGENCY_INFO", true) var appendReturnInfo, _ = utils.GetEnvBool("RETURN_INFO", true) @@ -486,14 +485,14 @@ func (c *Iso18626Client) getSelectedSupplierAndPeer(ctx extctx.ExtendedContext, } func (c *Iso18626Client) createMessageHeader(transaction ill_db.IllTransaction, sup *ill_db.LocatedSupplier, isRequestingMessage bool, brokerMode string) iso18626.Header { - requesterSymbol := strings.SplitN(BrokerSymbol, ":", 2) + requesterSymbol := strings.SplitN(brokerSymbol, ":", 2) if !isRequestingMessage || brokerMode == string(extctx.BrokerModeTransparent) { requesterSymbol = strings.SplitN(transaction.RequesterSymbol.String, ":", 2) } if len(requesterSymbol) < 2 { requesterSymbol = append(requesterSymbol, "") } - supplierSymbol := strings.SplitN(BrokerSymbol, ":", 2) + supplierSymbol := strings.SplitN(brokerSymbol, ":", 2) if sup != nil && sup.SupplierSymbol != "" && (isRequestingMessage || brokerMode == string(extctx.BrokerModeTransparent)) { supplierSymbol = strings.SplitN(sup.SupplierSymbol, ":", 2) } diff --git a/broker/handler/iso18626-handler.go b/broker/handler/iso18626-handler.go index 46c2137a..0cc95dda 100644 --- a/broker/handler/iso18626-handler.go +++ b/broker/handler/iso18626-handler.go @@ -25,23 +25,24 @@ import ( "github.com/jackc/pgx/v5/pgtype" ) +var brokerSymbol = utils.GetEnv("BROKER_SYMBOL", "ISIL:BROKER") + const HANDLER_COMP = "iso18626_handler" type ErrorValue string const ( - ReqIdAlreadyExists ErrorValue = "requestingAgencyRequestId: request with a given ID already exists" - ReqIdIsEmpty ErrorValue = "requestingAgencyRequestId: cannot be empty" - ReqIdNotFound ErrorValue = "requestingAgencyRequestId: request with a given ID not found" - RetryNotPossible ErrorValue = "requestType: Retry not possible" - SupplierNotFound ErrorValue = "supplyingAgencyId: located supplier cannot be found" - IncorrectSupplier ErrorValue = "supplyingAgencyId: not a selected supplier for this request" - UnsupportedRequestType ErrorValue = "requestType: unsupported value" - ReqAgencyNotFound ErrorValue = "requestingAgencyId: requesting agency not found" - CouldNotSendReqToPeer ErrorValue = "Could not send request to peer" - InvalidAction ErrorValue = "%v is not a valid action" - InvalidStatus ErrorValue = "%v is not a valid status" - InvalidReason ErrorValue = "%v is not a valid reason" + ReqIdAlreadyExists ErrorValue = "requestingAgencyRequestId: request with a given ID already exists" + ReqIdIsEmpty ErrorValue = "requestingAgencyRequestId: cannot be empty" + ReqIdNotFound ErrorValue = "requestingAgencyRequestId: request with a given ID not found" + RetryNotPossible ErrorValue = "requestType: Retry not possible" + SupplierNotFoundOrInvalid ErrorValue = "supplyingAgencyId: supplying agency not found or invalid" + UnsupportedRequestType ErrorValue = "requestType: unsupported value" + ReqAgencyNotFound ErrorValue = "requestingAgencyId: requesting agency not found" + CouldNotSendReqToPeer ErrorValue = "Could not send request to peer" + InvalidAction ErrorValue = "%v is not a valid action" + InvalidStatus ErrorValue = "%v is not a valid status" + InvalidReason ErrorValue = "%v is not a valid reason" ) const PublicFailedToProcessReqMsg = "failed to process request" @@ -333,25 +334,41 @@ func handleRequestingAgencyMessage(ctx extctx.ExtendedContext, illMessage *iso18 handleRequestingAgencyError(ctx, w, illMessage, iso18626.TypeErrorTypeUnrecognisedDataValue, ReqIdIsEmpty) return } - + symbol := getSupplierSymbol(&illMessage.RequestingAgencyMessage.Header) + if len(symbol) == 0 { + handleRequestingAgencyError(ctx, w, illMessage, iso18626.TypeErrorTypeUnrecognisedDataValue, SupplierNotFoundOrInvalid) + return + } eventData := events.EventData{ CommonEventData: events.CommonEventData{ IncomingMessage: illMessage, }, } - var err error var illTrans ill_db.IllTransaction var action iso18626.TypeAction + errorValue := ReqIdNotFound err = repo.WithTxFunc(ctx, func(repo ill_db.IllRepo) error { illTrans, err = repo.GetIllTransactionByRequesterRequestIdForUpdate(ctx, createPgText(requestingRequestId)) if err != nil { + errorValue = ReqIdNotFound return err } action = validateAction(ctx, illMessage, w, eventData, eventBus, illTrans) if action == "" { return nil } + if symbol != brokerSymbol { + supp, err := repo.GetSelectedSupplierForIllTransaction(ctx, illTrans.ID) + if err != nil { + errorValue = SupplierNotFoundOrInvalid + return err + } + if supp.SupplierSymbol != symbol { + errorValue = SupplierNotFoundOrInvalid + return pgx.ErrNoRows + } + } illTrans.PrevRequesterAction = illTrans.LastRequesterAction illTrans.LastRequesterAction = createPgText(string(action)) _, err = repo.SaveIllTransaction(ctx, ill_db.SaveIllTransactionParams(illTrans)) @@ -359,7 +376,7 @@ func handleRequestingAgencyMessage(ctx extctx.ExtendedContext, illMessage *iso18 }) if err != nil { if errors.Is(err, pgx.ErrNoRows) { - handleRequestingAgencyError(ctx, w, illMessage, iso18626.TypeErrorTypeUnrecognisedDataValue, ReqIdNotFound) + handleRequestingAgencyError(ctx, w, illMessage, iso18626.TypeErrorTypeUnrecognisedDataValue, errorValue) return } ctx.Logger().Error(InternalFailedToSaveTx, "error", err) @@ -383,6 +400,14 @@ func handleRequestingAgencyMessage(ctx extctx.ExtendedContext, illMessage *iso18 wg.Wait() } +func getSupplierSymbol(header *iso18626.Header) string { + if len(header.SupplyingAgencyId.AgencyIdType.Text) == 0 || len(header.SupplyingAgencyId.AgencyIdValue) == 0 { + return "" + } + return header.SupplyingAgencyId.AgencyIdType.Text + ":" + + header.SupplyingAgencyId.AgencyIdValue +} + func validateAction(ctx extctx.ExtendedContext, illMessage *iso18626.ISO18626Message, w http.ResponseWriter, eventData events.EventData, eventBus events.EventBus, illTrans ill_db.IllTransaction) iso18626.TypeAction { action, ok := iso18626.ActionMap[string(illMessage.RequestingAgencyMessage.Action)] if !ok { @@ -435,10 +460,9 @@ func handleSupplyingAgencyMessage(ctx extctx.ExtendedContext, illMessage *iso186 http.Error(w, PublicFailedToProcessReqMsg, http.StatusInternalServerError) return } - symbol := illMessage.SupplyingAgencyMessage.Header.SupplyingAgencyId.AgencyIdType.Text + ":" + - illMessage.SupplyingAgencyMessage.Header.SupplyingAgencyId.AgencyIdValue - if len(symbol) < 3 { - handleSupplyingAgencyError(ctx, w, illMessage, iso18626.TypeErrorTypeUnrecognisedDataValue, IncorrectSupplier) + symbol := getSupplierSymbol(&illMessage.SupplyingAgencyMessage.Header) + if len(symbol) == 0 { + handleSupplyingAgencyError(ctx, w, illMessage, iso18626.TypeErrorTypeUnrecognisedDataValue, SupplierNotFoundOrInvalid) return } requester, err := repo.GetPeerById(ctx, illTrans.RequesterID.String) @@ -468,18 +492,18 @@ func handleSupplyingAgencyMessage(ctx extctx.ExtendedContext, illMessage *iso186 return } if supplier.SupplierStatus != ill_db.SupplierStateSkippedPg { - handleSupplyingAgencyErrorWithNotice(ctx, w, illMessage, iso18626.TypeErrorTypeUnrecognisedDataValue, SupplierNotFound, + handleSupplyingAgencyErrorWithNotice(ctx, w, illMessage, iso18626.TypeErrorTypeUnrecognisedDataValue, SupplierNotFoundOrInvalid, eventBus, illTrans.ID) return } } else { - handleSupplyingAgencyErrorWithNotice(ctx, w, illMessage, iso18626.TypeErrorTypeUnrecognisedDataValue, IncorrectSupplier, + handleSupplyingAgencyErrorWithNotice(ctx, w, illMessage, iso18626.TypeErrorTypeUnrecognisedDataValue, SupplierNotFoundOrInvalid, eventBus, illTrans.ID) return } } if supplier.SupplierSymbol != symbol { //ensure we found the correct supplier - handleSupplyingAgencyErrorWithNotice(ctx, w, illMessage, iso18626.TypeErrorTypeUnrecognisedDataValue, IncorrectSupplier, + handleSupplyingAgencyErrorWithNotice(ctx, w, illMessage, iso18626.TypeErrorTypeUnrecognisedDataValue, SupplierNotFoundOrInvalid, eventBus, illTrans.ID) return } diff --git a/broker/handler/iso18626-handler_test.go b/broker/handler/iso18626-handler_test.go new file mode 100644 index 00000000..19b73b51 --- /dev/null +++ b/broker/handler/iso18626-handler_test.go @@ -0,0 +1,28 @@ +package handler + +import ( + "testing" + + "github.com/indexdata/crosslink/iso18626" + "github.com/stretchr/testify/assert" +) + +func TestGetSupplierSymbol(t *testing.T) { + header := &iso18626.Header{ + SupplyingAgencyId: iso18626.TypeAgencyId{ + AgencyIdType: iso18626.TypeSchemeValuePair{ + Text: "ISIL", + }, + AgencyIdValue: "12345", + }, + } + symbol := getSupplierSymbol(header) + assert.Equal(t, "ISIL:12345", symbol) + header.SupplyingAgencyId.AgencyIdType.Text = "" + symbol = getSupplierSymbol(header) + assert.Equal(t, "", symbol) + header.SupplyingAgencyId.AgencyIdType.Text = "ISIL" + header.SupplyingAgencyId.AgencyIdValue = "" + symbol = getSupplierSymbol(header) + assert.Equal(t, "", symbol) +} diff --git a/broker/test/handler/iso18626-handler_test.go b/broker/test/handler/iso18626-handler_test.go index c454d754..2f344c65 100644 --- a/broker/test/handler/iso18626-handler_test.go +++ b/broker/test/handler/iso18626-handler_test.go @@ -230,7 +230,7 @@ func TestIso18626PostSupplyingMessageIncorrectSupplier(t *testing.T) { assert.Equal(t, http.StatusOK, rr.Code) msgError := "ERROR" assert.Contains(t, rr.Body.String(), msgError) - errorValue := "supplyingAgencyId: not a selected supplier for this request" + errorValue := "supplyingAgencyId: supplying agency not found or invalid" assert.Contains(t, rr.Body.String(), errorValue) } @@ -288,11 +288,13 @@ func TestIso18626PostSupplyingMessageReqNotFound(t *testing.T) { func TestIso18626PostRequestingMessage(t *testing.T) { tests := []struct { - name string - status int - contains string - urlEnding string - useMock bool + name string + status int + contains string + urlEnding string + supplierSymbol string + skipped bool + useMock bool }{ { name: "ResponseSuccessful", @@ -322,35 +324,61 @@ func TestIso18626PostRequestingMessage(t *testing.T) { urlEnding: "/notExists", useMock: false, }, + { + name: "ResponseSupplierNotFoundOrInvalid-WrongSymbol", + status: 200, + contains: "supplyingAgencyId: supplying agency not found or invalid", + urlEnding: "", + supplierSymbol: "ISIL:SLNP_TWO_B", + useMock: true, + }, + { + name: "ResponseSupplierNotFoundOrInvalid-Skipped", + status: 200, + contains: "supplyingAgencyId: supplying agency not found or invalid", + urlEnding: "", + supplierSymbol: "ISIL:SLNP_TWO_A", + skipped: true, + useMock: true, + }, } appCtx := extctx.CreateExtCtxWithArgs(context.Background(), nil) - data, _ := os.ReadFile("../testdata/reqmsg-ok.xml") + data, _ := os.ReadFile("../testdata/reqmsg-notification.xml") illId := uuid.NewString() - requester := apptest.CreatePeer(t, illRepo, "isil:requester1", adapter.MOCK_CLIENT_URL) + requester := apptest.CreatePeer(t, illRepo, "ISIL:SLNP_ONE", adapter.MOCK_CLIENT_URL) _, err := illRepo.SaveIllTransaction(appCtx, ill_db.SaveIllTransactionParams{ ID: illId, Timestamp: test.GetNow(), RequesterRequestID: apptest.CreatePgText("reqid"), - RequesterSymbol: apptest.CreatePgText("isil:requester1"), + RequesterSymbol: apptest.CreatePgText("ISIL:SLNP_ONE"), RequesterID: apptest.CreatePgText(requester.ID), }) if err != nil { t.Errorf("failed to create ill transaction: %s", err) } - peer := apptest.CreatePeer(t, illRepo, "isil:reqTest", adapter.MOCK_CLIENT_URL) - apptest.CreateLocatedSupplier(t, illRepo, illId, peer.ID, "isil:reqTest", "selected") - + supplier := apptest.CreatePeer(t, illRepo, "ISIL:SLNP_TWO_A", adapter.MOCK_CLIENT_URL) + locSup := apptest.CreateLocatedSupplier(t, illRepo, illId, supplier.ID, "ISIL:SLNP_TWO_A", "selected") for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.useMock { - peer.Url = adapter.MOCK_CLIENT_URL + tt.urlEnding + supplier.Url = adapter.MOCK_CLIENT_URL + tt.urlEnding } else { port, _ := test.GetFreePort() - peer.Url = "http:localhost:" + strconv.Itoa(port) + tt.urlEnding + supplier.Url = "http:localhost:" + strconv.Itoa(port) + tt.urlEnding + } + supplier, err = illRepo.SavePeer(appCtx, ill_db.SavePeerParams(supplier)) + if err != nil { + t.Errorf("failed to update supplier peer : %s", err) + } + if tt.supplierSymbol != "" { + locSup.SupplierSymbol = tt.supplierSymbol + } + if tt.skipped { + locSup.SupplierStatus = ill_db.SupplierStateSkippedPg } - peer, err = illRepo.SavePeer(appCtx, ill_db.SavePeerParams(peer)) + _, err := illRepo.SaveLocatedSupplier(appCtx, ill_db.SaveLocatedSupplierParams(locSup)) if err != nil { - t.Errorf("failed to update peer : %s", err) + t.Errorf("failed to update located supplier : %s", err) } url := "http://localhost:" + strconv.Itoa(app.HTTP_PORT) + "/iso18626" req, _ := http.NewRequest("POST", url, bytes.NewReader(data)) diff --git a/broker/test/testdata/reqmsg-notification.xml b/broker/test/testdata/reqmsg-notification.xml new file mode 100644 index 00000000..9c89ddf3 --- /dev/null +++ b/broker/test/testdata/reqmsg-notification.xml @@ -0,0 +1,25 @@ + + + +
+ + ISIL + SLNP_TWO_A + + + ISIL + SLNP_ONE + + + 2024-12-12T20:12:00.62959771Z + reqid + c488bef0-5735-4c33-ba13-a9f343447574 +
+ Notification +
+