Skip to content

Commit

Permalink
fix: placeholder tests
Browse files Browse the repository at this point in the history
  • Loading branch information
joel authored and joel committed Mar 9, 2024
1 parent 17e8e42 commit cfc6fa8
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 20 deletions.
13 changes: 7 additions & 6 deletions internal/api/hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ func (a *API) runHTTPHook(hookConfig conf.ExtensibilityPointConfiguration, input
})

defaultHookRetries := 3
hookLog.Infof("hook invoked")
inputPayload, err := json.Marshal(input)
if err != nil {
return nil, err
Expand Down Expand Up @@ -116,11 +115,11 @@ func (a *API) runHTTPHook(hookConfig conf.ExtensibilityPointConfiguration, input
rsp, err := client.Do(req)
if err != nil {
if terr, ok := err.(net.Error); ok && terr.Timeout() {
hookLog.Errorf("Request timed out for attempt %d", i)
hookLog.Errorf("Request timed out for attempt %d with err %s", i, err)
time.Sleep(defaultTimeout)
continue
} else if !watcher.gotConn {
hookLog.Errorf("Failed to establish a connection on attempt %d", i)
} else if !watcher.gotConn && i < defaultHookRetries-1 {
hookLog.Errorf("Failed to establish a connection on attempt %d with err %s", i, err)
time.Sleep(defaultTimeout)
continue
} else {
Expand All @@ -143,7 +142,8 @@ func (a *API) runHTTPHook(hookConfig conf.ExtensibilityPointConfiguration, input
}
return body, nil
case http.StatusTooManyRequests, http.StatusServiceUnavailable:
retryAfterHeader := rsp.Header.Get("Retry-After")
// TODO (joel): Accept more liberal naming?
retryAfterHeader := rsp.Header.Get("retry-after")
if retryAfterHeader != "" {
continue
}
Expand All @@ -156,7 +156,8 @@ func (a *API) runHTTPHook(hookConfig conf.ExtensibilityPointConfiguration, input
return []byte{}, internalServerError("error executing hooks")
}
}
return nil, nil
// TODO (joel): properly check for third attempt
return nil, internalServerError("error ex")
}

func generateSignatures(secrets []string, msgID uuid.UUID, currentTime time.Time, inputPayload []byte) ([]string, error) {
Expand Down
97 changes: 83 additions & 14 deletions internal/api/hooks_test.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
package api

import (
"encoding/json"
"net/http"
"testing"

"github.com/gofrs/uuid"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/supabase/auth/internal/conf"
"github.com/supabase/auth/internal/hooks"

"gopkg.in/h2non/gock.v1"
)

var handleApiRequest func(*http.Request) (*http.Response, error)

type HooksTestSuite struct {
suite.Suite
API *API
Config *conf.GlobalConfiguration
}

Expand All @@ -26,28 +32,91 @@ func (m *MockHttpClient) Do(req *http.Request) (*http.Response, error) {
}

func TestHooks(t *testing.T) {
api, config, err := setupAPIForTest()
require.NoError(t, err)

ts := &HooksTestSuite{
Config: &conf.GlobalConfiguration{},
API: api,
Config: config,
}
defer api.db.Close()

suite.Run(t, ts)
}

func (ts *HooksTestSuite) TestRunHTTPHook() {
defer gock.Off()
// body := CustomSMSProviderInput{}
//
// Test Case 1:
// testUrl := "http://localhost:54321/functions/v1/custom-sms-sender"
// response := gock.New(testUrl).Post("").
// MatchType("url").BodyString(body.Encode()).
// Reply(200).JSON(CustomSMSProviderOutput{})
defer gock.OffAll()

input := hooks.CustomSMSProviderInput{
UserID: uuid.Must(uuid.NewV4()),
Phone: "1234567890",
OTP: "123456",
}
successOutput := hooks.CustomSMSProviderOutput{Success: true}
testURL := "http://localhost:54321/functions/v1/custom-sms-sender"
ts.Config.Hook.CustomSMSProvider.URI = testURL

// Test Case 2: Too many requests MatchHeaders with retry-after header
testCases := []struct {
description string
mockResponse interface{}
status int
matchHeader map[string]string
expectError bool
}{
{
description: "Successful Post request with delay",
mockResponse: successOutput,
status: http.StatusOK,
expectError: false,
},
{
description: "Too many requests with retry-after header",
status: http.StatusTooManyRequests,
matchHeader: map[string]string{"retry-after": "true"},
expectError: true,
},
{
// TODO: maybe properly check for a condition in the w/o retry case
description: "Too many requests without retry header should not retry",
status: http.StatusTooManyRequests,
expectError: true,
},
}

for _, tc := range testCases {
ts.Run(tc.description, func() {
gock.Off()
request := gock.New(testURL).Post("/").MatchType("json").Reply(tc.status)

// Directly chain mock response setup
if tc.mockResponse != nil {
request.JSON(tc.mockResponse)
}

// Test Case 3: too many requests w/o retry header should not retry
// If there are headers to match, especially for responses
if tc.status == http.StatusTooManyRequests && tc.matchHeader != nil {
for key, value := range tc.matchHeader {
// Instead of creating a new Gock interceptor,
// use the `request` variable to chain setting headers on the response.
request.SetHeader(key, value)
}
}

//_, err = ts.API.runHTTPHook(a.config.Hooks.CustomSMSProvider, input, output)
// require.NoError(ts.T(), err)
var output hooks.CustomSMSProviderOutput

// Test the retry behaviour
body, err := ts.API.runHTTPHook(ts.Config.Hook.CustomSMSProvider, &input, &output)
if err == nil && body != nil {
err = json.Unmarshal(body, &output)
require.NoError(ts.T(), err, "Unmarshal should not fail")
require.True(ts.T(), output.Success, "Success should be true")
}

if tc.expectError {
require.Error(ts.T(), err)
} else {
require.NoError(ts.T(), err)
}
require.True(ts.T(), gock.IsDone(), "Expected HTTP mock to have been called")
})
}
}
8 changes: 8 additions & 0 deletions internal/hooks/auth_hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ const (
HookRejection = "reject"
)

type HTTPHookInput interface {
IsHTTPHook()
}

type HookOutput interface {
IsError() bool
Error() string
Expand Down Expand Up @@ -178,6 +182,10 @@ func (cs *CustomSMSProviderOutput) Error() string {
return cs.HookError.Message
}

func (cs *CustomSMSProviderOutput) IsHTTPHook() bool {
return true
}

type AuthHookError struct {
HTTPCode int `json:"http_code,omitempty"`
Message string `json:"message,omitempty"`
Expand Down

0 comments on commit cfc6fa8

Please sign in to comment.