diff --git a/.github/workflows/on-pull-request.yml b/.github/workflows/on-pull-request.yml index 2b17f40..8501e01 100644 --- a/.github/workflows/on-pull-request.yml +++ b/.github/workflows/on-pull-request.yml @@ -5,12 +5,6 @@ on: workflow_dispatch: pull_request: -env: - PASSAGE_APP_ID: ${{ secrets.PASSAGE_APP_ID }} - PASSAGE_API_KEY: ${{ secrets.PASSAGE_API_KEY }} - PASSAGE_USER_ID: ${{ secrets.PASSAGE_USER_ID }} - PASSAGE_AUTH_TOKEN: ${{ secrets.PASSAGE_AUTH_TOKEN }} - jobs: lint: name: Lint diff --git a/go.mod b/go.mod index a6da4b2..89a7921 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,6 @@ go 1.21 require ( github.com/golang-jwt/jwt v3.2.2+incompatible - github.com/joho/godotenv v1.5.1 github.com/lestrrat-go/jwx/v2 v2.1.3 github.com/oapi-codegen/runtime v1.1.1 github.com/stretchr/testify v1.10.0 diff --git a/go.sum b/go.sum index 0261cc8..1624174 100644 --- a/go.sum +++ b/go.sum @@ -13,8 +13,6 @@ github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keL github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= -github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE= github.com/lestrrat-go/blackmagic v1.0.2 h1:Cg2gVSc9h7sz9NOByczrbUvLopQmXrfFx//N+AkAr5k= github.com/lestrrat-go/blackmagic v1.0.2/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU= diff --git a/passage_test.go b/passage_test.go index a012ccb..46fc2d7 100644 --- a/passage_test.go +++ b/passage_test.go @@ -1,82 +1,13 @@ package passage_test import ( - "crypto/rand" - "fmt" - "os" - "strings" "sync" "testing" - "github.com/joho/godotenv" "github.com/passageidentity/passage-go/v2" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) -var ( - PassageAppID string - PassageApiKey string - PassageUserID string - PassageAuthToken string - RandomEmail = generateRandomEmail(14) - CreatedUser passage.PassageUser -) - -func generateRandomEmail(prefixLength int) string { - n := prefixLength - randomChars := make([]byte, n) - if _, err := rand.Read(randomChars); err != nil { - panic(err) - } - email := fmt.Sprintf("%X@email.com", randomChars) - return strings.ToLower(email) -} - -func TestMain(m *testing.M) { - _ = godotenv.Load(".env") - - PassageAppID = os.Getenv("PASSAGE_APP_ID") - PassageApiKey = os.Getenv("PASSAGE_API_KEY") - PassageUserID = os.Getenv("PASSAGE_USER_ID") - PassageAuthToken = os.Getenv("PASSAGE_AUTH_TOKEN") - - exitVal := m.Run() - os.Exit(exitVal) -} - -func passageUserNotFoundAsserts(t *testing.T, err error) { - splitError := strings.Split(err.Error(), ", ") - assert.Len(t, splitError, 3) - assert.Equal(t, "PassageError - message: User not found", splitError[0]) - assert.Equal(t, "errorCode: user_not_found", splitError[1]) - assert.Equal(t, "statusCode: 404", splitError[2]) -} - -func passageCouldNotFindUserByIdentifierAsserts(t *testing.T, err error) { - splitError := strings.Split(err.Error(), ", ") - assert.Len(t, splitError, 3) - assert.Equal(t, "PassageError - message: Could not find user with that identifier.", splitError[0]) - assert.Equal(t, "errorCode: user_not_found", splitError[1]) - assert.Equal(t, "statusCode: 404", splitError[2]) -} - -func passageUnauthorizedAsserts(t *testing.T, err error) { - splitError := strings.Split(err.Error(), ", ") - assert.Len(t, splitError, 3) - assert.Equal(t, "PassageError - message: Invalid access token", splitError[0]) - assert.Equal(t, "errorCode: invalid_access_token", splitError[1]) - assert.Equal(t, "statusCode: 401", splitError[2]) -} - -func passageBadRequestAsserts(t *testing.T, err error, message string) { - splitError := strings.Split(err.Error(), ", ") - assert.Len(t, splitError, 3) - assert.Equal(t, "PassageError - message: "+message, splitError[0]) - assert.Equal(t, "errorCode: invalid_request", splitError[1]) - assert.Equal(t, "statusCode: 400", splitError[2]) -} - // should be run with the -race flag, i.e. `go test -race -run TestAppJWKSCacheWriteConcurrency` func TestAppJWKSCacheWriteConcurrency(t *testing.T) { goRoutineCount := 2 @@ -88,7 +19,8 @@ func TestAppJWKSCacheWriteConcurrency(t *testing.T) { go func() { defer wg.Done() - _, err := passage.New(PassageAppID, PassageApiKey) + // a network call is made upon initialization to retrieve the JWKs from a real source + _, err := passage.New("passage", "some-api-key") require.Nil(t, err) }() } diff --git a/user_test.go b/user_test.go deleted file mode 100644 index 4d9e15e..0000000 --- a/user_test.go +++ /dev/null @@ -1,429 +0,0 @@ -package passage_test - -import ( - "fmt" - "strings" - "testing" - - "github.com/passageidentity/passage-go/v2" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestGetInfoX(t *testing.T) { - t.Run("Successful get user", func(t *testing.T) { - psg, err := passage.New(PassageAppID, PassageApiKey) - require.Nil(t, err) - - user, err := psg.User.Get(PassageUserID) - require.Nil(t, err) - assert.Equal(t, PassageUserID, user.ID) - }) - - t.Run("Error: unauthorized", func(t *testing.T) { - psg, err := passage.New(PassageAppID, "invalid api key") - require.Nil(t, err) - - _, err = psg.User.Get(PassageUserID) - require.NotNil(t, err) - passageUnauthorizedAsserts(t, err) - }) - - t.Run("Error: not found", func(t *testing.T) { - psg, err := passage.New(PassageAppID, PassageApiKey) - require.Nil(t, err) - - _, err = psg.User.Get("PassageUserID") - require.NotNil(t, err) - passageUserNotFoundAsserts(t, err) - }) -} - -func TestGetInfoByIdentifier(t *testing.T) { - t.Run("Success: get user by identifer - exact email", func(t *testing.T) { - psg, err := passage.New(PassageAppID, PassageApiKey) - require.Nil(t, err) - - createUserBody := passage.CreateUserArgs{ - Email: RandomEmail, - } - - user, err := psg.User.Create(createUserBody) - require.Nil(t, err) - assert.Equal(t, RandomEmail, user.Email) - - userByIdentifier, err := psg.User.GetByIdentifier(RandomEmail) - require.Nil(t, err) - - userById, err := psg.User.Get(user.ID) - require.Nil(t, err) - - assert.Equal(t, user.ID, userById.ID) - - assert.Equal(t, userById, userByIdentifier) - }) - - t.Run("Success: get user by identifer - email uppercase", func(t *testing.T) { - psg, err := passage.New(PassageAppID, PassageApiKey) - require.Nil(t, err) - - createUserBody := passage.CreateUserArgs{ - Email: RandomEmail, - } - - user, err := psg.User.Create(createUserBody) - require.Nil(t, err) - assert.Equal(t, RandomEmail, user.Email) - - userByIdentifier, err := psg.User.GetByIdentifier(strings.ToUpper(RandomEmail)) - require.Nil(t, err) - - assert.Equal(t, user.ID, userByIdentifier.ID) - }) - - t.Run("Success: get user by identifer - phone number", func(t *testing.T) { - psg, err := passage.New(PassageAppID, PassageApiKey) - require.Nil(t, err) - - phone := "+15005550007" - createUserBody := passage.CreateUserArgs{ - Phone: phone, - } - - user, err := psg.User.Create(createUserBody) - require.Nil(t, err) - assert.Equal(t, phone, user.Phone) - - userByIdentifier, err := psg.User.GetByIdentifier(phone) - require.Nil(t, err) - - userById, err := psg.User.Get(user.ID) - require.Nil(t, err) - - assert.Equal(t, user.ID, userById.ID) - - assert.Equal(t, userById, userByIdentifier) - }) - - t.Run("Error: identifier not found", func(t *testing.T) { - psg, err := passage.New(PassageAppID, PassageApiKey) - require.Nil(t, err) - - _, err = psg.User.GetByIdentifier("error@passage.id") - require.NotNil(t, err) - passageCouldNotFindUserByIdentifierAsserts(t, err) - }) - - t.Run("Error: unauthorized", func(t *testing.T) { - psg, err := passage.New(PassageAppID, "invalid api key") - require.Nil(t, err) - - _, err = psg.User.GetByIdentifier("any@passage.id") - require.NotNil(t, err) - passageUnauthorizedAsserts(t, err) - }) -} - -func TestActivate(t *testing.T) { - t.Run("Success: activate user", func(t *testing.T) { - psg, err := passage.New(PassageAppID, PassageApiKey) - require.Nil(t, err) - - user, err := psg.User.Activate(PassageUserID) - require.Nil(t, err) - assert.Equal(t, PassageUserID, user.ID) - assert.Equal(t, passage.StatusActive, user.Status) - }) - - t.Run("Error: unauthorized", func(t *testing.T) { - psg, err := passage.New(PassageAppID, "invalid api key") - require.Nil(t, err) - - _, err = psg.User.Activate(PassageUserID) - require.NotNil(t, err) - passageUnauthorizedAsserts(t, err) - }) - - t.Run("Error: not found", func(t *testing.T) { - psg, err := passage.New(PassageAppID, PassageApiKey) - require.Nil(t, err) - - _, err = psg.User.Activate("PassageUserID") - require.NotNil(t, err) - passageUserNotFoundAsserts(t, err) - }) -} -func TestDeactivate(t *testing.T) { - t.Run("Success: deactivate user", func(t *testing.T) { - psg, err := passage.New(PassageAppID, PassageApiKey) - require.Nil(t, err) - - user, err := psg.User.Deactivate(PassageUserID) - require.Nil(t, err) - assert.Equal(t, PassageUserID, user.ID) - assert.Equal(t, passage.StatusInactive, user.Status) - }) - - t.Run("Error: unauthorized", func(t *testing.T) { - psg, err := passage.New(PassageAppID, "invalid api key") - require.Nil(t, err) - - _, err = psg.User.Deactivate(PassageUserID) - require.NotNil(t, err) - passageUnauthorizedAsserts(t, err) - }) - - t.Run("Error: not found", func(t *testing.T) { - psg, err := passage.New(PassageAppID, PassageApiKey) - require.Nil(t, err) - - _, err = psg.User.Deactivate("PassageUserID") - require.NotNil(t, err) - - passageUserNotFoundAsserts(t, err) - }) -} - -func TestUpdate(t *testing.T) { - t.Run("Success: update user", func(t *testing.T) { - psg, err := passage.New(PassageAppID, PassageApiKey) - require.Nil(t, err) - - updateBody := passage.UpdateUserOptions{ - Email: "updatedemail-gosdk@passage.id", - Phone: "+15005550012", - UserMetadata: map[string]interface{}{ - "example1": "123", - }, - } - user, err := psg.User.Update(PassageUserID, updateBody) - require.Nil(t, err) - assert.Equal(t, "updatedemail-gosdk@passage.id", user.Email) - assert.Equal(t, "+15005550012", user.Phone) - assert.Equal(t, "123", user.UserMetadata["example1"]) - - secondUpdateBody := passage.UpdateUserOptions{ - Email: "updatedemail-gosdk@passage.id", - Phone: "+15005550012", - UserMetadata: map[string]interface{}{ - "example1": "456", - }, - } - user, err = psg.User.Update(PassageUserID, secondUpdateBody) - require.Nil(t, err) - assert.Equal(t, "updatedemail-gosdk@passage.id", user.Email) - assert.Equal(t, "+15005550012", user.Phone) - assert.Equal(t, "456", user.UserMetadata["example1"]) - }) - - t.Run("Error: Bad Request: on phone number", func(t *testing.T) { - psg, err := passage.New(PassageAppID, PassageApiKey) - require.Nil(t, err) - - updateBody := passage.UpdateUserOptions{ - Phone: " ", - } - _, err = psg.User.Update(PassageUserID, updateBody) - require.NotNil(t, err) - expectedMessage := "identifier: must be a valid E164 number." - passageBadRequestAsserts(t, err, expectedMessage) - }) - - t.Run("Error: Bad Request: on email", func(t *testing.T) { - psg, err := passage.New(PassageAppID, PassageApiKey) - require.Nil(t, err) - - updateBody := passage.UpdateUserOptions{ - Email: " ", - } - _, err = psg.User.Update(PassageUserID, updateBody) - require.NotNil(t, err) - expectedMessage := "identifier: must be a valid email address." - passageBadRequestAsserts(t, err, expectedMessage) - }) - - t.Run("Error: not found", func(t *testing.T) { - psg, err := passage.New(PassageAppID, PassageApiKey) - require.Nil(t, err) - - updateBody := passage.UpdateUserOptions{ - Email: "updatedemail-gosdk@passage.id", - Phone: "+15005550012", - UserMetadata: map[string]interface{}{ - "example1": "123", - }, - } - - _, err = psg.User.Update("PassageUserID", updateBody) - require.NotNil(t, err) - passageUserNotFoundAsserts(t, err) - }) - - t.Run("Error: unauthorized", func(t *testing.T) { - psg, err := passage.New(PassageAppID, "invalid api key") - require.Nil(t, err) - - updateBody := passage.UpdateUserOptions{ - Email: "updatedemail-gosdk@passage.id", - Phone: "+15005550012", - UserMetadata: map[string]interface{}{ - "example1": "123", - }, - } - - _, err = psg.User.Update(PassageUserID, updateBody) - require.NotNil(t, err) - passageUnauthorizedAsserts(t, err) - }) -} - -func TestCreate(t *testing.T) { - t.Run("Success: create user", func(t *testing.T) { - psg, err := passage.New(PassageAppID, PassageApiKey) - require.Nil(t, err) - - createUserBody := passage.CreateUserArgs{ - Email: RandomEmail, - } - - user, err := psg.User.Create(createUserBody) - require.Nil(t, err) - assert.Equal(t, RandomEmail, user.Email) - - CreatedUser = *user - }) - - t.Run("Success: create user with metadata", func(t *testing.T) { - psg, err := passage.New(PassageAppID, PassageApiKey) - require.Nil(t, err) - - createUserBody := passage.CreateUserArgs{ - Email: fmt.Sprintf("1%v", RandomEmail), - UserMetadata: map[string]interface{}{ - "example1": "test", - }, - } - - user, err := psg.User.Create(createUserBody) - require.Nil(t, err) - assert.Equal(t, "1"+RandomEmail, user.Email) - assert.Equal(t, "test", user.UserMetadata["example1"].(string)) - - CreatedUser = *user - }) - - t.Run("Error: Bad Request: on blank phone number and email", func(t *testing.T) { - psg, err := passage.New(PassageAppID, PassageApiKey) - require.Nil(t, err) - - createUserBody := passage.CreateUserArgs{ - Email: "", - Phone: "", - } - _, err = psg.User.Create(createUserBody) - - require.NotNil(t, err) - assert.Equal(t, "At least one of args.Email or args.Phone is required.", err.Error()) - }) - - t.Run("Error: unauthorized", func(t *testing.T) { - psg, err := passage.New(PassageAppID, "invalid api key") - require.Nil(t, err) - - createUserBody := passage.CreateUserArgs{ - Email: RandomEmail, - } - - _, err = psg.User.Create(createUserBody) - require.NotNil(t, err) - passageUnauthorizedAsserts(t, err) - }) -} - -func TestDelete(t *testing.T) { - t.Run("Success: delete user", func(t *testing.T) { - psg, err := passage.New(PassageAppID, PassageApiKey) - require.Nil(t, err) - - err = psg.User.Delete(CreatedUser.ID) - require.Nil(t, err) - }) - - t.Run("Error: unauthorized", func(t *testing.T) { - psg, err := passage.New(PassageAppID, "invalid api key") - require.Nil(t, err) - - err = psg.User.Delete(CreatedUser.ID) - require.NotNil(t, err) - passageUnauthorizedAsserts(t, err) - }) - - t.Run("Error: not found", func(t *testing.T) { - psg, err := passage.New(PassageAppID, PassageApiKey) - require.Nil(t, err) - - err = psg.User.Delete("PassageUserID") - require.NotNil(t, err) - - passageUserNotFoundAsserts(t, err) - }) -} - -func TestListUser(t *testing.T) { - t.Run("Success: list user devices", func(t *testing.T) { - psg, err := passage.New(PassageAppID, PassageApiKey) - require.Nil(t, err) - - devices, err := psg.User.ListDevices(PassageUserID) - require.Nil(t, err) - assert.Equal(t, 2, len(devices)) - }) - - t.Run("Error: unauthorized", func(t *testing.T) { - psg, err := passage.New(PassageAppID, "invalid api key") - require.Nil(t, err) - - _, err = psg.User.ListDevices(PassageUserID) - require.NotNil(t, err) - passageUnauthorizedAsserts(t, err) - }) - - t.Run("Error: not found", func(t *testing.T) { - psg, err := passage.New(PassageAppID, PassageApiKey) - require.Nil(t, err) - - _, err = psg.User.ListDevices("PassageUserID") - require.NotNil(t, err) - - passageUserNotFoundAsserts(t, err) - }) -} - -func TestRevokeRefreshTokens(t *testing.T) { - t.Run("Success: sign out user", func(t *testing.T) { - psg, err := passage.New(PassageAppID, PassageApiKey) - require.Nil(t, err) - - err = psg.User.RevokeRefreshTokens(PassageUserID) - require.Nil(t, err) - }) - - t.Run("Error: unauthorized", func(t *testing.T) { - psg, err := passage.New(PassageAppID, "invalid api key") - require.Nil(t, err) - - err = psg.User.RevokeRefreshTokens(PassageUserID) - require.NotNil(t, err) - passageUnauthorizedAsserts(t, err) - }) - - t.Run("Error: not found", func(t *testing.T) { - psg, err := passage.New(PassageAppID, PassageApiKey) - require.Nil(t, err) - - err = psg.User.RevokeRefreshTokens("PassageUserID") - require.NotNil(t, err) - - passageUserNotFoundAsserts(t, err) - }) -}