Skip to content

feat: add tests for the search #73

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

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added packages/k6-tests/data/test1.docx
Binary file not shown.
109 changes: 109 additions & 0 deletions packages/k6-tests/tests/oc/upload-search/default.k6.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import { ENV, queryJson, queryXml, randomString, store, check } from '@ownclouders/k6-tdk/lib/utils'
import { Permission, ShareType } from '@ownclouders/k6-tdk/lib/values'
import { randomBytes } from 'k6/crypto'
import exec from 'k6/execution'
import { Options } from 'k6/options'
import { sleep } from 'k6'
import { times } from 'lodash'

import { clientFor } from '@/shortcuts'
import { envValues } from '@/values'

// eslint-disable-next-line no-restricted-globals
const t1docX = open('../data/test1.docx', 'b')

export interface Environment {
adminData: {
adminRoot: string;
};
actorData: {
actorLogin: string;
actorPassword: string;
actorRoot: string;
}[];
}

/**/
export const settings = {
...envValues(),
sleepTime: parseInt(ENV('SLEEP_TIME', '10'), 10)
}
/**/

export const options: Options = {
vus: 1,
insecureSkipTLSVerify: true,
setupTimeout: '3m'
}

export function setup(): Environment {
const adminClient = clientFor({ userLogin: settings.admin.login, userPassword: settings.admin.password })
const getMyDrivesResponseAdmin = adminClient.me.getMyDrives({ params: { $filter: "driveType eq 'personal'" } })
const [adminRoot = settings.admin.login] = queryJson("$.value[?(@.driveType === 'personal')].id", getMyDrivesResponseAdmin?.body)

adminClient.resource.createResource({ root: adminRoot, resourcePath: settings.testFolder })

const actorData = times(options.vus || 1, () => {
const [actorLogin, actorPassword] = [randomString(), randomString()]
adminClient.user.createUser({ userLogin: actorLogin, userPassword: actorPassword })
adminClient.user.enableUser({ userLogin: actorLogin })

const actorClient = clientFor({ userLogin: actorLogin, userPassword: actorPassword })
const getMyDrivesResponseActor = actorClient.me.getMyDrives({ params: { $filter: "driveType eq 'personal'" } })
const [actorRoot = actorLogin] = queryJson("$.value[?(@.driveType === 'personal')].id", getMyDrivesResponseActor?.body)

actorClient.resource.createResource({ root: actorRoot, resourcePath: "initial" })

actorClient.resource.uploadResource({
root: actorRoot,
resourcePath: ["initial", "file.docx"].join('/'),
resourceBytes: t1docX
})

return {
actorLogin,
actorPassword,
actorRoot
}
})

// give time for the search extractor to index the file
sleep(settings.sleepTime)

return {
adminData: {
adminRoot
},
actorData
}
}


export default async function actor({ actorData }: Environment): Promise<void> {
const { actorLogin, actorPassword, actorRoot } = actorData[exec.vu.idInTest - 1]
const actorStore = store(actorLogin)

const actorClient = await actorStore.setOrGet('client', async () => {
return clientFor({ userLogin: actorLogin, userPassword: actorPassword })
})

const resp = actorClient.search.searchForResources({
root: actorRoot,
searchQuery: "(name:\"*automatically*\" OR content:\"automatically\")",
})
check({val: resp}, {
'search -> only one result found': ({ body }) => {
const props = queryXml("$..['d:prop']", body)
return props.length === 1 && props[0]['oc:name'] === 'file.docx'
},
})
}

export function teardown({ adminData, actorData }: Environment): void {
const adminClient = clientFor({ userLogin: settings.admin.login, userPassword: settings.admin.password })

adminClient.resource.deleteResource({ root: adminData.adminRoot, resourcePath: settings.testFolder })
actorData.forEach(({ actorLogin }) => {
adminClient.user.deleteUser({ userLogin: actorLogin })
})
}
36 changes: 36 additions & 0 deletions packages/k6-tests/tests/oc/upload-search/default.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Description

The `upload search` test mimics a typical end user resource search scenario.

Each user uploads a file and searches a particular word in that file.

**NOTE**: A search extractor is required to be configured in the oCIS instance in order to extract the word from the file, otherwise the search won't find the word and the test will fail.


## Procedure

* `admin` creates `N` users.
* `N` can be set with the `--vus` option.
* by default, it set to 1.
* each `user` logs into the system individually.
* each `user` uploads a particular file containing the `automatically` word to the `initial/file.docx` path. This happens during the setup phase.
* each `user` searches for the `automatically` word inside his root folder.
* `admin` deletes the created users.

Note that the setup phase will wait for 10 seconds (configurable) to ensure that the file is uploaded and indexed before the search is executed.

The iterations are shared among the users, so if you define `--iterations 5` and `--vus 2`, the test will run 5 times in total, within the 2 users running in parallel.
In other words, 2 users will run the tests in parallel until the 5 iterations are completed.


## Available options

* [Shared options](/k6-tests/src/values/env)
* `SLEEP_TIME`: time to wait after the setup to allow indexing the file. Not giving enough time can cause the tests to fail.
* default value: `10` (seconds)
* `export SLEEP_TIME=12`


## How to run the test

please read [here](/k6-tests/docs/run) how the test can be executed, only the script is different
106 changes: 106 additions & 0 deletions packages/k6-tests/tests/oc/upload-search/indexing.k6.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import { ENV, queryJson, queryXml, randomString, store, check } from '@ownclouders/k6-tdk/lib/utils'
import { Permission, ShareType } from '@ownclouders/k6-tdk/lib/values'
import { randomBytes } from 'k6/crypto'
import exec from 'k6/execution'
import { Options } from 'k6/options'
import { sleep } from 'k6'
import { times } from 'lodash'

import { clientFor } from '@/shortcuts'
import { envValues } from '@/values'

// eslint-disable-next-line no-restricted-globals
const t1docX = open('../data/test1.docx', 'b')

export interface Environment {
adminData: {
adminRoot: string;
};
actorData: {
actorLogin: string;
actorPassword: string;
actorRoot: string;
}[];
}

/**/
export const settings = {
...envValues(),
}
/**/

export const options: Options = {
vus: 1,
insecureSkipTLSVerify: true,
}

export function setup(): Environment {
const adminClient = clientFor({ userLogin: settings.admin.login, userPassword: settings.admin.password })
const getMyDrivesResponseAdmin = adminClient.me.getMyDrives({ params: { $filter: "driveType eq 'personal'" } })
const [adminRoot = settings.admin.login] = queryJson("$.value[?(@.driveType === 'personal')].id", getMyDrivesResponseAdmin?.body)

adminClient.resource.createResource({ root: adminRoot, resourcePath: settings.testFolder })

const actorData = times(options.vus || 1, () => {
const [actorLogin, actorPassword] = [randomString(), randomString()]
adminClient.user.createUser({ userLogin: actorLogin, userPassword: actorPassword })
adminClient.user.enableUser({ userLogin: actorLogin })

const actorClient = clientFor({ userLogin: actorLogin, userPassword: actorPassword })
const getMyDrivesResponseActor = actorClient.me.getMyDrives({ params: { $filter: "driveType eq 'personal'" } })
const [actorRoot = actorLogin] = queryJson("$.value[?(@.driveType === 'personal')].id", getMyDrivesResponseActor?.body)

actorClient.resource.createResource({ root: actorRoot, resourcePath: "initial" })

return {
actorLogin,
actorPassword,
actorRoot
}
})

return {
adminData: {
adminRoot
},
actorData
}
}


export default async function actor({ actorData }: Environment): Promise<void> {
const { actorLogin, actorPassword, actorRoot } = actorData[exec.vu.idInTest - 1]
const actorStore = store(actorLogin)

const actorClient = await actorStore.setOrGet('client', async () => {
return clientFor({ userLogin: actorLogin, userPassword: actorPassword })
})


const filename = [randomString(), exec.scenario.iterationInTest, '.docx'].join('')
actorClient.resource.uploadResource({
root: actorRoot,
resourcePath: ["initial", filename].join('/'),
resourceBytes: t1docX
})

// We're focused on response times so we don't care about the result, just the status code.
// No need to wait for indexing.

const resp = actorClient.search.searchForResources({
root: actorRoot,
searchQuery: `(name:\"*${filename}*\" OR content:\"${filename}\")`,
})
check({val: resp}, {
'search -> status': ({ status }) => status === 207,
})
}

export function teardown({ adminData, actorData }: Environment): void {
const adminClient = clientFor({ userLogin: settings.admin.login, userPassword: settings.admin.password })

adminClient.resource.deleteResource({ root: adminData.adminRoot, resourcePath: settings.testFolder })
actorData.forEach(({ actorLogin }) => {
adminClient.user.deleteUser({ userLogin: actorLogin })
})
}
31 changes: 31 additions & 0 deletions packages/k6-tests/tests/oc/upload-search/indexing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Description

The `upload search` test mimics a typical end user resource search scenario.

While the `default` test just focuses on searching, this test also includes the upload part. The test will just upload a file and search it, but it will only check the status code of the search request. This means that the search will likely will return empty results (not indexed yet) and the test will pass.

The test is expected to perform worse than the `default` test, as it includes the upload part. There are also additional write locks on the index, due to the indexing operation, that are expected to slow down the test. Note that we won't wait for the indexing to finish in order to send the search request.


## Procedure

* `admin` creates `N` users.
* `N` can be set with the `--vus` option.
* by default, it set to 1.
* each `user` logs into the system individually.
* each `user` uploads a particular file in the `initial` folder. The file is uploaded with a random name.
* each `user` searches for the filename inside his root folder.
* `admin` deletes the created users.

The iterations are shared among the users, so if you define `--iterations 5` and `--vus 2`, the test will run 5 times in total, within the 2 users running in parallel.
In other words, 2 users will run the tests in parallel until the 5 iterations are completed.


## Available options

* [Shared options](/k6-tests/src/values/env)


## How to run the test

please read [here](/k6-tests/docs/run) how the test can be executed, only the script is different