Ctrl K
ComunidadGuías…

internal/mtprotoedge/layer_rpc_execution_test.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
package mtprotoedge

import (
	"context"
	"errors"
	"fmt"
	"sync/atomic"
	"testing"
	"time"

	"github.com/iamxvbaba/td/bin"
	"github.com/iamxvbaba/td/mt"
	"github.com/iamxvbaba/td/proto"
	"github.com/iamxvbaba/td/tg"
	"github.com/iamxvbaba/td/tlprofile"
)

// preparedOnlyLayerRPCResult is intentionally incapable of encoding. The
// binding guard must reject it solely from immutable admission identity before
// any result method other than Prepared can be observed.
type preparedOnlyLayerRPCResult struct {
	tlprofile.Result
	prepared tlprofile.PreparedCall
}

func (r *preparedOnlyLayerRPCResult) Prepared() tlprofile.PreparedCall { return r.prepared }

func TestBindAdmittedLayerRPCResultRequiresExactRequestIdentity(t *testing.T) {
	dispatcher := tlprofile.NewDispatcher()
	admit := func(request bin.Encoder) tlprofile.Admission {
		t.Helper()
		body := &bin.Buffer{Buf: exactLayerRPCBody(t, request)}
		admitted, err := dispatcher.Admit(tlprofile.Profile227, body, tlprofile.Limits{})
		if err != nil {
			t.Fatal(err)
		}
		return admitted
	}

	request := admit(&tg.HelpGetConfigRequest{})
	other := admit(&tg.HelpGetNearestDCRequest{})

	if _, err := bindAdmittedLayerRPCResult(request, &preparedOnlyLayerRPCResult{prepared: other.Prepared()}); !errors.Is(err, errLayerRPCResultIdentityMismatch) {
		t.Fatalf("mismatched result error = %v, want %v", err, errLayerRPCResultIdentityMismatch)
	}

	bound, err := bindAdmittedLayerRPCResult(request, &preparedOnlyLayerRPCResult{prepared: request.Prepared()})
	if err != nil {
		t.Fatal(err)
	}
	if bound == nil || bound.call.Identity() != request.Call().Identity() {
		t.Fatal("matching result did not retain the admitted call identity")
	}
}

type mismatchedProjectionLayerRPC struct {
	*admissionOnlyLayerRPC
	result tlprofile.Result
	calls  atomic.Int32
}

func (h *mismatchedProjectionLayerRPC) DispatchAdmitted(
	context.Context,
	[8]byte,
	int64,
	int64,
	uint64,
	tlprofile.Admission,
) (tlprofile.Result, string, error) {
	h.calls.Add(1)
	return h.result, "help.getConfig", nil
}

func TestProjectionFailureCachesInternalWithoutRepeatingBusiness(t *testing.T) {
	dispatcher := tlprofile.NewDispatcher()
	admit := func(request bin.Encoder) tlprofile.Admission {
		t.Helper()
		body := &bin.Buffer{Buf: exactLayerRPCBody(t, request)}
		admitted, err := dispatcher.Admit(tlprofile.Profile227, body, tlprofile.Limits{})
		if err != nil {
			t.Fatal(err)
		}
		return admitted
	}
	request := admit(&tg.HelpGetConfigRequest{})
	other := admit(&tg.HelpGetNearestDCRequest{})
	handler := &mismatchedProjectionLayerRPC{
		admissionOnlyLayerRPC: newAdmissionOnlyLayerRPC(),
		result:                &preparedOnlyLayerRPCResult{prepared: other.Prepared()},
	}
	s := New(Options{DC: 2, LayerRPC: handler})
	c := newOutboundTestConn(t, &collectingSessionTransport{}, newOutboundTrackedBudget(1<<20))
	c.authKeyID = [8]byte{0x41, 0x01}
	c.sessionID = 4101
	const reqMsgID = int64(410100)
	claim, err := s.rpcResults.AcquireLayerIdentified(
		c.authKeyID, c.sessionID, reqMsgID,
		tlprofile.Profile227, request.Prepared().Identity(),
	)
	if err != nil || claim.owner == nil {
		t.Fatalf("owner acquisition err=%v", err)
	}
	if err := s.handleAdmittedLayerRPC(
		context.Background(), c, reqMsgID, claim.admissionSeq,
		"help.getConfig", request, claim.owner, nil,
	); err != nil {
		t.Fatalf("publish projection failure: %v", err)
	}

	deadline := time.Now().Add(2 * time.Second)
	var completed rpcResultAcquire
	for {
		completed, err = s.rpcResults.AcquireLayerIdentified(
			c.authKeyID, c.sessionID, reqMsgID,
			tlprofile.Profile227, request.Prepared().Identity(),
		)
		if err == nil && completed.state == rpcResultAcquireCompleted {
			break
		}
		if time.Now().After(deadline) {
			t.Fatalf("projection failure did not become completed: state=%d err=%v", completed.state, err)
		}
		time.Sleep(time.Millisecond)
	}
	if !completed.executionKnown || !completed.executionOK {
		t.Fatalf("projection failure lost successful business outcome: known=%v ok=%v", completed.executionKnown, completed.executionOK)
	}
	if got := handler.calls.Load(); got != 1 {
		t.Fatalf("business calls=%d, want 1", got)
	}
	var envelope proto.Result
	if err := envelope.Decode(&bin.Buffer{Buf: completed.encoded.body}); err != nil {
		t.Fatal(err)
	}
	var rpcErr mt.RPCError
	if err := rpcErr.Decode(&bin.Buffer{Buf: envelope.Result}); err != nil {
		t.Fatal(err)
	}
	if rpcErr.ErrorCode != 500 || rpcErr.ErrorMessage != "INTERNAL" {
		t.Fatalf("projection terminal = %+v", rpcErr)
	}
	if _, ok := s.rpcResults.Replay(c.authKeyID, c.sessionID, reqMsgID); !ok {
		t.Fatal("projection receipt disappeared before duplicate acquire")
	}
	// A same-msg replay is served from the completed exact identity; there is no
	// second DispatchAdmitted call even though projection failed after business
	// success.
	replay, err := s.rpcResults.AcquireLayerIdentified(
		c.authKeyID, c.sessionID, reqMsgID,
		tlprofile.Profile227, request.Prepared().Identity(),
	)
	if err != nil || replay.state != rpcResultAcquireCompleted {
		t.Fatalf("projection replay = state:%d err:%v", replay.state, err)
	}
	if replay.encoded == nil || replay.encoded.replayMsgID != completed.encoded.replayMsgID ||
		replay.encoded.replaySeqNo != completed.encoded.replaySeqNo ||
		!sameBacking(replay.encoded.body, completed.encoded.body) {
		t.Fatal("projection replay did not reference the original logical-outbox frame")
	}
	if got := handler.calls.Load(); got != 1 {
		t.Fatalf("replay repeated business calls=%d", got)
	}
}

// childDeadlineLayerRPC fails the admitted business call with a store failure
// whose inner cause is a child-operation deadline, not the request context.
type childDeadlineLayerRPC struct {
	*admissionOnlyLayerRPC
	calls atomic.Int32
}

func (h *childDeadlineLayerRPC) DispatchAdmitted(
	context.Context,
	[8]byte,
	int64,
	int64,
	uint64,
	tlprofile.Admission,
) (tlprofile.Result, string, error) {
	h.calls.Add(1)
	return nil, "help.getConfig", fmt.Errorf("child store op: %w", context.DeadlineExceeded)
}

// TestChildOperationDeadlineWithLiveOuterContextPublishesInternal pins the
// review finding: a child-operation timeout must not suppress the terminal RPC
// result merely because the wrapped error is context.DeadlineExceeded. Only the
// authoritative request/connection context may do that; with a live outer
// context the client must still receive a terminal INTERNAL instead of nothing.
func TestChildOperationDeadlineWithLiveOuterContextPublishesInternal(t *testing.T) {
	dispatcher := tlprofile.NewDispatcher()
	admit := func(request bin.Encoder) tlprofile.Admission {
		t.Helper()
		body := &bin.Buffer{Buf: exactLayerRPCBody(t, request)}
		admitted, err := dispatcher.Admit(tlprofile.Profile227, body, tlprofile.Limits{})
		if err != nil {
			t.Fatal(err)
		}
		return admitted
	}
	request := admit(&tg.HelpGetConfigRequest{})
	handler := &childDeadlineLayerRPC{
		admissionOnlyLayerRPC: newAdmissionOnlyLayerRPC(),
	}
	s := New(Options{DC: 2, LayerRPC: handler})
	c := newOutboundTestConn(t, &collectingSessionTransport{}, newOutboundTrackedBudget(1<<20))
	c.authKeyID = [8]byte{0x42, 0x02}
	c.sessionID = 4202
	const reqMsgID = int64(420200)
	claim, err := s.rpcResults.AcquireLayerIdentified(
		c.authKeyID, c.sessionID, reqMsgID,
		tlprofile.Profile227, request.Prepared().Identity(),
	)
	if err != nil || claim.owner == nil {
		t.Fatalf("owner acquisition err=%v", err)
	}
	// The outer context stays live: only the child operation crossed its own
	// deadline, so the client still exists and expects a terminal result.
	if err := s.handleAdmittedLayerRPC(
		context.Background(), c, reqMsgID, claim.admissionSeq,
		"help.getConfig", request, claim.owner, nil,
	); err != nil {
		t.Fatalf("publish child-deadline failure: %v", err)
	}

	deadline := time.Now().Add(2 * time.Second)
	var completed rpcResultAcquire
	for {
		completed, err = s.rpcResults.AcquireLayerIdentified(
			c.authKeyID, c.sessionID, reqMsgID,
			tlprofile.Profile227, request.Prepared().Identity(),
		)
		if err == nil && completed.state == rpcResultAcquireCompleted {
			break
		}
		if time.Now().After(deadline) {
			t.Fatalf("child-deadline failure was suppressed: state=%d err=%v", completed.state, err)
		}
		time.Sleep(time.Millisecond)
	}
	var envelope proto.Result
	if err := envelope.Decode(&bin.Buffer{Buf: completed.encoded.body}); err != nil {
		t.Fatal(err)
	}
	var rpcErr mt.RPCError
	if err := rpcErr.Decode(&bin.Buffer{Buf: envelope.Result}); err != nil {
		t.Fatal(err)
	}
	if rpcErr.ErrorCode != 500 || rpcErr.ErrorMessage != "INTERNAL" {
		t.Fatalf("child-deadline terminal = %+v", rpcErr)
	}
	if got := handler.calls.Load(); got != 1 {
		t.Fatalf("business calls=%d, want 1", got)
	}
}