test: no location header in response (#8441)

# Which Problems Are Solved

Sometimes integrations tests are failing with an error `http: no
location header in response`. The underlying cause was hidden, as in
some tests we assumed a 3xx range response but got a 4xx response
instead. No assertion on the status code was made, resulting in the
above error message on calling `resp.Location()`.

The underlying issue, the application not found in the projection, is
also fixed.

# How the Problems Are Solved

This change adds a check for the status code and returns the response
body if the response is not in the 3xx status code range.

Helper function that create applications now do an additional
`GetAppByID` in a retry loop to ensure consitency in the projection
before proceeding with tests.

# Additional Changes

- none

# Additional Context

- Pipline failures were observed, no issue was created
- Cherry-picked form WIP #8407

Co-authored-by: Livio Spring <livio.a@gmail.com>
This commit is contained in:
Tim Möhlmann 2024-08-17 17:48:06 +03:00 committed by GitHub
parent c8e2a3bd49
commit 10d5fc6184
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 43 additions and 2 deletions

View File

@ -431,3 +431,19 @@ func (s *Tester) updateInstanceAndOrg(ctx context.Context, domain string) contex
logging.OnError(err).Fatal("query organisation") logging.OnError(err).Fatal("query organisation")
return ctx return ctx
} }
func await(af func() error) error {
maxTimer := time.NewTimer(15 * time.Minute)
for {
err := af()
if err == nil {
return nil
}
select {
case <-maxTimer.C:
return err
case <-time.After(time.Second / 10):
continue
}
}
}

View File

@ -3,6 +3,7 @@ package integration
import ( import (
"context" "context"
"fmt" "fmt"
"io"
"net/http" "net/http"
"net/url" "net/url"
"strings" "strings"
@ -27,7 +28,7 @@ func (s *Tester) CreateOIDCClient(ctx context.Context, redirectURI, logoutRedire
if len(grantTypes) == 0 { if len(grantTypes) == 0 {
grantTypes = []app.OIDCGrantType{app.OIDCGrantType_OIDC_GRANT_TYPE_AUTHORIZATION_CODE, app.OIDCGrantType_OIDC_GRANT_TYPE_REFRESH_TOKEN} grantTypes = []app.OIDCGrantType{app.OIDCGrantType_OIDC_GRANT_TYPE_AUTHORIZATION_CODE, app.OIDCGrantType_OIDC_GRANT_TYPE_REFRESH_TOKEN}
} }
return s.Client.Mgmt.AddOIDCApp(ctx, &management.AddOIDCAppRequest{ resp, err := s.Client.Mgmt.AddOIDCApp(ctx, &management.AddOIDCAppRequest{
ProjectId: projectID, ProjectId: projectID,
Name: fmt.Sprintf("app-%d", time.Now().UnixNano()), Name: fmt.Sprintf("app-%d", time.Now().UnixNano()),
RedirectUris: []string{redirectURI}, RedirectUris: []string{redirectURI},
@ -46,6 +47,16 @@ func (s *Tester) CreateOIDCClient(ctx context.Context, redirectURI, logoutRedire
AdditionalOrigins: nil, AdditionalOrigins: nil,
SkipNativeAppSuccessPage: false, SkipNativeAppSuccessPage: false,
}) })
if err != nil {
return nil, err
}
return resp, await(func() error {
_, err := s.Client.Mgmt.GetAppByID(ctx, &management.GetAppByIDRequest{
ProjectId: projectID,
AppId: resp.GetAppId(),
})
return err
})
} }
func (s *Tester) CreateOIDCNativeClient(ctx context.Context, redirectURI, logoutRedirectURI, projectID string, devMode bool) (*management.AddOIDCAppResponse, error) { func (s *Tester) CreateOIDCNativeClient(ctx context.Context, redirectURI, logoutRedirectURI, projectID string, devMode bool) (*management.AddOIDCAppResponse, error) {
@ -95,7 +106,7 @@ func (s *Tester) CreateOIDCImplicitFlowClient(ctx context.Context, redirectURI s
if err != nil { if err != nil {
return nil, err return nil, err
} }
return s.Client.Mgmt.AddOIDCApp(ctx, &management.AddOIDCAppRequest{ resp, err := s.Client.Mgmt.AddOIDCApp(ctx, &management.AddOIDCAppRequest{
ProjectId: project.GetId(), ProjectId: project.GetId(),
Name: fmt.Sprintf("app-%d", time.Now().UnixNano()), Name: fmt.Sprintf("app-%d", time.Now().UnixNano()),
RedirectUris: []string{redirectURI}, RedirectUris: []string{redirectURI},
@ -114,6 +125,16 @@ func (s *Tester) CreateOIDCImplicitFlowClient(ctx context.Context, redirectURI s
AdditionalOrigins: nil, AdditionalOrigins: nil,
SkipNativeAppSuccessPage: false, SkipNativeAppSuccessPage: false,
}) })
if err != nil {
return nil, err
}
return resp, await(func() error {
_, err := s.Client.Mgmt.GetAppByID(ctx, &management.GetAppByIDRequest{
ProjectId: project.GetId(),
AppId: resp.GetAppId(),
})
return err
})
} }
func (s *Tester) CreateOIDCTokenExchangeClient(ctx context.Context) (client *management.AddOIDCAppResponse, keyData []byte, err error) { func (s *Tester) CreateOIDCTokenExchangeClient(ctx context.Context) (client *management.AddOIDCAppResponse, keyData []byte, err error) {
@ -284,6 +305,10 @@ func CheckRedirect(req *http.Request) (*url.URL, error) {
return nil, err return nil, err
} }
defer resp.Body.Close() defer resp.Body.Close()
if resp.StatusCode < 300 || resp.StatusCode >= 400 {
body, _ := io.ReadAll(resp.Body)
return nil, fmt.Errorf("check redirect unexpected status: %q; body: %q", resp.Status, body)
}
return resp.Location() return resp.Location()
} }