Skip to content

Commit 5afe349

Browse files
committed
add a get to trigger SSE
1 parent cce6630 commit 5afe349

3 files changed

Lines changed: 77 additions & 66 deletions

File tree

e2e/proxy/proxy_test.go

Lines changed: 52 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ func startProxy(t *testing.T, ctx context.Context, infisicalURL string, config P
9090
}
9191

9292
// setupProxyTest sets up the common test
93-
func setupProxyTest(t *testing.T, ctx context.Context, proxyConfig ProxyTestConfig) (*helpers.InfisicalService, *proxyHelpers.ProxyTestHelper, *helpers.Command, string, string) {
93+
func setupProxyTest(t *testing.T, ctx context.Context, proxyConfig ProxyTestConfig) (*helpers.InfisicalService, *proxyHelpers.ProxyTestHelper, *helpers.Command, string, string, helpers.MachineIdentity) {
9494
infisical := helpers.NewInfisicalService().Up(t, ctx)
9595

9696
// create machine identity with token auth (and universal auth if SSE is enabled)
@@ -145,14 +145,14 @@ func setupProxyTest(t *testing.T, ctx context.Context, proxyConfig ProxyTestConf
145145
// create test helper with both proxy and direct API clients
146146
helper := proxyHelpers.NewProxyTestHelper(t, proxyURL, infisical.ApiUrl(t), identityToken, projectID)
147147

148-
return infisical, helper, proxyCmd, identityToken, proxyURL
148+
return infisical, helper, proxyCmd, identityToken, proxyURL, identity
149149
}
150150

151151
func TestProxy_CacheHitMiss(t *testing.T) {
152152
ctx, cancel := context.WithCancel(context.Background())
153153
t.Cleanup(cancel)
154154

155-
_, helper, proxyCmd, _, _ := setupProxyTest(t, ctx, DefaultProxyTestConfig())
155+
_, helper, proxyCmd, _, _, _ := setupProxyTest(t, ctx, DefaultProxyTestConfig())
156156

157157
// create a test secret
158158
secret := helper.GenerateSecret(proxyHelpers.GenerateSecretOptions{
@@ -209,7 +209,7 @@ func TestProxy_MutationPurging(t *testing.T) {
209209
ctx, cancel := context.WithCancel(context.Background())
210210
t.Cleanup(cancel)
211211

212-
_, helper, proxyCmd, _, _ := setupProxyTest(t, ctx, DefaultProxyTestConfig())
212+
_, helper, proxyCmd, _, _, _ := setupProxyTest(t, ctx, DefaultProxyTestConfig())
213213

214214
initialSecret := helper.GenerateSecret(proxyHelpers.GenerateSecretOptions{
215215
Prefix: "MUTATION_TEST_",
@@ -281,7 +281,7 @@ func TestProxy_DeleteMutationPurging(t *testing.T) {
281281
ctx, cancel := context.WithCancel(context.Background())
282282
t.Cleanup(cancel)
283283

284-
_, helper, proxyCmd, _, _ := setupProxyTest(t, ctx, DefaultProxyTestConfig())
284+
_, helper, proxyCmd, _, _, _ := setupProxyTest(t, ctx, DefaultProxyTestConfig())
285285

286286
// create a test secret
287287
secret := helper.GenerateSecret(proxyHelpers.GenerateSecretOptions{
@@ -338,7 +338,7 @@ func TestProxy_TokenInvalidation(t *testing.T) {
338338
config := DefaultProxyTestConfig()
339339
config.AccessTokenCheckInterval = "2s"
340340

341-
_, helper, proxyCmd, _, _ := setupProxyTest(t, ctx, config)
341+
_, helper, proxyCmd, _, _, _ := setupProxyTest(t, ctx, config)
342342

343343
// create and cache a secret
344344
secret := helper.GenerateSecret(proxyHelpers.GenerateSecretOptions{
@@ -377,7 +377,7 @@ func TestProxy_HighAvailability(t *testing.T) {
377377
ctx, cancel := context.WithCancel(context.Background())
378378
t.Cleanup(cancel)
379379

380-
infisical, helper, proxyCmd, _, _ := setupProxyTest(t, ctx, DefaultProxyTestConfig())
380+
infisical, helper, proxyCmd, _, _, _ := setupProxyTest(t, ctx, DefaultProxyTestConfig())
381381

382382
// create and cache a secret
383383
secret := helper.GenerateSecret(proxyHelpers.GenerateSecretOptions{
@@ -451,7 +451,7 @@ func TestProxy_BackgroundRefresh(t *testing.T) {
451451
ctx, cancel := context.WithCancel(context.Background())
452452
t.Cleanup(cancel)
453453

454-
_, helper, proxyCmd, _, _ := setupProxyTest(t, ctx, DefaultProxyTestConfig())
454+
_, helper, proxyCmd, _, _, _ := setupProxyTest(t, ctx, DefaultProxyTestConfig())
455455

456456
// create a test initialSecret
457457
initialSecret := helper.GenerateSecret(proxyHelpers.GenerateSecretOptions{
@@ -520,7 +520,7 @@ func TestProxy_MultipleSecrets(t *testing.T) {
520520
ctx, cancel := context.WithCancel(context.Background())
521521
t.Cleanup(cancel)
522522

523-
_, helper, _, _, _ := setupProxyTest(t, ctx, DefaultProxyTestConfig())
523+
_, helper, _, _, _, _ := setupProxyTest(t, ctx, DefaultProxyTestConfig())
524524

525525
var secrets []proxyHelpers.Secret
526526
for i := 0; i < 3; i++ {
@@ -557,7 +557,7 @@ func TestProxy_SingleSecretEndpoint(t *testing.T) {
557557
ctx, cancel := context.WithCancel(context.Background())
558558
t.Cleanup(cancel)
559559

560-
_, helper, proxyCmd, _, _ := setupProxyTest(t, ctx, DefaultProxyTestConfig())
560+
_, helper, proxyCmd, _, _, _ := setupProxyTest(t, ctx, DefaultProxyTestConfig())
561561

562562
// create a test secret
563563
secret := helper.GenerateSecret(proxyHelpers.GenerateSecretOptions{
@@ -591,7 +591,7 @@ func TestProxy_SSECacheUpdate(t *testing.T) {
591591
ctx, cancel := context.WithCancel(context.Background())
592592
t.Cleanup(cancel)
593593

594-
_, helper, proxyCmd, _, _ := setupProxyTest(t, ctx, SSEProxyTestConfig())
594+
_, helper, proxyCmd, _, _, _ := setupProxyTest(t, ctx, SSEProxyTestConfig())
595595

596596
// wait for SSE manager initialization
597597
result := helpers.WaitForStderr(t, helpers.WaitForStderrOptions{
@@ -687,7 +687,7 @@ func TestProxy_SSEConnectionRecovery(t *testing.T) {
687687
ctx, cancel := context.WithCancel(context.Background())
688688
t.Cleanup(cancel)
689689

690-
infisical, helper, proxyCmd, _, _ := setupProxyTest(t, ctx, SSEProxyTestConfig())
690+
infisical, helper, proxyCmd, _, _, _ := setupProxyTest(t, ctx, SSEProxyTestConfig())
691691

692692
// create and cache a secret to trigger SSE subscription
693693
secret := helper.GenerateSecret(proxyHelpers.GenerateSecretOptions{
@@ -777,7 +777,7 @@ func TestProxy_SSEMultipleProjects(t *testing.T) {
777777
ctx, cancel := context.WithCancel(context.Background())
778778
t.Cleanup(cancel)
779779

780-
infisical, helper1, proxyCmd, identityToken, proxyURL := setupProxyTest(t, ctx, SSEProxyTestConfig())
780+
infisical, helper1, proxyCmd, identityToken, proxyURL, _ := setupProxyTest(t, ctx, SSEProxyTestConfig())
781781

782782
// create a second project using the same identity
783783
bearerAuth, err := securityprovider.NewSecurityProviderBearerToken(identityToken)
@@ -889,85 +889,76 @@ func TestProxy_SSEPollingFallbackRecovery(t *testing.T) {
889889
ctx, cancel := context.WithCancel(context.Background())
890890
t.Cleanup(cancel)
891891

892-
infisical, helper, proxyCmd, _, _ := setupProxyTest(t, ctx, SSEProxyTestConfig())
892+
infisical, helper, proxyCmd, _, _, identity := setupProxyTest(t, ctx, SSEProxyTestConfig())
893893

894-
// create and cache a secret to trigger SSE subscription
895-
secret := helper.GenerateSecret(proxyHelpers.GenerateSecretOptions{
896-
Prefix: "SSE_POLLING_RECOVERY_",
897-
})
898-
helper.CreateSecretWithApi(ctx, secret)
899-
900-
slog.Info("Caching secret via proxy")
901-
resp1 := helper.GetSecretsWithProxy(ctx)
902-
require.Equal(t, http.StatusOK, resp1.StatusCode())
903-
require.NotEmpty(t, resp1.JSON200.Secrets)
904-
905-
// wait for SSE connection established
906894
result := helpers.WaitForStderr(t, helpers.WaitForStderrOptions{
907895
EnsureCmdRunning: proxyCmd,
908-
ExpectedString: "SSE connection established",
896+
ExpectedString: "SSE manager initialized",
909897
Timeout: 30 * time.Second,
910898
})
911899
require.Equal(t, helpers.WaitSuccess, result)
912900

913-
// stop the Infisical backend to break SSE connection
914-
slog.Info("Stopping Infisical backend to break SSE connection")
915-
backendContainer, err := infisical.Compose().ServiceContainer(ctx, "backend")
916-
require.NoError(t, err)
917-
err = backendContainer.Stop(ctx, nil)
918-
require.NoError(t, err)
901+
// create secret via API (not proxy)
902+
initialSecret := helper.GenerateSecret(proxyHelpers.GenerateSecretOptions{
903+
Prefix: "SSE_POLLING_FALLBACK_RECOVERY_",
904+
})
905+
helper.CreateSecretWithApi(ctx, initialSecret)
919906

920-
require.Eventually(t, func() bool {
921-
state, err := backendContainer.State(ctx)
922-
if err != nil {
923-
return false
907+
// fetch via proxy -> cache miss, now cached
908+
slog.Info("Fetching secret via proxy (expecting cache miss)")
909+
resp1 := helper.GetSecretsWithProxy(ctx)
910+
require.Equal(t, http.StatusOK, resp1.StatusCode())
911+
require.NotNil(t, resp1.JSON200)
912+
913+
var foundInitial bool
914+
for _, s := range resp1.JSON200.Secrets {
915+
if s.SecretKey == initialSecret.SecretKey {
916+
assert.Equal(t, initialSecret.SecretValue, s.SecretValue)
917+
foundInitial = true
918+
break
924919
}
925-
return !state.Running
926-
}, 60*time.Second, 200*time.Millisecond, "Backend container should have stopped")
927-
slog.Info("Backend stopped")
920+
}
921+
require.True(t, foundInitial, "Initial secret not found in response")
928922

929-
// wait for SSE connection loss
923+
// wait for SSE connection (demand-driven, triggered by first fetch)
930924
result = helpers.WaitForStderr(t, helpers.WaitForStderrOptions{
931925
EnsureCmdRunning: proxyCmd,
932-
ExpectedString: "SSE connection lost",
926+
ExpectedString: "SSE connection established",
933927
Timeout: 30 * time.Second,
928+
Interval: 200 * time.Millisecond,
934929
})
935-
require.Equal(t, helpers.WaitSuccess, result, "SSE connection loss should be detected")
930+
require.Equal(t, helpers.WaitSuccess, result)
931+
932+
// change identity role to no-access to break SSE connection with auth errors
933+
slog.Info("Changing identity role to no-access to break SSE connection")
934+
infisical.UpdateMachineIdentityRole(t, ctx, identity.Id, "no-access")
936935

937-
// wait for SSE retries to exhaust and polling fallback to start (~62s worst case with backoff)
936+
// wait for SSE retries to exhaust and polling fallback to start
938937
slog.Info("Waiting for SSE retries to exhaust and polling fallback to start")
939938
result = helpers.WaitForStderr(t, helpers.WaitForStderrOptions{
940939
EnsureCmdRunning: proxyCmd,
941940
ExpectedString: "transitioning to polling fallback",
942-
Timeout: 180 * time.Second,
941+
Timeout: 120 * time.Second,
942+
Interval: 200 * time.Millisecond,
943943
})
944944
require.Equal(t, helpers.WaitSuccess, result, "Should transition to polling fallback after retries exhausted")
945945

946946
result = helpers.WaitForStderr(t, helpers.WaitForStderrOptions{
947947
EnsureCmdRunning: proxyCmd,
948948
ExpectedString: "Starting polling fallback for project",
949949
Timeout: 10 * time.Second,
950+
Interval: 200 * time.Millisecond,
950951
})
951952
require.Equal(t, helpers.WaitSuccess, result, "Polling fallback loop should start")
952953

953-
// restart the Infisical backend
954-
slog.Info("Restarting Infisical backend")
955-
err = backendContainer.Start(ctx)
956-
require.NoError(t, err)
957-
958-
require.Eventually(t, func() bool {
959-
state, err := backendContainer.State(ctx)
960-
if err != nil {
961-
return false
962-
}
963-
return state.Running
964-
}, 60*time.Second, 200*time.Millisecond, "Backend container should have restarted")
965-
slog.Info("Backend restarted")
954+
// restore identity role to member to allow SSE reconnection
955+
slog.Info("Restoring identity role to member")
956+
infisical.UpdateMachineIdentityRole(t, ctx, identity.Id, "member")
966957

967958
// trigger EnsureSubscription by making a request — detects polling, attempts SSE reconnection
968959
slog.Info("Fetching secrets to trigger SSE reconnection from polling mode")
969-
respAfterRestart := helper.GetSecretsWithProxy(ctx)
970-
require.Equal(t, http.StatusOK, respAfterRestart.StatusCode())
960+
respAfterRestore := helper.GetSecretsWithProxy(ctx)
961+
require.Equal(t, http.StatusOK, respAfterRestore.StatusCode())
971962

972963
// wait for SSE to re-establish (second occurrence after reconnection from polling)
973964
slog.Info("Waiting for SSE reconnection from polling mode")
@@ -987,7 +978,7 @@ func TestProxy_SSEPollingFallbackRecovery(t *testing.T) {
987978
// verify polling was cancelled after SSE recovery
988979
result = helpers.WaitForStderr(t, helpers.WaitForStderrOptions{
989980
EnsureCmdRunning: proxyCmd,
990-
ExpectedString: "cancelled polling fallback",
981+
ExpectedString: "Cancelled polling fallback",
991982
Timeout: 30 * time.Second,
992983
})
993984
require.Equal(t, helpers.WaitSuccess, result, "Polling should be cancelled after SSE recovery")
@@ -997,9 +988,4 @@ func TestProxy_SSEPollingFallbackRecovery(t *testing.T) {
997988
respFinal := helper.GetSecretsWithProxy(ctx)
998989
require.Equal(t, http.StatusOK, respFinal.StatusCode())
999990
require.True(t, proxyCmd.IsRunning(), "Proxy should still be running")
1000-
1001-
// tear down compose stack for clean state in subsequent tests
1002-
slog.Info("Tearing down compose stack for clean state")
1003-
err = infisical.DownWithForce(ctx)
1004-
require.NoError(t, err, "Failed to tear down compose stack")
1005991
}

e2e/util/helpers.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package util
22

33
import (
4+
"bytes"
45
"context"
6+
"encoding/json"
57
"errors"
68
"fmt"
79
"io"
@@ -265,6 +267,29 @@ func WithUniversalAuth() MachineIdentityOption {
265267
}
266268
}
267269

270+
func (s *InfisicalService) UpdateMachineIdentityRole(t *testing.T, ctx context.Context, identityId string, role string) {
271+
apiUrl := s.ApiUrl(t)
272+
url := fmt.Sprintf("%s/api/v1/identities/%s", apiUrl, identityId)
273+
274+
body, err := json.Marshal(map[string]string{"role": role})
275+
require.NoError(t, err)
276+
277+
req, err := http.NewRequestWithContext(ctx, http.MethodPatch, url, bytes.NewReader(body))
278+
require.NoError(t, err)
279+
req.Header.Set("Content-Type", "application/json")
280+
req.Header.Set("Authorization", "Bearer "+s.provisionResult.Token)
281+
282+
resp, err := (&http.Client{Timeout: 30 * time.Second}).Do(req)
283+
require.NoError(t, err)
284+
defer resp.Body.Close()
285+
286+
respBody, _ := io.ReadAll(resp.Body)
287+
require.True(t, resp.StatusCode >= 200 && resp.StatusCode < 300,
288+
"Failed to update identity role to '%s', status %d: %s", role, resp.StatusCode, string(respBody))
289+
290+
slog.Info("Updated machine identity role", "identityId", identityId, "role", role)
291+
}
292+
268293
type RunMethod string
269294

270295
const (

infisical-cli

79.5 MB
Binary file not shown.

0 commit comments

Comments
 (0)