Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[tests-only] [full-ci] Restructure e2e tests data storage for keycloak #10895

Merged
merged 13 commits into from
Jun 19, 2024
1 change: 1 addition & 0 deletions .drone.star
Original file line number Diff line number Diff line change
Expand Up @@ -1796,6 +1796,7 @@ def e2eTestsOnKeycloak(ctx):
e2e_Keycloak_tests = [
"journeys",
"admin-settings/users.feature:20",
"admin-settings/spaces.feature",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks, that you included spaces.feature 👍
did you try to run test for a full admin-settings/users.feature?

and second question: can we include admin-settings/groups.feature to keycloak test?

Copy link
Member Author

@nabim777 nabim777 Jun 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I try to run full, but it fails. There is problem on afterall during clean-up which fails to delete the users from oCIS-web. I'll cover that in another PR, but I might need your advice. May be after that we can include some other feature file for keycloak.

Since there is issue on group creation for keycloak issue. So, I think we cannot include the tests related to the group. Or should we include?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ScharfViktor I think user.feature file contains scenarios which change users ceredentials like name, role and password. If we run e2e scenario in user.feature which changes user name, role and password through web-UI then our tests fail because ocis side changes on user name , password , role will not sync with keycloak. Is this actual feature of ocis or a bug?
If unable to change user name, role, password from web is a feature then change quota is only e2e scenario we can run from user.feature file

]

e2e_volumes = [
Expand Down
7 changes: 5 additions & 2 deletions tests/e2e/cucumber/environment/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@ import {
createdSpaceStore,
createdLinkStore,
createdGroupStore,
createdUserStore
createdUserStore,
keycloakCreatedUser
} from '../../support/store'
import { Group, User } from '../../support/types'
import { getTokenFromLogin } from '../../support/utils/tokenHelper'
import { createdTokenStore } from '../../support/store/token'
import { createdTokenStore, keycloakTokenStore } from '../../support/store/token'
import { removeTempUploadDirectory } from '../../support/utils/runtimeFs'
import { refreshToken, setupKeycloakAdminUser } from '../../support/api/keycloak'
import { closeSSEConnections } from '../../support/environment/sse'
Expand Down Expand Up @@ -129,6 +130,7 @@ After(async function (this: World, { result, willBeRetried }: ITestCaseHookParam

createdLinkStore.clear()
createdTokenStore.clear()
keycloakTokenStore.clear()
removeTempUploadDirectory()
closeSSEConnections()
})
Expand All @@ -144,6 +146,7 @@ const cleanUpUser = async (adminUser: User) => {
})
await Promise.all(requests)
createdUserStore.clear()
keycloakCreatedUser.clear()
}

const cleanUpSpaces = async (adminUser: User) => {
Expand Down
8 changes: 4 additions & 4 deletions tests/e2e/cucumber/steps/ui/adminSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -225,10 +225,10 @@ Then(
for (const { user } of stepTable.hashes()) {
switch (action) {
case 'should':
expect(users).toContain(await usersObject.getUUID({ key: user }))
expect(users).toContain(usersObject.getUUID({ key: user }))
break
case 'should not':
expect(users).not.toContain(await usersObject.getUUID({ key: user }))
expect(users).not.toContain(usersObject.getUUID({ key: user }))
break
default:
throw new Error(`'${action}' not implemented`)
Expand Down Expand Up @@ -263,7 +263,7 @@ When(
const userIds = []

for (const { user } of stepTable.hashes()) {
userIds.push(await usersObject.getUUID({ key: user }))
userIds.push(usersObject.getUUID({ key: user }))
await usersObject.select({ key: user })
}

Expand Down Expand Up @@ -347,7 +347,7 @@ When(
switch (actionType) {
case 'batch actions':
for (const { id: user } of stepTable.hashes()) {
userIds.push(await usersObject.getUUID({ key: user }))
userIds.push(usersObject.getUUID({ key: user }))
await usersObject.selectUser({ key: user })
}
await usersObject.deleteUserUsingBatchAction({ userIds })
Expand Down
19 changes: 3 additions & 16 deletions tests/e2e/support/api/graph/userManagement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,20 +92,6 @@ export const createGroup = async ({
return group
}

const getGroupId = async ({ group, admin }: { group: Group; admin: User }): Promise<string> => {
Copy link
Contributor

@amrita-shrestha amrita-shrestha Jun 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why u remove this api function?

Copy link
Member Author

@nabim777 nabim777 Jun 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function simply returns the group uuid by hitting the API. But the group uuid was already stored during group creation. So, replacing it with the stored value on getCreatedGroup makes this function unused and tends to be removed.
Is it okay to remove it?
or may it be needed in the future, so I have not removed it?
or is there any use cases of this function which I have not found?

Moreover it also throws lint error

error  'getGroupId' is assigned a value but never used  @typescript-eslint/no-unused-vars

let groupId = ''
const response = await request({
method: 'GET',
path: join('graph', 'v1.0', 'groups', group.displayName),
user: admin
})
if (response.ok) {
const resBody = (await response.json()) as Group
groupId = resBody.id
}
return groupId
}

export const deleteGroup = async ({
group,
admin
Expand Down Expand Up @@ -133,8 +119,9 @@ export const addUserToGroup = async ({
group: Group
admin: User
}): Promise<void> => {
const groupId = await getGroupId({ group, admin })
const userId = await getUserId({ user, admin })
const usersEnvironment = new UsersEnvironment()
const userId = usersEnvironment.getCreatedUser({ key: user.id }).uuid
const groupId = usersEnvironment.getCreatedGroup({ key: group.id }).uuid
const body = JSON.stringify({
'@odata.id': join(config.backendUrl, 'graph', 'v1.0', 'users', userId)
})
Expand Down
30 changes: 23 additions & 7 deletions tests/e2e/support/api/keycloak/user.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import join from 'join-path'
import { getUserIdFromResponse, request, realmBasePath } from './utils'
import { deleteUser as graphDeleteUser } from '../graph'
import { deleteUser as graphDeleteUser, getUserId } from '../graph'
import { checkResponseStatus } from '../http'
import { User, KeycloakRealmRole } from '../../types'
import { UsersEnvironment } from '../../environment'
Expand Down Expand Up @@ -43,19 +43,26 @@ export const createUser = async ({ user, admin }: { user: User; admin: User }):
checkResponseStatus(creationRes, 'Failed while creating user')

// created user id
const uuid = getUserIdFromResponse(creationRes)
const keycloakUUID = getUserIdFromResponse(creationRes)

// assign realmRoles to user
const defaultNewUserRole = 'User'
const roleRes = await assignRole({ admin, uuid, role: defaultNewUserRole })
const roleRes = await assignRole({ admin, uuid: keycloakUUID, role: defaultNewUserRole })
checkResponseStatus(roleRes, 'Failed while assigning roles to user')

const usersEnvironment = new UsersEnvironment()
usersEnvironment.storeCreatedUser({ user: { ...user, uuid, role: defaultNewUserRole } })
// stored keycloak user information on storage
usersEnvironment.storeCreatedKeycloakUser({
user: { ...user, uuid: keycloakUUID, role: defaultNewUserRole }
})

// initialize user
// login to initialize the user in oCIS Web
await initializeUser(user.id)

// store oCIS user information
usersEnvironment.storeCreatedUser({
user: { ...user, uuid: await getUserId({ user, admin }), role: defaultNewUserRole }
})
return user
}

Expand Down Expand Up @@ -115,13 +122,22 @@ export const deleteUser = async ({ user, admin }: { user: User; admin: User }):
// deletes the user data
await graphDeleteUser({ user, admin })

const usersEnvironment = new UsersEnvironment()
const keyclockUser = usersEnvironment.getCreatedKeycloakUser({ key: user.id })
const response = await request({
method: 'DELETE',
path: join(realmBasePath, 'users', user.uuid),
path: join(realmBasePath, 'users', keyclockUser.uuid),
user: admin
})
checkResponseStatus(response, 'Failed to delete keycloak user: ' + user.id)

if (response.ok) {
try {
const usersEnvironment = new UsersEnvironment()
usersEnvironment.removeCreatedKeycloakUser({ key: user.id })
} catch (e) {
console.error('Error removing Keycloak user:', e)
}
}
return user
}

Expand Down
4 changes: 2 additions & 2 deletions tests/e2e/support/api/provision/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export const assignRole = async ({
}): Promise<void> => {
if (config.keycloak) {
const usersEnvironment = new UsersEnvironment()
const createdUser = usersEnvironment.getCreatedUser({ key: user.id })
const createdUser = usersEnvironment.getCreatedKeycloakUser({ key: user.id })
await keycloakAssignRole({ admin, uuid: createdUser.uuid, role })
} else {
const id = await getUserId({ user, admin })
Expand All @@ -50,7 +50,7 @@ export const assignRole = async ({
export const unAssignRole = async ({ admin, user }: { admin: User; user: User }): Promise<void> => {
if (config.keycloak) {
const usersEnvironment = new UsersEnvironment()
const createdUser = usersEnvironment.getCreatedUser({ key: user.id })
const createdUser = usersEnvironment.getCreatedKeycloakUser({ key: user.id })
await keycloakUnAssignRole({ admin, uuid: createdUser.uuid, role: createdUser.role })
}
}
35 changes: 34 additions & 1 deletion tests/e2e/support/environment/userManagement.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import { Group, User } from '../types'
import { dummyUserStore, dummyGroupStore, createdUserStore, createdGroupStore } from '../store'
import {
dummyUserStore,
dummyGroupStore,
createdUserStore,
createdGroupStore,
keycloakCreatedUser
} from '../store'

export class UsersEnvironment {
getUser({ key }: { key: string }): User {
Expand Down Expand Up @@ -91,4 +97,31 @@ export class UsersEnvironment {

return group
}

storeCreatedKeycloakUser({ user }: { user: User }): User {
if (keycloakCreatedUser.has(user.id)) {
throw new Error(`Keycloak user '${user.id}' already exists`)
}
keycloakCreatedUser.set(user.id, user)
return user
}

getCreatedKeycloakUser({ key }: { key: string }): User {
const userKey = key.toLowerCase()
if (!keycloakCreatedUser.has(userKey)) {
throw new Error(`Keycloak user with key '${userKey}' not found`)
}

return keycloakCreatedUser.get(userKey)
}

removeCreatedKeycloakUser({ key }: { key: string }): boolean {
const userKey = key.toLowerCase()

if (!keycloakCreatedUser.has(userKey)) {
throw new Error(`Keycloak user with key '${userKey}' not found`)
}

return keycloakCreatedUser.delete(userKey)
}
}
46 changes: 25 additions & 21 deletions tests/e2e/support/objects/app-admin-settings/users/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { Page } from '@playwright/test'
import { UsersEnvironment } from '../../../environment'
import * as po from './actions'
import { config } from '../../../../config'
import { getUserId } from '../../../api/graph'

export class Users {
#page: Page
Expand All @@ -11,22 +9,18 @@ export class Users {
this.#usersEnvironment = new UsersEnvironment()
this.#page = page
}
async getUUID({ key }: { key: string }): Promise<string> {
nabim777 marked this conversation as resolved.
Show resolved Hide resolved
if (config.keycloak) {
const user = this.#usersEnvironment.getUser({ key })
const admin = this.#usersEnvironment.getUser({ key: 'admin' })
return await getUserId({ user, admin })
} else {
return this.#usersEnvironment.getCreatedUser({ key }).uuid
}

getUUID({ key }: { key: string }): string {
return this.#usersEnvironment.getCreatedUser({ key }).uuid
}

async allowLogin({ key, action }: { key: string; action: string }): Promise<void> {
const uuid = await this.getUUID({ key })
const uuid = this.getUUID({ key })
await po.openEditPanel({ page: this.#page, uuid, action })
await po.changeAccountEnabled({ uuid, value: true, page: this.#page })
}
async forbidLogin({ key, action }: { key: string; action: string }): Promise<void> {
const uuid = await this.getUUID({ key })
const uuid = this.getUUID({ key })
await po.openEditPanel({ page: this.#page, uuid, action })
await po.changeAccountEnabled({ uuid, value: false, page: this.#page })
}
Expand All @@ -39,13 +33,13 @@ export class Users {
value: string
action: string
}): Promise<void> {
const uuid = await this.getUUID({ key })
const uuid = this.getUUID({ key })
await po.openEditPanel({ page: this.#page, uuid, action })
await po.changeQuota({ uuid, value, page: this.#page })
}

async selectUser({ key }: { key: string }): Promise<void> {
const uuid = await this.getUUID({ key })
const uuid = this.getUUID({ key })
await po.selectUser({ page: this.#page, uuid })
}
async changeQuotaUsingBatchAction({
Expand All @@ -57,15 +51,18 @@ export class Users {
}): Promise<void> {
const userIds = []
for (const user of users) {
userIds.push(await this.getUUID({ key: user }))
userIds.push(this.getUUID({ key: user }))
}
await po.changeQuotaUsingBatchAction({ page: this.#page, value, userIds })
}
getDisplayedUsers(): Promise<string[]> {
return po.getDisplayedUsers({ page: this.#page })
}
async select({ key }: { key: string }): Promise<void> {
await po.selectUser({ page: this.#page, uuid: await this.getUUID({ key }) })
await po.selectUser({
page: this.#page,
uuid: this.getUUID({ key })
})
}
async addToGroupsBatchAtion({
userIds,
Expand Down Expand Up @@ -99,7 +96,7 @@ export class Users {
value: string
action: string
}): Promise<void> {
const uuid = await this.getUUID({ key })
const uuid = this.getUUID({ key })

await po.openEditPanel({ page: this.#page, uuid, action })
await po.changeUser({ uuid, attribute: attribute, value: value, page: this.#page })
Expand All @@ -122,7 +119,7 @@ export class Users {
groups: string[]
action: string
}): Promise<void> {
const uuid = await this.getUUID({ key })
const uuid = this.getUUID({ key })
await po.openEditPanel({ page: this.#page, uuid, action })
await po.addUserToGroups({ page: this.#page, userId: uuid, groups })
}
Expand All @@ -135,12 +132,15 @@ export class Users {
groups: string[]
action: string
}): Promise<void> {
const uuid = await this.getUUID({ key })
const uuid = this.getUUID({ key })
await po.openEditPanel({ page: this.#page, uuid, action })
await po.removeUserFromGroups({ page: this.#page, userId: uuid, groups })
}
async deleteUserUsingContextMenu({ key }: { key: string }): Promise<void> {
await po.deleteUserUsingContextMenu({ page: this.#page, uuid: await this.getUUID({ key }) })
await po.deleteUserUsingContextMenu({
page: this.#page,
uuid: this.getUUID({ key })
})
}
async deleteUserUsingBatchAction({ userIds }: { userIds: string[] }): Promise<void> {
await po.deleteUserUsingBatchAction({ page: this.#page, userIds })
Expand Down Expand Up @@ -171,7 +171,11 @@ export class Users {
}

async openEditPanel({ key, action }: { key: string; action: string }): Promise<void> {
await po.openEditPanel({ page: this.#page, uuid: await this.getUUID({ key }), action })
await po.openEditPanel({
page: this.#page,
uuid: this.getUUID({ key }),
action
})
}

async waitForEditPanelToBeVisible(): Promise<void> {
Expand Down
2 changes: 1 addition & 1 deletion tests/e2e/support/store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ export { createdSpaceStore } from './space'
export { dummyUserStore, createdUserStore } from './user'
export { dummyGroupStore, createdGroupStore } from './group'
export { userRoleStore } from './role'
export { keycloakRealmRoles } from './keycloak'
export { keycloakRealmRoles, keycloakCreatedUser } from './keycloak'
3 changes: 2 additions & 1 deletion tests/e2e/support/store/keycloak.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { KeycloakRealmRole } from '../types'
import { KeycloakRealmRole, User } from '../types'

export const keycloakRealmRoles = new Map<string, KeycloakRealmRole>()
export const keycloakCreatedUser = new Map<string, User>()