feat: sync multilayer td integration
This commit is contained in:
parent
20a310f6ca
commit
766c5db992
491 changed files with 26235 additions and 35340 deletions
111
internal/mtprotoedge/rpc_delivery_hook_executor_test.go
Normal file
111
internal/mtprotoedge/rpc_delivery_hook_executor_test.go
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
package mtprotoedge
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func hookTestMessage(reqMsgID int64, coordinator *rpcResultDeliveryCoordinator, fn func()) *encodedOutboundMessage {
|
||||
msg := &encodedOutboundMessage{delivery: newRPCResultDelivery(reqMsgID, coordinator)}
|
||||
msg.setDeliveryHook(fn)
|
||||
return msg
|
||||
}
|
||||
|
||||
func TestRPCDeliveryHookExecutorBoundsAdmissionWithoutBlockingDelivery(t *testing.T) {
|
||||
executor := newRPCDeliveryHookExecutor(1, 1)
|
||||
started := make(chan struct{})
|
||||
release := make(chan struct{})
|
||||
first := hookTestMessage(1, nil, func() {
|
||||
close(started)
|
||||
<-release
|
||||
})
|
||||
if err := first.prepareDeliveryHook(executor); err != nil {
|
||||
t.Fatalf("reserve first hook: %v", err)
|
||||
}
|
||||
delivered := make(chan struct{})
|
||||
go func() {
|
||||
first.markDelivered()
|
||||
close(delivered)
|
||||
}()
|
||||
select {
|
||||
case <-delivered:
|
||||
case <-time.After(100 * time.Millisecond):
|
||||
t.Fatal("physical delivery blocked on hook execution")
|
||||
}
|
||||
select {
|
||||
case <-started:
|
||||
case <-time.After(time.Second):
|
||||
t.Fatal("first hook did not start")
|
||||
}
|
||||
|
||||
second := hookTestMessage(2, nil, func() {})
|
||||
if err := second.prepareDeliveryHook(executor); !errors.Is(err, ErrRPCDeliveryHookCapacity) {
|
||||
t.Fatalf("second reservation = %v, want capacity error", err)
|
||||
}
|
||||
close(release)
|
||||
deadline := time.Now().Add(time.Second)
|
||||
for len(executor.slots) != 0 && time.Now().Before(deadline) {
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
if got := len(executor.slots); got != 0 {
|
||||
t.Fatalf("executor retained %d capacity slots", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRPCDeliveryHookExecutorIsolatesPanicsAndContinues(t *testing.T) {
|
||||
executor := newRPCDeliveryHookExecutor(1, 2)
|
||||
first := hookTestMessage(1, nil, func() { panic("hook boom") })
|
||||
done := make(chan struct{})
|
||||
second := hookTestMessage(2, nil, func() { close(done) })
|
||||
if err := first.prepareDeliveryHook(executor); err != nil {
|
||||
t.Fatalf("reserve panic hook: %v", err)
|
||||
}
|
||||
if err := second.prepareDeliveryHook(executor); err != nil {
|
||||
t.Fatalf("reserve following hook: %v", err)
|
||||
}
|
||||
first.markDelivered()
|
||||
second.markDelivered()
|
||||
select {
|
||||
case <-done:
|
||||
case <-time.After(time.Second):
|
||||
t.Fatal("worker stopped after a hook panic")
|
||||
}
|
||||
deadline := time.Now().Add(time.Second)
|
||||
for executor.panics.Load() != 1 && time.Now().Before(deadline) {
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
if got := executor.panics.Load(); got != 1 {
|
||||
t.Fatalf("recorded hook panics = %d, want 1", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEquivalentRPCDeliveryAttemptsShareExactlyOnceCoordinator(t *testing.T) {
|
||||
executor := newRPCDeliveryHookExecutor(1, 2)
|
||||
var calls atomic.Int32
|
||||
first := hookTestMessage(11, nil, func() { calls.Add(1) })
|
||||
second := hookTestMessage(22, first.delivery.coordinator, nil)
|
||||
if err := first.prepareDeliveryHook(executor); err != nil {
|
||||
t.Fatalf("reserve first attempt: %v", err)
|
||||
}
|
||||
if err := second.prepareDeliveryHook(executor); err != nil {
|
||||
t.Fatalf("reserve equivalent attempt: %v", err)
|
||||
}
|
||||
first.markDelivered()
|
||||
second.markDelivered()
|
||||
deadline := time.Now().Add(time.Second)
|
||||
for calls.Load() != 1 && time.Now().Before(deadline) {
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
if got := calls.Load(); got != 1 {
|
||||
t.Fatalf("equivalent delivery hooks = %d, want 1", got)
|
||||
}
|
||||
deadline = time.Now().Add(time.Second)
|
||||
for len(executor.slots) != 0 && time.Now().Before(deadline) {
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
if got := len(executor.slots); got != 0 {
|
||||
t.Fatalf("equivalent attempts leaked %d tickets", got)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue