package services import ( "context" "fmt" "strings" "testing" "github.com/DATA-DOG/go-sqlmock" "github.com/stretchr/testify/assert" "edge-infra.dev/pkg/edge/api/bsl/types" "edge-infra.dev/pkg/edge/api/graph/model" "edge-infra.dev/pkg/edge/api/middleware" sqlquery "edge-infra.dev/pkg/edge/api/sql" edgetypes "edge-infra.dev/pkg/edge/api/types" "edge-infra.dev/pkg/edge/bsl" ) func TestLogin(t *testing.T) { bspMockServer := GetMockBspServer(testOrganization, testOrganization, testUsername, model.RoleEdgeBannerViewer.String(), "testEmail", "testResetURL") appConfig := edgetypes.Config{ BSP: types.BSPConfig{ Endpoint: bspMockServer.URL, }, Bff: edgetypes.BffConfig{TopLevelProjectID: testOrganization}, } bslClient := bsl.NewBSLClient(appConfig.BSP, nil) service := NewUserManagementService(appConfig, bslClient, nil, nil, nil) ctx := context.Background() user, err := service.Login(ctx, "test", "testPassword", testOrganization) assert.Nil(t, err) assert.NotEmpty(t, user) assert.Equal(t, 1, len(user.Roles)) assert.Empty(t, user.Banners) // user.Banners is set using forceResolver } func TestUpdatePasswordWToken(t *testing.T) { bspMockServer := GetMockBspServer("testOrg", "testOrgID", "testUser", "EDGE_BANNER_VIEWER", "testEmail", "testResetURL") appConfig := edgetypes.Config{ BSP: types.BSPConfig{ Endpoint: bspMockServer.URL, }, Bff: edgetypes.BffConfig{TopLevelProjectID: "test-org"}, } bslClient := bsl.NewBSLClient(appConfig.BSP, nil) ctx := context.Background() service := NewUserManagementService(appConfig, bslClient, nil, nil, nil) err := service.UpdateUserPasswordWithToken(ctx, "good-token", "org", "good-password") assert.Nil(t, err, "No error should be thrown for good token, org and password") err = service.UpdateUserPasswordWithToken(ctx, "good-token", "org", "bad-password") assert.Error(t, err, "Error should be thrown for bad password") err = service.UpdateUserPasswordWithToken(ctx, "bad-token", "org", "bad-token") assert.Error(t, err, "Error should be thrown for bad token") } func TestGetUser(t *testing.T) { bspMockServer := GetMockBspServer("testOrg", "testOrgID", "testUser", "EDGE_BANNER_VIEWER", "testEmail", "testResetURL") appConfig := edgetypes.Config{ BSP: types.BSPConfig{ Endpoint: bspMockServer.URL, }, Bff: edgetypes.BffConfig{TopLevelProjectID: "test-org"}, } bslClient := bsl.NewBSLClient(appConfig.BSP, nil) service := NewUserManagementService(appConfig, bslClient, nil, nil, nil) contextWithAuth := middleware.NewContext(context.Background(), &types.AuthUser{ Username: testUsername, Token: testBSLToken, Organization: testOrganization, }) user, err := service.GetUser(contextWithAuth, "test", "edge-dev0-edge-b413cb", "token", "bsl") assert.Nil(t, err) assert.NotEmpty(t, user) } func TestGetUsers(t *testing.T) { bspMockServer := GetMockBspServer("testOrg", "testOrgID", "testUser", "EDGE_BANNER_VIEWER", "testEmail", "testResetURL") appConfig := edgetypes.Config{ BSP: types.BSPConfig{ Endpoint: bspMockServer.URL, }, Bff: edgetypes.BffConfig{TopLevelProjectID: "test-org"}, } bslClient := bsl.NewBSLClient(appConfig.BSP, nil) service := NewUserManagementService(appConfig, bslClient, nil, nil, nil) contextWithAuth := middleware.NewContext(context.Background(), &types.AuthUser{ Username: testUsername, Token: testBSLToken, Organization: testOrganization, }) users, err := service.GetUsers(contextWithAuth) assert.Nil(t, err) assert.Equal(t, 1, len(users)) if len(users) > 0 { for _, user := range users { assert.True(t, !strings.HasSuffix(user.Username, fmt.Sprintf("-%s", edgetypes.BFFUsername))) } } } func TestUpdateUserProfile(t *testing.T) { bspMockServer := GetMockBspServer("testOrg", "testOrgID", "testUser", "EDGE_BANNER_VIEWER", "testEmail", "testResetURL") appConfig := edgetypes.Config{ BSP: types.BSPConfig{ Endpoint: bspMockServer.URL, }, Bff: edgetypes.BffConfig{TopLevelProjectID: "test-org"}, } bslClient := bsl.NewBSLClient(appConfig.BSP, nil) service := NewUserManagementService(appConfig, bslClient, nil, nil, nil) contextWithAuth := middleware.NewContext(context.Background(), &types.AuthUser{ Username: testUsername, Token: testBSLToken, Organization: testOrganization, }) familyName := "Josh" updateRequest := &model.UpdateUser{ Username: "acct:edge-dev0-edge-b413cb@test", FamilyName: &familyName, } user, err := service.UpdateUserProfile(contextWithAuth, updateRequest) assert.Nil(t, err) assert.NotEmpty(t, user) } func TestGetUsersFilteredServiceAcc(t *testing.T) { bspMockServer := GetMockBspServer("testOrg", "testOrgID", "testUser", "EDGE_BANNER_VIEWER", "testEmail", "testResetURL") appConfig := edgetypes.Config{ BSP: types.BSPConfig{ Endpoint: bspMockServer.URL, }, Bff: edgetypes.BffConfig{TopLevelProjectID: "test-org"}, } bannerName := "dev1-engineering" bslClient := bsl.NewBSLClient(appConfig.BSP, nil) service := NewUserManagementService(appConfig, bslClient, nil, nil, nil) contextWithAuth := middleware.NewContext(context.Background(), &types.AuthUser{ Username: "acct:Harry", Token: testBSLToken, Organization: testOrganization, }) user, err := service.GetUsersForOrgBanner(contextWithAuth, bannerName) assert.NoError(t, err) assert.NotEmpty(t, user) } func TestVerifyOktaToken_Valid(t *testing.T) { bspMockServer := GetMockBspServer("testOrg", "testOrgID", "testUser", "EDGE_BANNER_VIEWER", "testEmail", "testResetURL") appConfig := edgetypes.Config{ Okta: *oktaConfig, BSP: types.BSPConfig{ Endpoint: bspMockServer.URL, }, } service := NewUserManagementService(appConfig, nil, oktaClient, nil, nil) resp, err := service.VerifyOktaToken(context.Background(), "good-okta-token") assert.NoError(t, err) assert.True(t, resp.Active) } func TestVerifyOktaToken_Invalid(t *testing.T) { bspMockServer := GetMockBspServer("testOrg", "testOrgID", "testUser", "EDGE_BANNER_VIEWER", "testEmail", "testResetURL") appConfig := edgetypes.Config{ Okta: *oktaConfig, BSP: types.BSPConfig{ Endpoint: bspMockServer.URL, }, } service := NewUserManagementService(appConfig, nil, oktaClient, nil, nil) resp, err := service.VerifyOktaToken(context.Background(), "bad-okta-token") assert.Error(t, err) assert.Empty(t, resp) } func TestLoginWithOktaToken_Valid(t *testing.T) { bspMockServer := GetMockBspServer("testOrg", "testOrgID", "testUser", "EDGE_BANNER_VIEWER", "testEmail", "testResetURL") appConfig := edgetypes.Config{ Okta: *oktaConfig, BSP: types.BSPConfig{ Endpoint: bspMockServer.URL, }, } bslClient := bsl.NewBSLClient(appConfig.BSP, nil) service := NewUserManagementService(appConfig, bslClient, oktaClient, nil, nil) resp, err := service.LoginWithOktaToken(context.Background(), "good-okta-token", "test-refresh-token", "test-org") assert.NoError(t, err) assert.NotNil(t, resp) } func TestLoginWithOktaToken_BadToken(t *testing.T) { bspMockServer := GetMockBspServer("testOrg", "testOrgID", "testUser", "EDGE_BANNER_VIEWER", "testEmail", "testResetURL") appConfig := edgetypes.Config{ Okta: *oktaConfig, BSP: types.BSPConfig{ Endpoint: bspMockServer.URL, }, } service := NewUserManagementService(appConfig, nil, oktaClient, nil, nil) resp, err := service.LoginWithOktaToken(context.Background(), "bad-okta-token", "test-refresh-token", "test-org") assert.Error(t, err) assert.Nil(t, resp) } func TestLoginWithOktaToken_InValid(t *testing.T) { bspMockServer := GetMockBspServer("testOrg", "testOrgID", "testUser", "EDGE_BANNER_VIEWER", "testEmail", "testResetURL") appConfig := edgetypes.Config{ Okta: *oktaConfig, BSP: types.BSPConfig{ Endpoint: bspMockServer.URL, }, } service := NewUserManagementService(appConfig, nil, oktaClient, nil, nil) resp, err := service.LoginWithOktaToken(context.Background(), "invalid-okta-token", "test-refresh-token", "test-org") assert.Error(t, err) assert.Nil(t, resp) } func TestTokenExchangeOkta(t *testing.T) { bspMockServer := GetMockBspServer("testOrg", "testOrgID", "testUser", "EDGE_BANNER_VIEWER", "testEmail", "testResetURL") appConfig := edgetypes.Config{ Okta: *oktaConfig, BSP: types.BSPConfig{ Endpoint: bspMockServer.URL, }, Bff: edgetypes.BffConfig{TopLevelProjectID: "test-org"}, } bslClient := bsl.NewBSLClient(appConfig.BSP, nil) service := NewUserManagementService(appConfig, bslClient, oktaClient, nil, nil) resp, err := service.TokenExchange(context.Background(), "test-org", &types.AuthUser{ Email: "test@ncr.com", Organization: "test-org", Username: "testUser", Token: "good-okta-token", Roles: []string{"EDGE_ORG_ADMIN"}, }, "okta") assert.NoError(t, err) assert.NotNil(t, resp) } func TestTokenExchangeBSL(t *testing.T) { bspMockServer := GetMockBspServer("testOrg", "testOrgID", "testUser", "EDGE_BANNER_VIEWER", "testEmail", "testResetURL") appConfig := edgetypes.Config{ Okta: *oktaConfig, BSP: types.BSPConfig{ Endpoint: bspMockServer.URL, }, Bff: edgetypes.BffConfig{TopLevelProjectID: "test-org"}, } bslClient := bsl.NewBSLClient(appConfig.BSP, nil) service := NewUserManagementService(appConfig, bslClient, oktaClient, nil, nil) resp, err := service.TokenExchange(context.Background(), "test-org", &types.AuthUser{ Email: "test@ncr.com", Organization: "test-org", Username: "testUser", Token: "good-bsl-token", Roles: []string{"EDGE_ORG_ADMIN"}, }, "bsl") assert.NoError(t, err) assert.NotNil(t, resp) } func TestGetSessionUserEdgeRole(t *testing.T) { bspMockServer := GetMockBspServer("testOrg", "testOrgID", "testUser", "EDGE_BANNER_VIEWER", "testEmail", "testResetURL") appConfig := edgetypes.Config{ BSP: types.BSPConfig{ Endpoint: bspMockServer.URL, }, Bff: edgetypes.BffConfig{TopLevelProjectID: "test-org"}, } bslClient := bsl.NewBSLClient(appConfig.BSP, nil) service := NewUserManagementService(appConfig, bslClient, nil, nil, nil) user, err := service.GetSessionUserEdgeRoles(context.Background(), "test-user", "test-token", "test-org", "bsl") assert.NotNil(t, user) assert.NoError(t, err) } func TestUserData(t *testing.T) { db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) if err != nil { t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) } defer db.Close() mock.ExpectQuery(sqlquery.GetBannerByBSLID).WithArgs("test-org-banner"). WillReturnRows(sqlmock.NewRows([]string{"banner_edge_id", "banner_bsl_id", "banner_name", "banner_type", "project_id", "tenant_edge_id", "description", "bsl_data_synced", "bsl_entity_types", "edge_sec_opt_in_compliance"}). AddRow("test-org-banner", "test-org-banner", "eu-banner-bsl-id2", "EU", "eu-banner-bsl-id3", "eu-banner-bsl-id4", "eu-banner-bsl-id5", false, nil, true)) mock.ExpectQuery(sqlquery.GetBannerByBSLID).WithArgs("test-org-banner"). WillReturnRows(sqlmock.NewRows([]string{"banner_edge_id", "banner_bsl_id", "banner_name", "banner_type", "project_id", "tenant_edge_id", "description", "bsl_data_synced", "bsl_entity_types", "edge_sec_opt_in_compliance"}). AddRow("test-org-banner", "test-org-banner", "eu-banner-bsl-id2", "EU", "eu-banner-bsl-id3", "eu-banner-bsl-id4", "eu-banner-bsl-id5", false, nil, true)) mock.ExpectQuery(sqlquery.GetBannerByBSLID).WithArgs("eu-banner-bsl-id"). WillReturnRows(sqlmock.NewRows([]string{"banner_edge_id", "banner_bsl_id", "banner_name", "banner_type", "project_id", "tenant_edge_id", "description", "bsl_data_synced", "bsl_entity_types", "edge_sec_opt_in_compliance"}). AddRow("eu-banner-bsl-id", "test-org-banner", "eu-banner-bsl-id2", "EU", "eu-banner-bsl-id3", "eu-banner-bsl-id4", "eu-banner-bsl-id5", false, nil, true)) bspMockServer := GetMockBspServer("testOrg", "testOrgID", "testUser", "EDGE_BANNER_VIEWER", "testEmail", "testResetURL") appConfig := edgetypes.Config{ BSP: types.BSPConfig{ Endpoint: bspMockServer.URL, }, Bff: edgetypes.BffConfig{TopLevelProjectID: "test-org"}, } bslClient := bsl.NewBSLClient(appConfig.BSP, nil) roleSvc := NewRoleService(appConfig.BSP, bslClient) bannerSvc := NewBannerService(nil, nil, bslClient, "", db, defaultCfg) service := NewUserManagementService(appConfig, bslClient, nil, roleSvc, bannerSvc) contextWithAuth := middleware.NewContext(context.Background(), &types.AuthUser{ Username: testUsername, Token: testBSLToken, Organization: testOrganization, }) userData, err := service.UserData(contextWithAuth, "test") assert.NotNil(t, userData) assert.NoError(t, err) } func TestWhoAmI_BSL(t *testing.T) { db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) if err != nil { t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) } defer db.Close() mock.ExpectQuery(sqlquery.GetBannerByBSLID).WithArgs("test-org-banner"). WillReturnRows(sqlmock.NewRows([]string{"banner_edge_id", "banner_bsl_id", "banner_name", "banner_type", "project_id", "tenant_edge_id", "description", "edge_sec_opt_in_compliance"}). AddRow("test-org-banner", "test-org-banner", "eu-banner-bsl-id2", "EU", "eu-banner-bsl-id3", "eu-banner-bsl-id4", "eu-banner-bsl-id5", true)) mock.ExpectQuery(sqlquery.GetBannerByBSLID).WithArgs("test-org-banner"). WillReturnRows(sqlmock.NewRows([]string{"banner_edge_id", "banner_bsl_id", "banner_name", "banner_type", "project_id", "tenant_edge_id", "description", "edge_sec_opt_in_compliance"}). AddRow("test-org-banner", "test-org-banner", "eu-banner-bsl-id2", "EU", "eu-banner-bsl-id3", "eu-banner-bsl-id4", "eu-banner-bsl-id5", true)) mock.ExpectQuery(sqlquery.GetBannerByBSLID).WithArgs("eu-banner-bsl-id"). WillReturnRows(sqlmock.NewRows([]string{"banner_edge_id", "banner_bsl_id", "banner_name", "banner_type", "project_id", "tenant_edge_id", "description", "edge_sec_opt_in_compliance"}). AddRow("eu-banner-bsl-id", "test-org-banner", "eu-banner-bsl-id2", "EU", "eu-banner-bsl-id3", "eu-banner-bsl-id4", "eu-banner-bsl-id5", true)) bspMockServer := GetMockBspServer("testOrg", "testOrgID", "testUser", "EDGE_BANNER_VIEWER", "testEmail", "testResetURL") appConfig := edgetypes.Config{ BSP: types.BSPConfig{ Endpoint: bspMockServer.URL, }, Bff: edgetypes.BffConfig{TopLevelProjectID: "test-org"}, } bslClient := bsl.NewBSLClient(appConfig.BSP, nil) roleSvc := NewRoleService(appConfig.BSP, bslClient) bannerSvc := NewBannerService(nil, nil, bslClient, "", db, defaultCfg) service := NewUserManagementService(appConfig, bslClient, nil, roleSvc, bannerSvc) contextWithAuth := middleware.NewContext(context.Background(), &types.AuthUser{ Username: testUsername, Token: testBSLToken, Organization: testOrganization, }) userData, err := service.WhoAmI(contextWithAuth, "test", "test-org-banner", "testToken", "bsl") assert.NotNil(t, userData) assert.NoError(t, err) } func TestWhoAmI_OKTA(t *testing.T) { db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) if err != nil { t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) } defer db.Close() mock.ExpectQuery(sqlquery.GetBannerByBSLID).WithArgs("test-org-banner"). WillReturnRows(sqlmock.NewRows([]string{"banner_edge_id", "banner_bsl_id", "banner_name", "banner_type", "project_id", "tenant_edge_id", "description", "edge_sec_opt_in_compliance"}). AddRow("test-org-banner", "test-org-banner", "eu-banner-bsl-id2", "EU", "eu-banner-bsl-id3", "eu-banner-bsl-id4", "eu-banner-bsl-id5", true)) mock.ExpectQuery(sqlquery.GetBannerByBSLID).WithArgs("test-org-banner"). WillReturnRows(sqlmock.NewRows([]string{"banner_edge_id", "banner_bsl_id", "banner_name", "banner_type", "project_id", "tenant_edge_id", "description", "edge_sec_opt_in_compliance"}). AddRow("test-org-banner", "test-org-banner", "eu-banner-bsl-id2", "EU", "eu-banner-bsl-id3", "eu-banner-bsl-id4", "eu-banner-bsl-id5", true)) mock.ExpectQuery(sqlquery.GetBannerByBSLID).WithArgs("eu-banner-bsl-id"). WillReturnRows(sqlmock.NewRows([]string{"banner_edge_id", "banner_bsl_id", "banner_name", "banner_type", "project_id", "tenant_edge_id", "description", "edge_sec_opt_in_compliance"}). AddRow("eu-banner-bsl-id", "test-org-banner", "eu-banner-bsl-id2", "EU", "eu-banner-bsl-id3", "eu-banner-bsl-id4", "eu-banner-bsl-id5", true)) bspMockServer := GetMockBspServer("testOrg", "testOrgID", "testUser", "EDGE_BANNER_VIEWER", "testEmail", "testResetURL") appConfig := edgetypes.Config{ Okta: *oktaConfig, BSP: types.BSPConfig{ Endpoint: bspMockServer.URL, }, Bff: edgetypes.BffConfig{TopLevelProjectID: "test-org"}, } bslClient := bsl.NewBSLClient(appConfig.BSP, nil) roleSvc := NewRoleService(appConfig.BSP, bslClient) bannerSvc := NewBannerService(nil, nil, bslClient, "", db, defaultCfg) service := NewUserManagementService(appConfig, bslClient, oktaClient, roleSvc, bannerSvc) contextWithAuth := middleware.NewContext(context.Background(), &types.AuthUser{ Username: testUsername, Token: testBSLToken, Organization: testOrganization, }) userData, err := service.WhoAmI(contextWithAuth, "test", "test-org-banner", "testToken", "okta") assert.NotNil(t, userData) assert.NoError(t, err) }