-
Notifications
You must be signed in to change notification settings - Fork 32
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Plugin E2E: Interact with Grafana http api on behalf of logged in user (
#965)
- Loading branch information
Showing
12 changed files
with
152 additions
and
72 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,61 +1,13 @@ | ||
import { APIRequestContext, expect, TestFixture } from '@playwright/test'; | ||
import { PlaywrightArgs, User } from '../../types'; | ||
import { TestFixture } from '@playwright/test'; | ||
import { PlaywrightArgs } from '../../types'; | ||
|
||
type CreateUserFixture = TestFixture<() => Promise<void>, PlaywrightArgs>; | ||
|
||
const getHeaders = (user: User) => ({ | ||
Authorization: `Basic ${Buffer.from(`${user.user}:${user.password}`).toString('base64')}`, | ||
}); | ||
|
||
const getUserIdByUsername = async ( | ||
request: APIRequestContext, | ||
userName: string, | ||
grafanaAPIUser: User | ||
): Promise<number> => { | ||
const getUserIdByUserNameReq = await request.get(`/api/users/lookup?loginOrEmail=${userName}`, { | ||
headers: getHeaders(grafanaAPIUser), | ||
}); | ||
expect(getUserIdByUserNameReq.ok()).toBeTruthy(); | ||
const json = await getUserIdByUserNameReq.json(); | ||
return json.id; | ||
}; | ||
|
||
export const createUser: CreateUserFixture = async ({ request, user, grafanaAPICredentials }, use) => { | ||
export const createUser: CreateUserFixture = async ({ grafanaAPIClient, user }, use) => { | ||
await use(async () => { | ||
if (!user) { | ||
throw new Error('Playwright option `User` was not provided'); | ||
} | ||
|
||
const createUserReq = await request.post(`/api/admin/users`, { | ||
data: { | ||
name: user?.user, | ||
login: user?.user, | ||
password: user?.password, | ||
}, | ||
headers: getHeaders(grafanaAPICredentials), | ||
}); | ||
|
||
let userId: number | undefined; | ||
if (createUserReq.ok()) { | ||
const respJson = await createUserReq.json(); | ||
userId = respJson.id; | ||
} else if (createUserReq.status() === 412) { | ||
// user already exists | ||
userId = await getUserIdByUsername(request, user?.user, grafanaAPICredentials); | ||
} else { | ||
throw new Error(`Could not create user '${user?.user}': ${await createUserReq.text()}`); | ||
} | ||
|
||
if (user.role) { | ||
const updateRoleReq = await request.patch(`/api/org/users/${userId}`, { | ||
data: { role: user.role }, | ||
headers: getHeaders(grafanaAPICredentials), | ||
}); | ||
const updateRoleReqText = await updateRoleReq.text(); | ||
expect( | ||
updateRoleReq.ok(), | ||
`Could not assign role '${user.role}' to user '${user.user}': ${updateRoleReqText}` | ||
).toBeTruthy(); | ||
} | ||
await grafanaAPIClient.createUser(user); | ||
}); | ||
}; |
18 changes: 3 additions & 15 deletions
18
packages/plugin-e2e/src/fixtures/commands/gotoDataSourceConfigPage.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import path from 'path'; | ||
import { TestFixture, expect, APIRequestContext } from '@playwright/test'; | ||
import { PlaywrightArgs, User } from '../types'; | ||
import { GrafanaAPIClient } from '../models/GrafanaAPIClient'; | ||
|
||
type GrafanaAPIClientFixture = TestFixture<GrafanaAPIClient, PlaywrightArgs>; | ||
|
||
const adminClientStorageState = path.join(process.cwd(), `playwright/.auth/grafanaAPICredentials.json`); | ||
|
||
export const createAdminClientStorageState = async (request: APIRequestContext, grafanaAPICredentials: User) => { | ||
const loginReq = await request.post('/login', { data: grafanaAPICredentials }); | ||
const text = await loginReq.text(); | ||
await expect.soft(loginReq.ok(), `Could not log in to Grafana: ${text}`).toBeTruthy(); | ||
await request.storageState({ path: adminClientStorageState }); | ||
}; | ||
|
||
export const grafanaAPIClient: GrafanaAPIClientFixture = async ({ browser, grafanaAPICredentials }, use) => { | ||
const context = await browser.newContext({ storageState: undefined }); | ||
const loginReq = await context.request.post('/login', { data: grafanaAPICredentials }); | ||
if (!loginReq.ok()) { | ||
console.log( | ||
`Could not login to grafana using credentials '${ | ||
grafanaAPICredentials?.user | ||
}'. Find information on how user can be managed in the plugin-e2e docs: https://grafana.com/developers/plugin-tools/e2e-test-a-plugin/use-authentication#managing-users : ${await loginReq.text()}` | ||
); | ||
} | ||
await context.request.storageState({ path: adminClientStorageState }); | ||
await use(new GrafanaAPIClient(context.request)); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import { APIRequestContext } from '@playwright/test'; | ||
import { DataSourceSettings, User } from '../types'; | ||
|
||
export class GrafanaAPIClient { | ||
constructor(private request: APIRequestContext) {} | ||
|
||
async getUserIdByUsername(userName: string) { | ||
const getUserIdByUserNameReq = await this.request.get(`/api/users/lookup?loginOrEmail=${userName}`); | ||
const json = await getUserIdByUserNameReq.json(); | ||
return json.id; | ||
} | ||
|
||
async createUser(user: User) { | ||
const createUserReq = await this.request.post(`/api/admin/users`, { | ||
data: { | ||
name: user?.user, | ||
login: user?.user, | ||
password: user?.password, | ||
}, | ||
}); | ||
let userId: number | undefined; | ||
if (createUserReq.ok()) { | ||
const respJson = await createUserReq.json(); | ||
userId = respJson.id; | ||
} else if (createUserReq.status() === 412) { | ||
// user already exists | ||
userId = await this.getUserIdByUsername(user?.user); | ||
} else { | ||
throw new Error( | ||
`Could not create user '${ | ||
user?.user | ||
}'. Find information on how user can be managed in the plugin-e2e docs: https://grafana.com/developers/plugin-tools/e2e-test-a-plugin/use-authentication#managing-users : ${await createUserReq.text()}` | ||
); | ||
} | ||
|
||
if (user.role) { | ||
const updateRoleReq = await this.request.patch(`/api/org/users/${userId}`, { | ||
data: { role: user.role }, | ||
}); | ||
if (!updateRoleReq.ok()) { | ||
throw new Error(`Could not assign role '${user.role}' to user '${user.user}': ${await updateRoleReq.text()}`); | ||
} | ||
} | ||
} | ||
|
||
async getDataSourceSettingsByUID(uid: string) { | ||
const response = await this.request.get(`/api/datasources/uid/${uid}`); | ||
if (!response.ok()) { | ||
throw new Error( | ||
`Failed to get datasource by uid: ${response.statusText()}. If you're using a provisioned data source, make sure it has a UID` | ||
); | ||
} | ||
const settings: DataSourceSettings = await response.json(); | ||
return settings; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
8 changes: 8 additions & 0 deletions
8
...ages/plugin-e2e/tests/as-admin-user/permissions/createUserUsingInvalidCredentials.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { expect, test } from '../../../src'; | ||
|
||
test.use({ grafanaAPICredentials: { user: 'test', password: 'test' } }); | ||
test('should throw error when credentials are invalid', async ({ grafanaAPIClient }) => { | ||
await expect(grafanaAPIClient.createUser({ user: 'testuser1', password: 'pass' })).rejects.toThrowError( | ||
/Could not create user 'testuser1'.*/ | ||
); | ||
}); |
6 changes: 6 additions & 0 deletions
6
packages/plugin-e2e/tests/as-admin-user/permissions/createUserUsingValidCredentials.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import { expect, test } from '../../../src'; | ||
|
||
test('should be possible to create user when credentials are valid', async ({ grafanaAPIClient }) => { | ||
await expect(grafanaAPIClient.createUser({ user: 'testuser1', password: 'pass' })).resolves.toBeUndefined(); | ||
await expect(await grafanaAPIClient.getUserIdByUsername('testuser1')).toBeTruthy(); | ||
}); |
8 changes: 8 additions & 0 deletions
8
...ges/plugin-e2e/tests/as-viewer-user/permissions/createUserUsingInvalidCredentials.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { expect, test } from '../../../src'; | ||
|
||
test.use({ grafanaAPICredentials: { user: 'test', password: 'test' } }); | ||
test('should throw error when credentials are invalid', async ({ grafanaAPIClient }) => { | ||
await expect(grafanaAPIClient.createUser({ user: 'testuser1', password: 'pass' })).rejects.toThrowError( | ||
/Could not create user 'testuser1'.*/ | ||
); | ||
}); |
16 changes: 16 additions & 0 deletions
16
packages/plugin-e2e/tests/as-viewer-user/permissions/createUserUsingValidCredentials.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { expect, test } from '../../../src'; | ||
|
||
test('using grafanaAPIClient should not change storage state for logged in user', async ({ | ||
grafanaAPIClient, | ||
page, | ||
}) => { | ||
// assert one can create user on behalf of the admin credentials | ||
await expect(grafanaAPIClient.createUser({ user: 'testuser1', password: 'pass' })).resolves.toBeUndefined(); | ||
await expect(await grafanaAPIClient.getUserIdByUsername('testuser1')).toBeTruthy(); | ||
|
||
// but logged in user should still only have viewer persmissions | ||
await page.goto('/'); | ||
const homePageTitle = await page.title(); | ||
await page.goto('/datasources', { waitUntil: 'networkidle' }); | ||
expect(await page.title()).toEqual(homePageTitle); | ||
}); |