package notificationexecutor import ( "encoding/json" "net/http" "net/http/httptest" "testing" "git.cin.su/m/Assistant/contracts/capability" commitcontract "git.cin.su/m/Assistant/contracts/commit" "git.cin.su/m/Assistant/contracts/identity" ) func testAction(t *testing.T) commitcontract.AuthorizedAction { t.Helper() payload := Payload{ActionIntentID: "intent-1", TemplateCode: commitcontract.ProspectiveDeliveredTemplateV1, ProspectiveItemID: "item-1", ExpectedRevision: 2, Title: "Домовой", Message: "Пора вернуться к задаче"} digest, err := Digest(payload) if err != nil { t.Fatal(err) } return commitcontract.AuthorizedAction{PrincipalID: identity.PrincipalID("owner-1"), Proposal: commitcontract.ActionProposal{ IntentID: payload.ActionIntentID, CapabilityID: commitcontract.CapabilityProspectiveNotification, Operation: commitcontract.OperationDeliverProspectiveNotification, NotificationSubject: commitcontract.ProspectiveNotificationSubject{ProspectiveItemID: "item-1", ExpectedRevision: 2, TemplateCode: payload.TemplateCode, BindingID: "binding-1", BindingRevision: 1, RenderedTitle: payload.Title, RenderedMessage: payload.Message, RequestDigest: digest}, }} } func testBinding(origin string) capability.Binding { return capability.Binding{ID: "binding-1", CapabilityID: commitcontract.CapabilityProspectiveNotification, OwnerPrincipalID: "owner-1", Revision: 1, State: capability.BindingActive, HTTPSOrigin: origin, DeliveryPath: "/delivery/v1/deliveries", ReceiptPath: "/delivery/v1/receipts", Protocol: capability.ProtocolIdempotentReceiptV1, SecretRef: "write-v1", VerifiedAtUnixMillis: 1, Health: capability.HealthAvailable} } func TestExecutorPutAndReconcileMatchReceipt(t *testing.T) { action := testAction(t) server := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.Header.Get("Authorization") != "Bearer secret" { t.Error("missing credential") } if r.Method == http.MethodPut && r.URL.Path != "/delivery/v1/deliveries/intent-1" { t.Errorf("bad put path %s", r.URL.Path) } if r.Method == http.MethodGet && r.URL.Path != "/delivery/v1/receipts/intent-1" { t.Errorf("bad get path %s", r.URL.Path) } _ = json.NewEncoder(w).Encode(Receipt{ReceiptID: "receipt-intent-1", ActionIntentID: "intent-1", RequestDigest: action.Proposal.NotificationSubject.RequestDigest, AcceptedAt: 1}) })) defer server.Close() executor, err := New(testBinding(server.URL), "secret", server.Client()) if err != nil { t.Fatal(err) } if result := executor.Execute(action); !result.Known || !result.Succeeded { t.Fatalf("execute: %+v", result) } if result := executor.Reconcile(action); !result.Known || !result.Succeeded { t.Fatalf("reconcile: %+v", result) } } func TestExecutorAmbiguousAndIntegrityOutcomes(t *testing.T) { action := testAction(t) for name, handler := range map[string]http.HandlerFunc{ "server error": func(w http.ResponseWriter, _ *http.Request) { http.Error(w, "no", http.StatusBadGateway) }, "bad receipt": func(w http.ResponseWriter, _ *http.Request) { _ = json.NewEncoder(w).Encode(Receipt{ReceiptID: "r", ActionIntentID: "other", RequestDigest: action.Proposal.NotificationSubject.RequestDigest, AcceptedAt: 1}) }, } { t.Run(name, func(t *testing.T) { server := httptest.NewTLSServer(handler) defer server.Close() executor, err := New(testBinding(server.URL), "secret", server.Client()) if err != nil { t.Fatal(err) } if result := executor.Execute(action); result.Known { t.Fatalf("must be unknown: %+v", result) } }) } action.Proposal.NotificationSubject.RequestDigest = "bad" server := httptest.NewTLSServer(http.NotFoundHandler()) defer server.Close() executor, err := New(testBinding(server.URL), "secret", server.Client()) if err != nil { t.Fatal(err) } if result := executor.Execute(action); !result.Known || result.Succeeded { t.Fatalf("invalid evidence must fail closed: %+v", result) } } func TestExecutorDoesNotFollowRedirect(t *testing.T) { action := testAction(t) targetCalls := 0 target := httptest.NewTLSServer(http.HandlerFunc(func(http.ResponseWriter, *http.Request) { targetCalls++ })) defer target.Close() redirect := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, target.URL, http.StatusTemporaryRedirect) })) defer redirect.Close() executor, err := New(testBinding(redirect.URL), "secret", redirect.Client()) if err != nil { t.Fatal(err) } if result := executor.Execute(action); result.Known { t.Fatalf("redirect must be ambiguous: %+v", result) } if targetCalls != 0 { t.Fatal("redirect target was called") } }