feat(notify): 重构通信内核并补齐 stream/bulk/record/transfer 能力
- 引入 LogicalConn/TransportConn 分层,ClientConn 保留兼容适配层 - 新增 Stream、Bulk、RecordStream 三条数据面能力及对应控制路径 - 完成 transfer/file 传输内核与状态快照、诊断能力 - 补齐 reconnect、inbound dispatcher、modern psk 等基础模块 - 增加大规模回归、并发与基准测试覆盖 - 更新依赖库
This commit is contained in:
@@ -0,0 +1,199 @@
|
||||
package notify
|
||||
|
||||
import (
|
||||
"b612.me/stario"
|
||||
"context"
|
||||
"math"
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestMessageReplyUsesInboundConnForStaleTransport(t *testing.T) {
|
||||
server := NewServer().(*ServerCommon)
|
||||
UseLegacySecurityServer(server)
|
||||
|
||||
stopCtx, stopFn := context.WithCancel(context.Background())
|
||||
defer stopFn()
|
||||
server.setServerSessionRuntime(&serverSessionRuntime{
|
||||
stopCtx: stopCtx,
|
||||
stopFn: stopFn,
|
||||
queue: stario.NewQueueCtx(stopCtx, 4, math.MaxUint32),
|
||||
})
|
||||
server.markSessionStarted()
|
||||
defer server.markSessionStopped("test done", nil)
|
||||
|
||||
firstLeft, firstRight := net.Pipe()
|
||||
defer firstLeft.Close()
|
||||
defer firstRight.Close()
|
||||
|
||||
logical, _, _ := newRegisteredServerLogicalForTest(t, server, "reply-inbound-stale", firstLeft, stopCtx, stopFn)
|
||||
client := clientConnFromLogical(logical)
|
||||
client.applyClientConnAttachmentProfile(0, 0, server.defaultMsgEn, server.defaultMsgDe, server.handshakeRsaKey, server.SecretKey)
|
||||
|
||||
staleTransport := logical.transportConnSnapshotForInbound(firstLeft, nil, logical.transportGenerationSnapshot()+1, true)
|
||||
if staleTransport == nil {
|
||||
t.Fatal("stale transport snapshot should exist")
|
||||
}
|
||||
if staleTransport.IsCurrent() {
|
||||
t.Fatal("stale transport should not be current for mismatched generation")
|
||||
}
|
||||
|
||||
message := Message{
|
||||
NetType: NET_SERVER,
|
||||
LogicalConn: logical,
|
||||
TransportConn: staleTransport,
|
||||
TransferMsg: TransferMsg{
|
||||
ID: 11,
|
||||
Key: "reply-inbound",
|
||||
Type: MSG_SYNC_ASK,
|
||||
},
|
||||
Time: time.Now(),
|
||||
inboundConn: firstLeft,
|
||||
}
|
||||
|
||||
done := make(chan error, 1)
|
||||
go func() {
|
||||
done <- message.Reply(MsgVal("ok"))
|
||||
}()
|
||||
|
||||
env := readServerEnvelopeFromConn(t, server, logical, firstRight, time.Second)
|
||||
select {
|
||||
case err := <-done:
|
||||
if err != nil {
|
||||
t.Fatalf("Message.Reply failed: %v", err)
|
||||
}
|
||||
case <-time.After(time.Second):
|
||||
t.Fatal("timed out waiting for Message.Reply to finish")
|
||||
}
|
||||
|
||||
transfer, err := unwrapTransferMsgEnvelope(env, server.sequenceDe)
|
||||
if err != nil {
|
||||
t.Fatalf("unwrapTransferMsgEnvelope failed: %v", err)
|
||||
}
|
||||
if transfer.Type != MSG_SYNC_REPLY {
|
||||
t.Fatalf("reply type = %v, want %v", transfer.Type, MSG_SYNC_REPLY)
|
||||
}
|
||||
if transfer.ID != 11 {
|
||||
t.Fatalf("reply id = %d, want %d", transfer.ID, 11)
|
||||
}
|
||||
if transfer.Key != "reply-inbound" {
|
||||
t.Fatalf("reply key = %q, want %q", transfer.Key, "reply-inbound")
|
||||
}
|
||||
if string(transfer.Value) != "ok" {
|
||||
t.Fatalf("reply value = %q, want %q", string(transfer.Value), "ok")
|
||||
}
|
||||
}
|
||||
|
||||
func TestServerHandleReceivedSignalReliabilityUsesInboundConnForStaleTransport(t *testing.T) {
|
||||
server := NewServer().(*ServerCommon)
|
||||
UseLegacySecurityServer(server)
|
||||
if err := UseSignalReliabilityServer(server, &SignalReliabilityOptions{Enabled: true}); err != nil {
|
||||
t.Fatalf("UseSignalReliabilityServer failed: %v", err)
|
||||
}
|
||||
|
||||
stopCtx, stopFn := context.WithCancel(context.Background())
|
||||
defer stopFn()
|
||||
server.setServerSessionRuntime(&serverSessionRuntime{
|
||||
stopCtx: stopCtx,
|
||||
stopFn: stopFn,
|
||||
queue: stario.NewQueueCtx(stopCtx, 4, math.MaxUint32),
|
||||
})
|
||||
|
||||
firstLeft, firstRight := net.Pipe()
|
||||
defer firstLeft.Close()
|
||||
defer firstRight.Close()
|
||||
|
||||
logical, _, _ := newRegisteredServerLogicalForTest(t, server, "signal-ack-inbound-stale", firstLeft, stopCtx, stopFn)
|
||||
client := clientConnFromLogical(logical)
|
||||
client.applyClientConnAttachmentProfile(0, 0, server.defaultMsgEn, server.defaultMsgDe, server.handshakeRsaKey, server.SecretKey)
|
||||
|
||||
staleTransport := logical.transportConnSnapshotForInbound(firstLeft, nil, logical.transportGenerationSnapshot()+1, true)
|
||||
if staleTransport == nil {
|
||||
t.Fatal("stale transport snapshot should exist")
|
||||
}
|
||||
if staleTransport.IsCurrent() {
|
||||
t.Fatal("stale transport should not be current for mismatched generation")
|
||||
}
|
||||
|
||||
done := make(chan bool, 1)
|
||||
go func() {
|
||||
done <- server.handleReceivedSignalReliabilityTransport(logical, staleTransport, firstLeft, TransferMsg{
|
||||
ID: 22,
|
||||
Key: "signal-reliable",
|
||||
Type: MSG_ASYNC,
|
||||
})
|
||||
}()
|
||||
|
||||
env := readServerEnvelopeFromConn(t, server, logical, firstRight, time.Second)
|
||||
select {
|
||||
case duplicate := <-done:
|
||||
if duplicate {
|
||||
t.Fatal("first reliable signal receive should not be duplicate")
|
||||
}
|
||||
case <-time.After(time.Second):
|
||||
t.Fatal("timed out waiting for signal reliability handler to finish")
|
||||
}
|
||||
|
||||
if env.Kind != EnvelopeSignalAck {
|
||||
t.Fatalf("ack envelope kind = %v, want %v", env.Kind, EnvelopeSignalAck)
|
||||
}
|
||||
if env.ID != 22 {
|
||||
t.Fatalf("ack signal id = %d, want %d", env.ID, 22)
|
||||
}
|
||||
}
|
||||
|
||||
func TestServerDispatchFileEnvelopeUsesInboundConnForStaleTransportAck(t *testing.T) {
|
||||
server := NewServer().(*ServerCommon)
|
||||
UseLegacySecurityServer(server)
|
||||
|
||||
stopCtx, stopFn := context.WithCancel(context.Background())
|
||||
defer stopFn()
|
||||
server.setServerSessionRuntime(&serverSessionRuntime{
|
||||
stopCtx: stopCtx,
|
||||
stopFn: stopFn,
|
||||
queue: stario.NewQueueCtx(stopCtx, 4, math.MaxUint32),
|
||||
})
|
||||
|
||||
firstLeft, firstRight := net.Pipe()
|
||||
defer firstLeft.Close()
|
||||
defer firstRight.Close()
|
||||
|
||||
logical, _, _ := newRegisteredServerLogicalForTest(t, server, "file-ack-inbound-stale", firstLeft, stopCtx, stopFn)
|
||||
client := clientConnFromLogical(logical)
|
||||
client.applyClientConnAttachmentProfile(0, 0, server.defaultMsgEn, server.defaultMsgDe, server.handshakeRsaKey, server.SecretKey)
|
||||
|
||||
staleTransport := logical.transportConnSnapshotForInbound(firstLeft, nil, logical.transportGenerationSnapshot()+1, true)
|
||||
if staleTransport == nil {
|
||||
t.Fatal("stale transport snapshot should exist")
|
||||
}
|
||||
if staleTransport.IsCurrent() {
|
||||
t.Fatal("stale transport should not be current for mismatched generation")
|
||||
}
|
||||
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
server.dispatchFileEnvelope(logical, staleTransport, firstLeft, newFileMetaEnvelope("file-1", "demo.bin", 4, "", 0, 0), time.Now())
|
||||
close(done)
|
||||
}()
|
||||
|
||||
env := readServerEnvelopeFromConn(t, server, logical, firstRight, time.Second)
|
||||
select {
|
||||
case <-done:
|
||||
case <-time.After(time.Second):
|
||||
t.Fatal("timed out waiting for file dispatch to finish")
|
||||
}
|
||||
|
||||
if env.Kind != EnvelopeAck {
|
||||
t.Fatalf("file ack envelope kind = %v, want %v", env.Kind, EnvelopeAck)
|
||||
}
|
||||
if env.File.FileID != "file-1" {
|
||||
t.Fatalf("file ack file id = %q, want %q", env.File.FileID, "file-1")
|
||||
}
|
||||
if env.File.Stage != "meta" {
|
||||
t.Fatalf("file ack stage = %q, want %q", env.File.Stage, "meta")
|
||||
}
|
||||
if env.File.Offset != 0 {
|
||||
t.Fatalf("file ack offset = %d, want %d", env.File.Offset, 0)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user