115 lines
3.9 KiB
Go
115 lines
3.9 KiB
Go
package localreset
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"git.pcux.cn/xuans/Scert/backend/internal/deployment"
|
|
)
|
|
|
|
type reconciliationSession struct{ dispositionTestSession }
|
|
|
|
func (s *reconciliationSession) PrepareRecoveryReconciliation(ctx context.Context, sourceID string) (RecoveryPreparation, error) {
|
|
value, err := s.PrepareRecovery(ctx, "tx-1", deployment.RecoveryActionVerifyCommit)
|
|
value.Summary.SourceDispositionID = sourceID
|
|
value.Summary.Phase = deployment.TransactionPhaseCommitVerified
|
|
s.prepared = value
|
|
return value, err
|
|
}
|
|
|
|
func (s *reconciliationSession) ExecuteRecovery(ctx context.Context, id, token string) (deployment.RecoveryDispositionSummary, error) {
|
|
sourceID := s.prepared.Summary.SourceDispositionID
|
|
value, err := s.dispositionTestSession.ExecuteRecovery(ctx, id, token)
|
|
if err != nil {
|
|
return value, err
|
|
}
|
|
value.SourceDispositionID, value.ResultCode = sourceID, deployment.RecoveryResultCommitted
|
|
s.result = value
|
|
return value, nil
|
|
}
|
|
|
|
func TestRecoveryReconciliationProtocolAndQuery(t *testing.T) {
|
|
session := &reconciliationSession{}
|
|
_, conn, done := recoveryConnection(t, session)
|
|
client, err := Begin(t.Context(), conn)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
sourceID := strings.Repeat("a", 64)
|
|
prepared, err := client.PrepareRecoveryReconciliation(sourceID)
|
|
if err != nil || prepared.Summary.SourceDispositionID != sourceID {
|
|
t.Fatal("原处置绑定丢失", err)
|
|
}
|
|
result, err := client.ExecuteRecovery(prepared.DispositionID, prepared.Token)
|
|
if err != nil || result.SourceDispositionID != sourceID || result.Status != "succeeded" {
|
|
t.Fatal("重新核查结果无效", err)
|
|
}
|
|
queried, err := client.GetRecoveryDisposition(result.ID)
|
|
if err != nil || queried != result {
|
|
t.Fatal("查询改变了关联结果", err)
|
|
}
|
|
if _, err := client.ExecuteRecovery(prepared.DispositionID, prepared.Token); err == nil {
|
|
t.Fatal("旧令牌被重放")
|
|
}
|
|
_ = client.Close()
|
|
<-done
|
|
if session.prepares.Load() != 1 || session.executes.Load() != 2 || session.queries.Load() != 1 || session.resets.Load() != 0 {
|
|
t.Fatal("调用了错误业务入口")
|
|
}
|
|
}
|
|
|
|
func TestRecoveryReconciliationRejectsUnboundResponse(t *testing.T) {
|
|
sourceID := strings.Repeat("a", 64)
|
|
session := &reconciliationSession{}
|
|
prepared, err := session.PrepareRecoveryReconciliation(t.Context(), sourceID)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
request := Request{Action: "recovery_reconcile_prepare", DispositionID: sourceID}
|
|
for _, mode := range []string{"source", "action", "same-id", "transaction", "mixed", "expired-range"} {
|
|
t.Run(mode, func(t *testing.T) {
|
|
value := prepared
|
|
response := Response{Preparation: &value}
|
|
switch mode {
|
|
case "source":
|
|
value.Summary.SourceDispositionID = strings.Repeat("d", 64)
|
|
case "action":
|
|
value.Summary.Action = deployment.RecoveryActionCommit
|
|
case "same-id":
|
|
value.DispositionID = sourceID
|
|
case "transaction":
|
|
value.Summary.TransactionID = "../bad"
|
|
case "mixed":
|
|
response.Disposition = &deployment.RecoveryDispositionSummary{}
|
|
case "expired-range":
|
|
value.Summary.ExpiresAt = value.Summary.ObservedAt.Add(2 * time.Minute)
|
|
}
|
|
if validDispositionResponse(request, response) {
|
|
t.Fatal("接受了混合或无绑定准备响应")
|
|
}
|
|
})
|
|
}
|
|
if validRecoveryAction(deployment.RecoveryActionVerifyCommit) || validRecoveryAction(deployment.RecoveryActionVerifyRollback) {
|
|
t.Fatal("普通准备允许绕过原处置绑定")
|
|
}
|
|
}
|
|
|
|
func TestRecoveryReconciliationOldServerFailsClosed(t *testing.T) {
|
|
session := &dispositionTestSession{}
|
|
_, conn, done := recoveryConnection(t, session)
|
|
client, err := Begin(t.Context(), conn)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := client.PrepareRecoveryReconciliation(strings.Repeat("a", 64)); err == nil {
|
|
t.Fatal("旧服务错误地支持了重新核查")
|
|
}
|
|
_ = client.Close()
|
|
<-done
|
|
if session.prepares.Load() != 0 || session.executes.Load() != 0 {
|
|
t.Fatal("旧服务错误地执行了原动作")
|
|
}
|
|
}
|