Skip to content

Commit 3af9b78

Browse files
committed
enclave/nitro/host/host_test.go: directly test quorum timeout early exit
The previous test restored the global timeout before its goroutine was guaranteed to start, causing a data race. Synchronize on the timeout handler returning instead.
1 parent e9af8b7 commit 3af9b78

1 file changed

Lines changed: 10 additions & 95 deletions

File tree

enclave/nitro/host/host_test.go

Lines changed: 10 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -897,103 +897,18 @@ func TestHandleExecuteWithBatchError(t *testing.T) {
897897
assert.Contains(t, newRecorder.Body.String(), "failed to communicate with enclave: connection refused")
898898
}
899899

900-
// TestHandleExecuteWithQuorumTimeoutEarlyExit verifies that when quorum is reached and batch
901-
// processes successfully, the timeout goroutine exits early without waiting for the full timeout.
902-
func TestHandleExecuteWithQuorumTimeoutEarlyExit(t *testing.T) {
903-
// Set a long timeout - if the test takes anywhere near this long, early exit isn't working
904-
originalTimeout := *quorumTimeout
905-
*quorumTimeout = 5 * time.Second
906-
defer func() { *quorumTimeout = originalTimeout }()
907-
908-
const numSigners = 3
909-
signerKeys := make([]*ed25519.PrivateKey, numSigners)
910-
signers := make([][]byte, numSigners)
911-
912-
for i := 0; i < numSigners; i++ {
913-
pubKey, privKey, err := ed25519.GenerateKey(rand.Reader)
914-
require.NoError(t, err)
915-
signerKeys[i] = &privKey
916-
signers[i] = pubKey
917-
}
918-
919-
config := types.EnclaveConfig{
920-
Signers: signers,
921-
MasterPublicKey: []byte("master-public-key"),
922-
T: 2,
923-
F: 2, // threshold = F+1 = 3
924-
}
925-
926-
mockExecResponse := types.ExecuteResponse{
927-
RequestID: sha256.Sum256([]byte("test-request-early-exit")),
928-
Output: []byte("test-output"),
929-
Attestation: []byte("test-attestation"),
930-
}
931-
respBytes := util.MustMarshal(t, mockExecResponse)
932-
933-
mockResp := &http.Response{
934-
StatusCode: http.StatusOK,
935-
Body: io.NopCloser(bytes.NewReader(respBytes)),
936-
Header: http.Header{"Content-Type": []string{"application/json"}},
937-
}
900+
func TestHandleQuorumTimeoutEarlyExit(t *testing.T) {
901+
host := NewHostServer(context.Background(), &http.Client{})
902+
doneCh := make(chan struct{})
903+
returned := make(chan struct{})
938904

939-
mockTransport := &mockRoundTripper{response: mockResp}
940-
host := NewHostServer(context.Background(), &http.Client{Transport: mockTransport})
941-
host.config = config
942-
943-
computeReq := types.ComputeRequest{
944-
RequestID: sha256.Sum256([]byte("test-request-early-exit")),
945-
Ciphertexts: [][]byte{[]byte("test-ciphertext")},
946-
PublicData: []byte("test-public-data"),
947-
}
948-
949-
// Submit all 3 requests to reach quorum
950-
recorders := make([]*httptest.ResponseRecorder, numSigners)
951-
done := make([]chan struct{}, numSigners)
952-
953-
startTime := time.Now()
954-
955-
for i := 0; i < numSigners; i++ {
956-
hash := computeReq.Hash()
957-
prefixedHash := types.MakePeerIDSignatureDomainSeparatedPayload(util.GetConfidentialComputePayloadPrefix(), hash[:])
958-
signature := ed25519.Sign(*signerKeys[i], prefixedHash)
959-
960-
execReq := types.SignedComputeRequest{
961-
ComputeRequest: computeReq,
962-
Signature: signature,
963-
}
964-
965-
reqBytes := util.MustMarshal(t, execReq)
966-
req := httptest.NewRequest(http.MethodPost, "/requests", bytes.NewReader(reqBytes))
967-
recorders[i] = httptest.NewRecorder()
968-
done[i] = make(chan struct{})
969-
970-
go func(idx int, r *http.Request) {
971-
host.handleExecute(recorders[idx], r)
972-
close(done[idx])
973-
}(i, req)
974-
}
975-
976-
// Wait for all requests to complete
977-
for i := 0; i < numSigners; i++ {
978-
select {
979-
case <-done[i]:
980-
case <-time.After(2 * time.Second):
981-
t.Fatalf("Request %d did not complete within expected time", i)
982-
}
983-
}
984-
985-
elapsed := time.Since(startTime)
986-
987-
// Verify the test completed quickly (well under the 5 second timeout)
988-
assert.Less(t, elapsed, 1*time.Second, "Test should complete quickly due to early exit, not wait for full timeout")
989-
990-
// Verify all requests succeeded
991-
for i, rec := range recorders {
992-
assert.Equal(t, http.StatusOK, rec.Code, "Request %d should have succeeded", i)
993-
}
905+
go func() {
906+
host.handleQuorumTimeout([32]byte{}, 0, doneCh)
907+
close(returned)
908+
}()
994909

995-
// Verify request was sent to enclave
996-
assert.Len(t, mockTransport.requests, 1, "One batch request should be sent to enclave")
910+
close(doneCh)
911+
waitForTestSignal(t, returned, "quorum timeout handler to exit")
997912
}
998913

999914
// TestHandleExecuteWithSlowProcessingNoTimeout verifies that when quorum is reached but

0 commit comments

Comments
 (0)