110 lines
4.6 KiB
Go
110 lines
4.6 KiB
Go
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")
|
|
}
|
|
}
|