feat: sync multilayer td integration
This commit is contained in:
parent
20a310f6ca
commit
766c5db992
491 changed files with 26235 additions and 35340 deletions
|
|
@ -0,0 +1,140 @@
|
|||
package postgres
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"telesrv/internal/domain"
|
||||
"telesrv/internal/store"
|
||||
)
|
||||
|
||||
func TestAuthKeySessionLayerTransactionAndRestartPostgres(t *testing.T) {
|
||||
pool := testPool(t)
|
||||
ctx := context.Background()
|
||||
temp := randomLayerTestAuthKeyID(t)
|
||||
perm := randomLayerTestAuthKeyID(t)
|
||||
for perm == temp {
|
||||
perm = randomLayerTestAuthKeyID(t)
|
||||
}
|
||||
const sessionID = int64(87001)
|
||||
t.Cleanup(func() {
|
||||
_ = NewAuthKeyStore(pool).Delete(ctx, perm)
|
||||
_ = NewAuthKeyStore(pool).Delete(ctx, temp)
|
||||
})
|
||||
|
||||
keys := NewAuthKeyStore(pool)
|
||||
expiresAt := int(time.Now().Add(time.Hour).Unix())
|
||||
if err := keys.Save(ctx, store.AuthKeyData{ID: temp, ExpiresAt: expiresAt}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := keys.Save(ctx, store.AuthKeyData{ID: perm, ExpiresAt: 0}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
now := time.Now().UTC()
|
||||
firstMsgID := authKeySessionLayerTestMsgID(now, 1)
|
||||
newerMsgID := authKeySessionLayerTestMsgID(now, 2)
|
||||
concurrentLowMsgID := authKeySessionLayerTestMsgID(now, 3)
|
||||
concurrentHighMsgID := authKeySessionLayerTestMsgID(now, 4)
|
||||
for _, invalidMsgID := range []int64{
|
||||
authKeySessionLayerTestMsgID(now.Add(-302*time.Second), 1),
|
||||
authKeySessionLayerTestMsgID(now.Add(31*time.Second), 1),
|
||||
firstMsgID + 1,
|
||||
} {
|
||||
if _, _, err := keys.AdvanceSessionLayer(ctx, temp, sessionID, 220, invalidMsgID); !errors.Is(err, store.ErrAuthKeySessionLayerInvalid) {
|
||||
t.Fatalf("invalid msg_id %d advance err = %v", invalidMsgID, err)
|
||||
}
|
||||
}
|
||||
if _, found, err := keys.GetSessionLayer(ctx, temp, sessionID); err != nil || found {
|
||||
t.Fatalf("rejected evidence created session row: found=%v err=%v", found, err)
|
||||
}
|
||||
first, applied, err := keys.AdvanceSessionLayer(ctx, temp, sessionID, 220, firstMsgID)
|
||||
if err != nil || !applied || !first.SharedDefault || first.ObservationID <= 0 {
|
||||
t.Fatalf("first advance = (%+v,%v,%v)", first, applied, err)
|
||||
}
|
||||
if err := NewTempAuthKeyBindingStore(pool).Save(ctx, domain.TempAuthKeyBinding{
|
||||
TempAuthKeyID: temp,
|
||||
PermAuthKeyID: int64(binary.LittleEndian.Uint64(perm[:])),
|
||||
Nonce: 87,
|
||||
TempSessionID: sessionID,
|
||||
ExpiresAt: expiresAt,
|
||||
EncryptedMessage: []byte{8, 7},
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, id := range [][8]byte{temp, perm} {
|
||||
got, found, err := NewAuthKeyStore(pool).Get(ctx, id)
|
||||
if err != nil || !found || got.Layer != 220 || got.LayerObservationID != first.ObservationID {
|
||||
t.Fatalf("bound default %x = (%+v,%v,%v)", id, got, found, err)
|
||||
}
|
||||
}
|
||||
|
||||
newer, applied, err := NewAuthKeyStore(pool).AdvanceSessionLayer(ctx, temp, sessionID, 227, newerMsgID)
|
||||
if err != nil || !applied || !newer.SharedDefault || newer.ObservationID <= first.ObservationID {
|
||||
t.Fatalf("newer advance = (%+v,%v,%v)", newer, applied, err)
|
||||
}
|
||||
old, applied, err := NewAuthKeyStore(pool).AdvanceSessionLayer(ctx, temp, sessionID, 220, firstMsgID)
|
||||
if err != nil || applied || old.Layer != 227 || old.MessageID != newerMsgID || !old.SharedDefault {
|
||||
t.Fatalf("old replay = (%+v,%v,%v)", old, applied, err)
|
||||
}
|
||||
if _, _, err := NewAuthKeyStore(pool).AdvanceSessionLayer(ctx, temp, sessionID, 220, newerMsgID); !errors.Is(err, store.ErrAuthKeySessionLayerConflict) {
|
||||
t.Fatalf("same-msg conflict = %v", err)
|
||||
}
|
||||
|
||||
// Two independent store instances model two server processes. The raw-key
|
||||
// row lock and session CAS must converge on the greater selector msg_id.
|
||||
type candidate struct {
|
||||
layer int
|
||||
msgID int64
|
||||
}
|
||||
candidates := []candidate{{layer: 225, msgID: concurrentLowMsgID}, {layer: 227, msgID: concurrentHighMsgID}}
|
||||
start := make(chan struct{})
|
||||
errs := make(chan error, len(candidates))
|
||||
var wg sync.WaitGroup
|
||||
for _, item := range candidates {
|
||||
item := item
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
<-start
|
||||
_, _, err := NewAuthKeyStore(pool).AdvanceSessionLayer(ctx, temp, sessionID, item.layer, item.msgID)
|
||||
errs <- err
|
||||
}()
|
||||
}
|
||||
close(start)
|
||||
wg.Wait()
|
||||
close(errs)
|
||||
for err := range errs {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
restarted := NewAuthKeyStore(pool)
|
||||
current, found, err := restarted.GetSessionLayer(ctx, temp, sessionID)
|
||||
if err != nil || !found || current.Layer != 227 || current.MessageID != concurrentHighMsgID || !current.SharedDefault {
|
||||
t.Fatalf("restart authoritative row = (%+v,%v,%v)", current, found, err)
|
||||
}
|
||||
for _, id := range [][8]byte{temp, perm} {
|
||||
got, found, err := restarted.Get(ctx, id)
|
||||
if err != nil || !found || got.Layer != 227 || got.LayerObservationID != current.ObservationID {
|
||||
t.Fatalf("transactional shared default %x = (%+v,%v,%v)", id, got, found, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func authKeySessionLayerTestMsgID(at time.Time, order uint32) int64 {
|
||||
return int64((uint64(at.Unix()) << 32) | uint64(order)<<2)
|
||||
}
|
||||
|
||||
func randomLayerTestAuthKeyID(t *testing.T) [8]byte {
|
||||
t.Helper()
|
||||
var id [8]byte
|
||||
if _, err := rand.Read(id[:]); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return id
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue