mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-02-05 03:30:19 -06:00
add linting
add prettier add concurrent users upload test add api and play for users remove some code smell
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -11,7 +11,7 @@ node_modules/
|
||||
|
||||
.idea
|
||||
|
||||
*/yarn-error.log
|
||||
yarn-error.log
|
||||
|
||||
# Konnectd
|
||||
konnectd/assets/identifier
|
||||
|
||||
@@ -53,4 +53,5 @@ replace (
|
||||
github.com/owncloud/ocis/thumbnails => ../thumbnails
|
||||
github.com/owncloud/ocis/webdav => ../webdav
|
||||
google.golang.org/grpc => google.golang.org/grpc v1.26.0
|
||||
github.com/cs3org/reva => ../../../cs3org/reva
|
||||
)
|
||||
|
||||
2
tests/k6/.eslintignore
Normal file
2
tests/k6/.eslintignore
Normal file
@@ -0,0 +1,2 @@
|
||||
node_modules
|
||||
dist
|
||||
14
tests/k6/.eslintrc
Normal file
14
tests/k6/.eslintrc
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2020,
|
||||
"sourceType": "module"
|
||||
},
|
||||
"extends": [
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"prettier/@typescript-eslint",
|
||||
"plugin:prettier/recommended"
|
||||
],
|
||||
"rules": {
|
||||
}
|
||||
}
|
||||
7
tests/k6/.prettierrc
Normal file
7
tests/k6/.prettierrc
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"semi": true,
|
||||
"trailingComma": "all",
|
||||
"singleQuote": true,
|
||||
"printWidth": 120,
|
||||
"tabWidth": 4
|
||||
}
|
||||
@@ -4,9 +4,20 @@
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"clean": "rm -rf ./dist",
|
||||
"lint": "eslint './src/**/*.ts' --fix",
|
||||
"build": "rollup -c",
|
||||
"build:w": "rollup -c -w"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "lint-staged"
|
||||
}
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{ts}": [
|
||||
"eslint --fix"
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.9.0",
|
||||
"@babel/polyfill": "^7.12.1",
|
||||
@@ -18,26 +29,26 @@
|
||||
"@rollup/plugin-json": "^4.0.3",
|
||||
"@rollup/plugin-node-resolve": "^7.1.3",
|
||||
"@rollup/pluginutils": "^4.1.0",
|
||||
"@types/faker": "^5.1.4",
|
||||
"@types/jest": "^25.2.1",
|
||||
"@types/k6": "^0.28.2",
|
||||
"@types/lodash": "^4.14.165",
|
||||
"@typescript-eslint/eslint-plugin": "^2.29.0",
|
||||
"@typescript-eslint/parser": "^2.29.0",
|
||||
"@typescript-eslint/eslint-plugin": "^4.9.0",
|
||||
"@typescript-eslint/parser": "^4.9.0",
|
||||
"babel-plugin-lodash": "^3.3.4",
|
||||
"eslint": "^6.8.0",
|
||||
"eslint-config-prettier": "^6.11.0",
|
||||
"eslint": "^7.14.0",
|
||||
"eslint-config-prettier": "^6.15.0",
|
||||
"eslint-plugin-jest": "^23.8.2",
|
||||
"eslint-plugin-prettier": "^3.1.3",
|
||||
"eslint-plugin-prettier": "^3.2.0",
|
||||
"husky": "^4.3.0",
|
||||
"jest": "^25.4.0",
|
||||
"k6": "^0.0.0",
|
||||
"lint-staged": "^10.1.7",
|
||||
"prettier": "^2.0.5",
|
||||
"prettier": "^2.2.1",
|
||||
"prettier-eslint": "^12.0.0",
|
||||
"rollup": "^2.7.2",
|
||||
"rollup-plugin-babel": "^4.4.0",
|
||||
"rollup-plugin-multi-input": "^1.1.1",
|
||||
"rollup-plugin-terser": "^5.3.0",
|
||||
"typescript": "^3.8.3"
|
||||
"typescript": "^4.1.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"lodash": "^4.17.20",
|
||||
|
||||
@@ -1,41 +1,52 @@
|
||||
import encoding from 'k6/encoding';
|
||||
import * as types from '../types';
|
||||
import * as defaults from "../defaults";
|
||||
import {merge} from 'lodash';
|
||||
import http, {RefinedParams, RefinedResponse, RequestBody, ResponseType} from "k6/http";
|
||||
import * as defaults from '../defaults';
|
||||
import { merge } from 'lodash';
|
||||
import http, { RefinedParams, RefinedResponse, RequestBody, ResponseType } from 'k6/http';
|
||||
import { bytes } from 'k6';
|
||||
|
||||
export const buildHeaders = ({credential}: { credential: types.Credential }): { [key: string]: string } => {
|
||||
export const buildHeaders = ({ credential }: { credential?: types.Credential }): { [key: string]: string } => {
|
||||
const isOIDCGuard = (credential as types.Token).tokenType !== undefined;
|
||||
const authOIDC = credential as types.Token;
|
||||
const authBasic = credential as types.Account;
|
||||
|
||||
return {
|
||||
Authorization: isOIDCGuard ? `${authOIDC.tokenType} ${authOIDC.accessToken}` : `Basic ${encoding.b64encode(`${authBasic.login}:${authBasic.password}`)}`,
|
||||
}
|
||||
}
|
||||
...(credential && {
|
||||
Authorization: isOIDCGuard
|
||||
? `${authOIDC.tokenType} ${authOIDC.accessToken}`
|
||||
: `Basic ${encoding.b64encode(`${authBasic.login}:${authBasic.password}`)}`,
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
||||
export const buildURL = ({path}: { path: string }): string => {
|
||||
return [
|
||||
defaults.ENV.HOST,
|
||||
...path.split('/').filter(Boolean)
|
||||
].join('/')
|
||||
}
|
||||
export const buildURL = ({ path }: { path: string }): string => {
|
||||
return [defaults.ENV.HOST, ...path.split('/').filter(Boolean)].join('/');
|
||||
};
|
||||
|
||||
export const request = ({method, path, body = {}, params = {}, credential}: {
|
||||
method: 'PROPFIND' | 'PUT' | 'GET' | 'DELETE' | 'MKCOL',
|
||||
path: string,
|
||||
export const request = ({
|
||||
method,
|
||||
path,
|
||||
body = {},
|
||||
params = {},
|
||||
credential,
|
||||
}: {
|
||||
method: 'PROPFIND' | 'PUT' | 'GET' | 'POST' | 'DELETE' | 'MKCOL';
|
||||
path: string;
|
||||
credential: types.Credential;
|
||||
body?: RequestBody | null,
|
||||
params?: RefinedParams<ResponseType> | null
|
||||
body?: RequestBody | bytes | null;
|
||||
params?: RefinedParams<ResponseType> | null;
|
||||
}): RefinedResponse<ResponseType> => {
|
||||
return http.request(
|
||||
method,
|
||||
buildURL({path}),
|
||||
body,
|
||||
merge({
|
||||
headers: {
|
||||
...buildHeaders({credential})
|
||||
}
|
||||
}, params)
|
||||
buildURL({ path }),
|
||||
body as never,
|
||||
merge(
|
||||
{
|
||||
headers: {
|
||||
...buildHeaders({ credential }),
|
||||
},
|
||||
},
|
||||
params,
|
||||
),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,59 +1,111 @@
|
||||
import {RefinedResponse, ResponseType} from 'k6/http';
|
||||
import * as api from './api'
|
||||
import { RefinedResponse, ResponseType } from 'k6/http';
|
||||
import * as api from './api';
|
||||
import * as types from '../types';
|
||||
|
||||
export class Upload {
|
||||
public static exec({credential, userName, path = '', asset, tags}: {
|
||||
public static exec({
|
||||
credential,
|
||||
userName,
|
||||
path = '',
|
||||
asset,
|
||||
tags,
|
||||
}: {
|
||||
credential: types.Credential;
|
||||
userName: string;
|
||||
asset: types.Asset;
|
||||
path?: string;
|
||||
tags?: types.Tags;
|
||||
}): RefinedResponse<ResponseType> {
|
||||
return api.request({method: 'PUT', credential, path: `/remote.php/dav/files/${userName}/${path}/${asset.name}`, params: {tags}, body: asset.bytes as any})
|
||||
return api.request({
|
||||
method: 'PUT',
|
||||
credential,
|
||||
path: `/remote.php/dav/files/${userName}/${path}/${asset.name}`,
|
||||
params: { tags },
|
||||
body: asset.bytes,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class Download {
|
||||
public static exec({credential, userName, path, tags}: {
|
||||
public static exec({
|
||||
credential,
|
||||
userName,
|
||||
path,
|
||||
tags,
|
||||
}: {
|
||||
credential: types.Credential;
|
||||
userName: string;
|
||||
path: string;
|
||||
tags?: types.Tags;
|
||||
}): RefinedResponse<ResponseType> {
|
||||
return api.request({method: 'GET', credential, path: `/remote.php/dav/files/${userName}/${path}`, params: {tags}})
|
||||
return api.request({
|
||||
method: 'GET',
|
||||
credential,
|
||||
path: `/remote.php/dav/files/${userName}/${path}`,
|
||||
params: { tags },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class Delete {
|
||||
public static exec({credential, userName, path, tags}: {
|
||||
public static exec({
|
||||
credential,
|
||||
userName,
|
||||
path,
|
||||
tags,
|
||||
}: {
|
||||
credential: types.Credential;
|
||||
userName: string;
|
||||
path: string;
|
||||
tags?: types.Tags;
|
||||
}): RefinedResponse<ResponseType> {
|
||||
return api.request({method: 'DELETE', credential, path: `/remote.php/dav/files/${userName}/${path}`, params: {tags}})
|
||||
return api.request({
|
||||
method: 'DELETE',
|
||||
credential,
|
||||
path: `/remote.php/dav/files/${userName}/${path}`,
|
||||
params: { tags },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class Create {
|
||||
public static exec({credential, userName, path, tags}: {
|
||||
public static exec({
|
||||
credential,
|
||||
userName,
|
||||
path,
|
||||
tags,
|
||||
}: {
|
||||
credential: types.Credential;
|
||||
userName: string;
|
||||
path: string;
|
||||
tags?: types.Tags;
|
||||
}): RefinedResponse<ResponseType> {
|
||||
return api.request({method: 'MKCOL', credential, path: `/remote.php/dav/files/${userName}/${path}`, params: {tags}})
|
||||
return api.request({
|
||||
method: 'MKCOL',
|
||||
credential,
|
||||
path: `/remote.php/dav/files/${userName}/${path}`,
|
||||
params: { tags },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class Propfind {
|
||||
public static exec({credential, userName, path = '', tags}: {
|
||||
public static exec({
|
||||
credential,
|
||||
userName,
|
||||
path = '',
|
||||
tags,
|
||||
}: {
|
||||
credential: types.Credential;
|
||||
userName: string;
|
||||
path?: string;
|
||||
tags?: types.Tags;
|
||||
}): RefinedResponse<ResponseType> {
|
||||
return api.request({method: 'PROPFIND', credential, path: `/remote.php/dav/files/${userName}/${path}`, params: {tags}})
|
||||
return api.request({
|
||||
method: 'PROPFIND',
|
||||
credential,
|
||||
path: `/remote.php/dav/files/${userName}/${path}`,
|
||||
params: { tags },
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
export * as api from './api'
|
||||
export * as dav from './dav'
|
||||
export * as api from './api';
|
||||
export * as dav from './dav';
|
||||
export * as users from './users';
|
||||
|
||||
46
tests/k6/src/lib/api/users.ts
Normal file
46
tests/k6/src/lib/api/users.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { RefinedResponse, ResponseType } from 'k6/http';
|
||||
import * as api from './api';
|
||||
import * as types from '../types';
|
||||
|
||||
export class Create {
|
||||
public static exec({
|
||||
userName,
|
||||
password,
|
||||
email,
|
||||
credential,
|
||||
tags,
|
||||
}: {
|
||||
credential: types.Credential;
|
||||
userName: string;
|
||||
password: string;
|
||||
email: string;
|
||||
tags?: types.Tags;
|
||||
}): RefinedResponse<ResponseType> {
|
||||
return api.request({
|
||||
method: 'POST',
|
||||
credential,
|
||||
path: `/ocs/v1.php/cloud/users`,
|
||||
params: { tags },
|
||||
body: { userid: userName, password, email },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class Delete {
|
||||
public static exec({
|
||||
userName,
|
||||
credential,
|
||||
tags,
|
||||
}: {
|
||||
credential: types.Credential;
|
||||
userName: string;
|
||||
tags?: types.Tags;
|
||||
}): RefinedResponse<ResponseType> {
|
||||
return api.request({
|
||||
method: 'DELETE',
|
||||
credential,
|
||||
path: `/ocs/v1.php/cloud/users/${userName}`,
|
||||
params: { tags },
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,8 @@ import * as defaults from './defaults';
|
||||
import http from 'k6/http';
|
||||
import queryString from 'query-string';
|
||||
import * as types from './types';
|
||||
import {fail} from 'k6';
|
||||
import {get} from 'lodash'
|
||||
|
||||
import { fail } from 'k6';
|
||||
import { get } from 'lodash';
|
||||
|
||||
export default class Factory {
|
||||
private provider!: types.AuthProvider;
|
||||
@@ -15,14 +14,14 @@ export default class Factory {
|
||||
|
||||
if (defaults.ENV.OIDC_ENABLED) {
|
||||
this.provider = new OIDCProvider(account);
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
this.provider = new AccountProvider(account);
|
||||
}
|
||||
|
||||
public get credential(): types.Credential {
|
||||
return this.provider.credential
|
||||
return this.provider.credential;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +45,7 @@ class OIDCProvider implements types.AuthProvider {
|
||||
private cache!: {
|
||||
validTo: Date;
|
||||
token: types.Token;
|
||||
}
|
||||
};
|
||||
|
||||
constructor(account: types.Account) {
|
||||
this.account = account;
|
||||
@@ -63,12 +62,12 @@ class OIDCProvider implements types.AuthProvider {
|
||||
const offset = 5;
|
||||
const d = new Date();
|
||||
|
||||
d.setSeconds(d.getSeconds() + token.expiresIn - offset)
|
||||
d.setSeconds(d.getSeconds() + token.expiresIn - offset);
|
||||
|
||||
return d
|
||||
return d;
|
||||
})(),
|
||||
token,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return this.cache.token;
|
||||
@@ -77,18 +76,16 @@ class OIDCProvider implements types.AuthProvider {
|
||||
private getContinueURI(): string {
|
||||
const logonResponse = http.post(
|
||||
this.logonUri,
|
||||
JSON.stringify(
|
||||
{
|
||||
params: [this.account.login, this.account.password, '1'],
|
||||
hello: {
|
||||
scope: 'openid profile email',
|
||||
client_id: 'phoenix',
|
||||
redirect_uri: this.redirectUri,
|
||||
flow: 'oidc'
|
||||
},
|
||||
'state': 'vp42cf'
|
||||
JSON.stringify({
|
||||
params: [this.account.login, this.account.password, '1'],
|
||||
hello: {
|
||||
scope: 'openid profile email',
|
||||
client_id: 'phoenix',
|
||||
redirect_uri: this.redirectUri,
|
||||
flow: 'oidc',
|
||||
},
|
||||
),
|
||||
state: 'vp42cf',
|
||||
}),
|
||||
{
|
||||
headers: {
|
||||
'Kopano-Konnect-XSRF': '1',
|
||||
@@ -107,53 +104,49 @@ class OIDCProvider implements types.AuthProvider {
|
||||
}
|
||||
|
||||
private getCode(continueURI: string): string {
|
||||
const authorizeUri = `${continueURI}?${
|
||||
queryString.stringify(
|
||||
{
|
||||
client_id: 'phoenix',
|
||||
prompt: 'none',
|
||||
redirect_uri: this.redirectUri,
|
||||
response_mode: 'query',
|
||||
response_type: 'code',
|
||||
scope: 'openid profile email',
|
||||
},
|
||||
)
|
||||
}`;
|
||||
const authorizeResponse = http.get(
|
||||
authorizeUri,
|
||||
{
|
||||
redirects: 0,
|
||||
},
|
||||
)
|
||||
const authorizeUri = `${continueURI}?${queryString.stringify({
|
||||
client_id: 'phoenix',
|
||||
prompt: 'none',
|
||||
redirect_uri: this.redirectUri,
|
||||
response_mode: 'query',
|
||||
response_type: 'code',
|
||||
scope: 'openid profile email',
|
||||
})}`;
|
||||
const authorizeResponse = http.get(authorizeUri, {
|
||||
redirects: 0,
|
||||
});
|
||||
|
||||
const code = get(queryString.parseUrl(authorizeResponse.headers.Location), 'query.code')
|
||||
const code = get(queryString.parseUrl(authorizeResponse.headers.Location), 'query.code');
|
||||
|
||||
if (authorizeResponse.status != 302 || !code) {
|
||||
fail(continueURI);
|
||||
}
|
||||
|
||||
return code
|
||||
return code;
|
||||
}
|
||||
|
||||
private getToken(code: string): types.Token {
|
||||
const tokenResponse = http.post(
|
||||
this.tokenUrl,
|
||||
{
|
||||
client_id: 'phoenix',
|
||||
code,
|
||||
redirect_uri: this.redirectUri,
|
||||
grant_type: 'authorization_code'
|
||||
}
|
||||
)
|
||||
const tokenResponse = http.post(this.tokenUrl, {
|
||||
client_id: 'phoenix',
|
||||
code,
|
||||
redirect_uri: this.redirectUri,
|
||||
grant_type: 'authorization_code',
|
||||
});
|
||||
|
||||
const token = {
|
||||
accessToken: get(tokenResponse.json(), 'access_token'),
|
||||
tokenType: get(tokenResponse.json(), 'token_type'),
|
||||
idToken: get(tokenResponse.json(), 'id_token'),
|
||||
expiresIn: get(tokenResponse.json(), 'expires_in'),
|
||||
}
|
||||
};
|
||||
|
||||
if (tokenResponse.status != 200 || !token.accessToken || !token.tokenType || !token.idToken || !token.expiresIn) {
|
||||
if (
|
||||
tokenResponse.status != 200 ||
|
||||
!token.accessToken ||
|
||||
!token.tokenType ||
|
||||
!token.idToken ||
|
||||
!token.expiresIn
|
||||
) {
|
||||
fail(this.tokenUrl);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,9 +9,14 @@ export class ENV {
|
||||
}
|
||||
|
||||
export class ACCOUNTS {
|
||||
public static readonly ADMIN = 'admin';
|
||||
public static readonly EINSTEIN = 'einstein';
|
||||
public static readonly RICHARD = 'richard';
|
||||
public static readonly ALL: { [key: string]: types.Account; } = {
|
||||
public static readonly ALL: { [key: string]: types.Account } = {
|
||||
admin: {
|
||||
login: 'admin',
|
||||
password: 'admin',
|
||||
},
|
||||
einstein: {
|
||||
login: 'einstein',
|
||||
password: 'relativity',
|
||||
@@ -20,5 +25,5 @@ export class ACCOUNTS {
|
||||
login: 'richard',
|
||||
password: 'superfluidity',
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export * as api from './api'
|
||||
export * as playbook from './playbook'
|
||||
export * as auth from './auth'
|
||||
export * as defaults from './defaults'
|
||||
export * as types from './types'
|
||||
export * as utils from './utils'
|
||||
export * as api from './api';
|
||||
export * as playbook from './playbook';
|
||||
export * as auth from './auth';
|
||||
export * as defaults from './defaults';
|
||||
export * as types from './types';
|
||||
export * as utils from './utils';
|
||||
|
||||
@@ -1,141 +1,177 @@
|
||||
import * as api from '../api';
|
||||
import {check} from 'k6';
|
||||
import { check } from 'k6';
|
||||
import * as types from '../types';
|
||||
import {RefinedResponse, ResponseType} from 'k6/http';
|
||||
import {Play} from "./playbook";
|
||||
import { RefinedResponse, ResponseType } from 'k6/http';
|
||||
import { Play } from './playbook';
|
||||
|
||||
export class Upload extends Play {
|
||||
constructor({name, metricID = 'default'}: { name?: string; metricID?: string; }) {
|
||||
super({name: name || `oc_${metricID}_play_dav_upload`});
|
||||
constructor({ name, metricID = 'default' }: { name?: string; metricID?: string } = {}) {
|
||||
super({ name: name || `oc_${metricID}_play_dav_upload` });
|
||||
}
|
||||
|
||||
public exec(
|
||||
{credential, userName, path, asset, tags}: {
|
||||
credential: types.Credential;
|
||||
path?: string;
|
||||
userName: string;
|
||||
asset: types.Asset;
|
||||
tags?: types.Tags;
|
||||
}
|
||||
): { response: RefinedResponse<ResponseType>; tags: types.Tags; } {
|
||||
tags = {...this.tags, ...tags};
|
||||
public exec({
|
||||
credential,
|
||||
userName,
|
||||
path,
|
||||
asset,
|
||||
tags,
|
||||
}: {
|
||||
credential: types.Credential;
|
||||
path?: string;
|
||||
userName: string;
|
||||
asset: types.Asset;
|
||||
tags?: types.Tags;
|
||||
}): { response: RefinedResponse<ResponseType>; tags: types.Tags } {
|
||||
tags = { ...this.tags, ...tags };
|
||||
|
||||
const response = api.dav.Upload.exec({credential: credential as types.Credential, asset, userName, tags, path});
|
||||
const response = api.dav.Upload.exec({ credential: credential, asset, userName, tags, path });
|
||||
|
||||
check(response, {
|
||||
'upload status is 201': () => response.status === 201,
|
||||
}, tags) || this.metricErrorRate.add(1, tags);
|
||||
check(
|
||||
response,
|
||||
{
|
||||
'dav upload status is 201': () => response.status === 201,
|
||||
},
|
||||
tags,
|
||||
) || this.metricErrorRate.add(1, tags);
|
||||
|
||||
this.metricTrend.add(response.timings.duration, tags)
|
||||
this.metricTrend.add(response.timings.duration, tags);
|
||||
|
||||
return {response, tags}
|
||||
return { response, tags };
|
||||
}
|
||||
}
|
||||
|
||||
export class Delete extends Play {
|
||||
constructor({name, metricID = 'default'}: { name?: string; metricID?: string; }) {
|
||||
super({name: name || `oc_${metricID}_play_dav_delete`});
|
||||
constructor({ name, metricID = 'default' }: { name?: string; metricID?: string } = {}) {
|
||||
super({ name: name || `oc_${metricID}_play_dav_delete` });
|
||||
}
|
||||
|
||||
public exec(
|
||||
{credential, userName, path, tags}: {
|
||||
credential: types.Credential;
|
||||
path: string;
|
||||
userName: string;
|
||||
tags?: types.Tags;
|
||||
}
|
||||
): { response: RefinedResponse<ResponseType>; tags: types.Tags; } {
|
||||
tags = {...this.tags, ...tags};
|
||||
public exec({
|
||||
credential,
|
||||
userName,
|
||||
path,
|
||||
tags,
|
||||
}: {
|
||||
credential: types.Credential;
|
||||
path: string;
|
||||
userName: string;
|
||||
tags?: types.Tags;
|
||||
}): { response: RefinedResponse<ResponseType>; tags: types.Tags } {
|
||||
tags = { ...this.tags, ...tags };
|
||||
|
||||
const response = api.dav.Delete.exec({credential: credential as types.Credential, userName, tags, path});
|
||||
const response = api.dav.Delete.exec({ credential: credential, userName, tags, path });
|
||||
|
||||
check(response, {
|
||||
'delete status is 204': () => response.status === 204,
|
||||
}, tags) || this.metricErrorRate.add(1, tags);
|
||||
check(
|
||||
response,
|
||||
{
|
||||
'dav delete status is 204': () => response.status === 204,
|
||||
},
|
||||
tags,
|
||||
) || this.metricErrorRate.add(1, tags);
|
||||
|
||||
this.metricTrend.add(response.timings.duration, tags)
|
||||
this.metricTrend.add(response.timings.duration, tags);
|
||||
|
||||
return {response, tags}
|
||||
return { response, tags };
|
||||
}
|
||||
}
|
||||
|
||||
export class Download extends Play {
|
||||
constructor({name, metricID = 'default'}: { name?: string; metricID?: string; }) {
|
||||
super({name: name || `oc_${metricID}_play_dav_download`});
|
||||
constructor({ name, metricID = 'default' }: { name?: string; metricID?: string } = {}) {
|
||||
super({ name: name || `oc_${metricID}_play_dav_download` });
|
||||
}
|
||||
|
||||
public exec(
|
||||
{credential, userName, path, tags}: {
|
||||
credential: types.Credential;
|
||||
path: string;
|
||||
userName: string;
|
||||
tags?: types.Tags;
|
||||
}
|
||||
): { response: RefinedResponse<ResponseType>; tags: types.Tags; } {
|
||||
tags = {...this.tags, ...tags};
|
||||
public exec({
|
||||
credential,
|
||||
userName,
|
||||
path,
|
||||
tags,
|
||||
}: {
|
||||
credential: types.Credential;
|
||||
path: string;
|
||||
userName: string;
|
||||
tags?: types.Tags;
|
||||
}): { response: RefinedResponse<ResponseType>; tags: types.Tags } {
|
||||
tags = { ...this.tags, ...tags };
|
||||
|
||||
const response = api.dav.Download.exec({credential: credential as types.Credential, userName, tags, path});
|
||||
const response = api.dav.Download.exec({ credential: credential, userName, tags, path });
|
||||
|
||||
check(response, {
|
||||
'download status is 200': () => response.status === 200,
|
||||
}, tags) || this.metricErrorRate.add(1, tags);
|
||||
check(
|
||||
response,
|
||||
{
|
||||
'dav download status is 200': () => response.status === 200,
|
||||
},
|
||||
tags,
|
||||
) || this.metricErrorRate.add(1, tags);
|
||||
|
||||
this.metricTrend.add(response.timings.duration, tags)
|
||||
this.metricTrend.add(response.timings.duration, tags);
|
||||
|
||||
return {response, tags}
|
||||
return { response, tags };
|
||||
}
|
||||
}
|
||||
|
||||
export class Create extends Play {
|
||||
constructor({name, metricID = 'default'}: { name?: string; metricID?: string; }) {
|
||||
super({name: name || `oc_${metricID}_play_dav_create`});
|
||||
constructor({ name, metricID = 'default' }: { name?: string; metricID?: string } = {}) {
|
||||
super({ name: name || `oc_${metricID}_play_dav_create` });
|
||||
}
|
||||
|
||||
public exec(
|
||||
{credential, userName, path, tags}: {
|
||||
credential: types.Credential;
|
||||
path: string;
|
||||
userName: string;
|
||||
tags?: types.Tags;
|
||||
}
|
||||
): { response: RefinedResponse<ResponseType>; tags: types.Tags; } {
|
||||
tags = {...this.tags, ...tags};
|
||||
public exec({
|
||||
credential,
|
||||
userName,
|
||||
path,
|
||||
tags,
|
||||
}: {
|
||||
credential: types.Credential;
|
||||
path: string;
|
||||
userName: string;
|
||||
tags?: types.Tags;
|
||||
}): { response: RefinedResponse<ResponseType>; tags: types.Tags } {
|
||||
tags = { ...this.tags, ...tags };
|
||||
|
||||
const response = api.dav.Create.exec({credential: credential as types.Credential, userName, tags, path});
|
||||
const response = api.dav.Create.exec({ credential: credential, userName, tags, path });
|
||||
|
||||
check(response, {
|
||||
'create status is 201': () => response.status === 201,
|
||||
}, tags) || this.metricErrorRate.add(1, tags);
|
||||
check(
|
||||
response,
|
||||
{
|
||||
'dav create status is 201': () => response.status === 201,
|
||||
},
|
||||
tags,
|
||||
) || this.metricErrorRate.add(1, tags);
|
||||
|
||||
this.metricTrend.add(response.timings.duration, tags)
|
||||
this.metricTrend.add(response.timings.duration, tags);
|
||||
|
||||
return {response, tags}
|
||||
return { response, tags };
|
||||
}
|
||||
}
|
||||
|
||||
export class Propfind extends Play {
|
||||
constructor({name, metricID = 'default'}: { name?: string; metricID?: string; }) {
|
||||
super({name: name || `oc_${metricID}_play_dav_propfind`});
|
||||
constructor({ name, metricID = 'default' }: { name?: string; metricID?: string } = {}) {
|
||||
super({ name: name || `oc_${metricID}_play_dav_propfind` });
|
||||
}
|
||||
|
||||
public exec(
|
||||
{credential, userName, path, tags}: {
|
||||
credential: types.Credential;
|
||||
path?: string;
|
||||
userName: string;
|
||||
tags?: types.Tags;
|
||||
}
|
||||
): { response: RefinedResponse<ResponseType>; tags: types.Tags; } {
|
||||
tags = {...this.tags, ...tags};
|
||||
public exec({
|
||||
credential,
|
||||
userName,
|
||||
path,
|
||||
tags,
|
||||
}: {
|
||||
credential: types.Credential;
|
||||
path?: string;
|
||||
userName: string;
|
||||
tags?: types.Tags;
|
||||
}): { response: RefinedResponse<ResponseType>; tags: types.Tags } {
|
||||
tags = { ...this.tags, ...tags };
|
||||
|
||||
const response = api.dav.Propfind.exec({credential: credential as types.Credential, userName, tags, path});
|
||||
const response = api.dav.Propfind.exec({ credential: credential, userName, tags, path });
|
||||
|
||||
check(response, {
|
||||
'propfind status is 207': () => response.status === 207,
|
||||
}, tags) || this.metricErrorRate.add(1, tags);
|
||||
check(
|
||||
response,
|
||||
{
|
||||
'dav propfind status is 207': () => response.status === 207,
|
||||
},
|
||||
tags,
|
||||
) || this.metricErrorRate.add(1, tags);
|
||||
|
||||
this.metricTrend.add(response.timings.duration, tags)
|
||||
this.metricTrend.add(response.timings.duration, tags);
|
||||
|
||||
return {response, tags}
|
||||
return { response, tags };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
export * as dav from './dav'
|
||||
export * as dav from './dav';
|
||||
export * as users from './users';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Gauge, Trend} from "k6/metrics";
|
||||
import { Gauge, Trend } from 'k6/metrics';
|
||||
|
||||
export class Play {
|
||||
public readonly name: string;
|
||||
@@ -8,12 +8,12 @@ export class Play {
|
||||
public readonly metricErrorRate: Gauge;
|
||||
protected tags: { [key: string]: string };
|
||||
|
||||
constructor({name}: { name: string; }) {
|
||||
constructor({ name }: { name: string }) {
|
||||
this.name = name;
|
||||
this.metricTrendName = `${this.name}_trend`;
|
||||
this.metricErrorRateName = `${this.name}_error_rate`;
|
||||
this.metricTrend = new Trend(this.metricTrendName, true);
|
||||
this.metricErrorRate = new Gauge(this.metricErrorRateName);
|
||||
this.tags = {play: this.name}
|
||||
this.tags = { play: this.name };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
73
tests/k6/src/lib/playbook/users.ts
Normal file
73
tests/k6/src/lib/playbook/users.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
import * as api from '../api';
|
||||
import { check } from 'k6';
|
||||
import * as types from '../types';
|
||||
import { RefinedResponse, ResponseType } from 'k6/http';
|
||||
import { Play } from './playbook';
|
||||
|
||||
export class Create extends Play {
|
||||
constructor({ name, metricID = 'default' }: { name?: string; metricID?: string } = {}) {
|
||||
super({ name: name || `oc_${metricID}_play_users_create` });
|
||||
}
|
||||
|
||||
public exec({
|
||||
credential,
|
||||
userName,
|
||||
password,
|
||||
email,
|
||||
tags,
|
||||
}: {
|
||||
credential: types.Credential;
|
||||
userName: string;
|
||||
password: string;
|
||||
email: string;
|
||||
tags?: types.Tags;
|
||||
}): { response: RefinedResponse<ResponseType>; tags: types.Tags } {
|
||||
tags = { ...this.tags, ...tags };
|
||||
|
||||
const response = api.users.Create.exec({ credential: credential, userName, password, tags, email });
|
||||
|
||||
check(
|
||||
response,
|
||||
{
|
||||
'users create status is 200': () => response.status === 200,
|
||||
},
|
||||
tags,
|
||||
) || this.metricErrorRate.add(1, tags);
|
||||
|
||||
this.metricTrend.add(response.timings.duration, tags);
|
||||
|
||||
return { response, tags };
|
||||
}
|
||||
}
|
||||
|
||||
export class Delete extends Play {
|
||||
constructor({ name, metricID = 'default' }: { name?: string; metricID?: string } = {}) {
|
||||
super({ name: name || `oc_${metricID}_play_users_delete` });
|
||||
}
|
||||
|
||||
public exec({
|
||||
credential,
|
||||
userName,
|
||||
tags,
|
||||
}: {
|
||||
credential: types.Credential;
|
||||
userName: string;
|
||||
tags?: types.Tags;
|
||||
}): { response: RefinedResponse<ResponseType>; tags: types.Tags } {
|
||||
tags = { ...this.tags, ...tags };
|
||||
|
||||
const response = api.users.Delete.exec({ credential: credential, userName, tags });
|
||||
|
||||
check(
|
||||
response,
|
||||
{
|
||||
'users delete status is 200': () => response.status === 200,
|
||||
},
|
||||
tags,
|
||||
) || this.metricErrorRate.add(1, tags);
|
||||
|
||||
this.metricTrend.add(response.timings.duration, tags);
|
||||
|
||||
return { response, tags };
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import {bytes} from 'k6';
|
||||
import { bytes } from 'k6';
|
||||
|
||||
export interface Asset {
|
||||
bytes: bytes;
|
||||
@@ -13,16 +13,16 @@ export interface Token {
|
||||
}
|
||||
|
||||
export interface Account {
|
||||
login: string
|
||||
password: string
|
||||
login: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
export type Credential = Token | Account
|
||||
export type Credential = Token | Account;
|
||||
|
||||
export interface AuthProvider {
|
||||
credential: Credential
|
||||
credential: Credential;
|
||||
}
|
||||
|
||||
export type AssetUnit = 'KB' | 'MB' | 'GB'
|
||||
export type Tags = { [key: string]: string };
|
||||
|
||||
export type Tags = { [key: string]: string }
|
||||
export declare type AssetUnit = 'KB' | 'MB' | 'GB';
|
||||
|
||||
@@ -1,57 +1,60 @@
|
||||
import {bytes} from 'k6';
|
||||
import {randomBytes as k6_randomBytes} from 'k6/crypto';
|
||||
import { bytes } from 'k6';
|
||||
import { randomBytes as k6_randomBytes } from 'k6/crypto';
|
||||
import * as defaults from './defaults';
|
||||
import * as types from './types';
|
||||
|
||||
export const randomNumber = ({min, max}: { min: number; max: number; }): number => {
|
||||
export const randomNumber = ({ min, max }: { min: number; max: number }): number => {
|
||||
return Math.random() * (max - min) + min;
|
||||
}
|
||||
};
|
||||
|
||||
export const randomString = (): string => {
|
||||
return Math.random().toString(20).substr(2)
|
||||
}
|
||||
export const randomString = ({ length = 10 }: { length?: number } = {}): string => {
|
||||
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
|
||||
|
||||
export const buildAccount = ({login = defaults.ACCOUNTS.EINSTEIN}: { login: string; }): types.Account => {
|
||||
let str = '';
|
||||
for (let i = 0; i < length; i++) {
|
||||
str += chars.charAt(Math.floor(Math.random() * chars.length));
|
||||
}
|
||||
|
||||
return str;
|
||||
};
|
||||
|
||||
export const buildAccount = ({ login = defaults.ACCOUNTS.EINSTEIN }: { login: string }): types.Account => {
|
||||
if (defaults.ENV.LOGIN && defaults.ENV.PASSWORD) {
|
||||
return {
|
||||
login: defaults.ENV.LOGIN,
|
||||
password: defaults.ENV.PASSWORD,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return defaults.ACCOUNTS.ALL[login];
|
||||
}
|
||||
|
||||
export const buildAsset = (
|
||||
{
|
||||
name = 'dummy.zip',
|
||||
size = 1,
|
||||
unit = 'MB',
|
||||
}: {
|
||||
name?: string;
|
||||
size?: number;
|
||||
unit?: types.AssetUnit;
|
||||
}
|
||||
): types.Asset => {
|
||||
};
|
||||
export const buildAsset = ({
|
||||
name = 'dummy.zip',
|
||||
size = 50,
|
||||
unit = 'KB',
|
||||
}: {
|
||||
name?: string;
|
||||
size?: number;
|
||||
unit?: types.AssetUnit;
|
||||
}): types.Asset => {
|
||||
const gen = {
|
||||
KB: (s: number): bytes => {
|
||||
return k6_randomBytes(s * 1024)
|
||||
return k6_randomBytes(s * 1024);
|
||||
},
|
||||
MB: (s: number): bytes => {
|
||||
return gen.KB(s * 1024)
|
||||
return gen.KB(s * 1024);
|
||||
},
|
||||
GB: (s: number): bytes => {
|
||||
return gen.MB(s * 1024)
|
||||
return gen.MB(s * 1024);
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
const fileBaseName = name.split('/').reverse()[0]
|
||||
const fileName = fileBaseName.split('.')[0]
|
||||
const fileExtension = fileBaseName.split('.').reverse()[0] || 'zip'
|
||||
const fileBaseName = name.split('/').reverse()[0];
|
||||
const fileName = fileBaseName.split('.')[0];
|
||||
const fileExtension = fileBaseName.split('.').reverse()[0] || 'zip';
|
||||
|
||||
return {
|
||||
name: `${fileName}-${__VU}-${__ITER}-${size}-${unit}-${randomString()}.${fileExtension}`,
|
||||
name: `${fileName}-${__VU}-${__ITER}-${unit}-${size}-${randomString()}.${fileExtension}`,
|
||||
bytes: gen[unit](size),
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
73
tests/k6/src/test/issue/jira/ocis/1007/concurrent-users.ts
Normal file
73
tests/k6/src/test/issue/jira/ocis/1007/concurrent-users.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
import { Options, Threshold } from 'k6/options';
|
||||
import { utils, auth, defaults, playbook, types } from '../../../../../lib';
|
||||
|
||||
const files: Array<{
|
||||
size: number;
|
||||
unit: types.AssetUnit;
|
||||
}> = [
|
||||
{ size: 50, unit: 'KB' },
|
||||
{ size: 500, unit: 'KB' },
|
||||
{ size: 5, unit: 'MB' },
|
||||
{ size: 50, unit: 'MB' },
|
||||
];
|
||||
const adminAuthFactory = new auth.default(utils.buildAccount({ login: defaults.ACCOUNTS.ADMIN }));
|
||||
const plays = {
|
||||
usersCreate: new playbook.users.Create(),
|
||||
usersDelete: new playbook.users.Delete(),
|
||||
davUpload: new playbook.dav.Upload(),
|
||||
davDelete: new playbook.dav.Delete(),
|
||||
};
|
||||
export const options: Options = {
|
||||
insecureSkipTLSVerify: true,
|
||||
iterations: 10,
|
||||
vus: 10,
|
||||
thresholds: files.reduce((acc: { [name: string]: Threshold[] }, c) => {
|
||||
acc[`${plays.davUpload.metricTrendName}{asset:${c.unit + c.size.toString()}}`] = [];
|
||||
acc[`${plays.davDelete.metricTrendName}{asset:${c.unit + c.size.toString()}}`] = [];
|
||||
return acc;
|
||||
}, {}),
|
||||
};
|
||||
|
||||
export default (): void => {
|
||||
const userName: string = utils.randomString();
|
||||
const password: string = utils.randomString();
|
||||
|
||||
plays.usersCreate.exec({
|
||||
userName,
|
||||
password,
|
||||
email: `${userName}@owncloud.com`,
|
||||
credential: adminAuthFactory.credential,
|
||||
});
|
||||
const userAuthFactory = new auth.default({ login: userName, password });
|
||||
const filesUploaded: { id: string; name: string }[] = [];
|
||||
|
||||
files.forEach((f) => {
|
||||
const id = f.unit + f.size.toString();
|
||||
|
||||
const asset = utils.buildAsset({
|
||||
name: `${userName}-dummy.zip`,
|
||||
unit: f.unit,
|
||||
size: f.size,
|
||||
});
|
||||
|
||||
plays.davUpload.exec({
|
||||
credential: userAuthFactory.credential,
|
||||
asset,
|
||||
userName,
|
||||
tags: { asset: id },
|
||||
});
|
||||
|
||||
filesUploaded.push({ id, name: asset.name });
|
||||
});
|
||||
|
||||
filesUploaded.forEach((f) => {
|
||||
plays.davDelete.exec({
|
||||
credential: userAuthFactory.credential,
|
||||
userName: userAuthFactory.account.login,
|
||||
path: f.name,
|
||||
tags: { asset: f.id },
|
||||
});
|
||||
});
|
||||
|
||||
plays.usersDelete.exec({ userName: userName, credential: adminAuthFactory.credential });
|
||||
};
|
||||
@@ -1,64 +1,63 @@
|
||||
import {Options} from "k6/options";
|
||||
import {utils, auth, defaults, playbook} from '../../../../../../lib'
|
||||
import {times} from 'lodash'
|
||||
import { Options, Threshold } from 'k6/options';
|
||||
import { utils, auth, defaults, playbook, types } from '../../../../../../lib';
|
||||
import { times } from 'lodash';
|
||||
|
||||
// put 1000 files into one dir and run a 'PROPFIND' through API
|
||||
|
||||
const files: {
|
||||
size: number;
|
||||
unit: any;
|
||||
}[] = times(1000, () => ({size: 1, unit: 'KB'}))
|
||||
const authFactory = new auth.default(utils.buildAccount({login: defaults.ACCOUNTS.EINSTEIN}));
|
||||
unit: types.AssetUnit;
|
||||
}[] = times(1000, () => ({ size: 1, unit: 'KB' }));
|
||||
const authFactory = new auth.default(utils.buildAccount({ login: defaults.ACCOUNTS.EINSTEIN }));
|
||||
const plays = {
|
||||
davUpload: new playbook.dav.Upload({}),
|
||||
davPropfind: new playbook.dav.Propfind({}),
|
||||
davDelete: new playbook.dav.Delete({}),
|
||||
}
|
||||
davUpload: new playbook.dav.Upload(),
|
||||
davPropfind: new playbook.dav.Propfind(),
|
||||
davDelete: new playbook.dav.Delete(),
|
||||
};
|
||||
export const options: Options = {
|
||||
insecureSkipTLSVerify: true,
|
||||
iterations: 3,
|
||||
vus: 1,
|
||||
thresholds: files.reduce((acc: any, c) => {
|
||||
acc[`${plays.davUpload.metricTrendName}{asset:${c.unit + c.size.toString()}`] = []
|
||||
acc[`${plays.davPropfind.metricTrendName}`] = []
|
||||
acc[`${plays.davDelete.metricTrendName}{asset:${c.unit + c.size.toString()}`] = []
|
||||
return acc
|
||||
thresholds: files.reduce((acc: { [name: string]: Threshold[] }, c) => {
|
||||
acc[`${plays.davUpload.metricTrendName}{asset:${c.unit + c.size.toString()}}`] = [];
|
||||
acc[`${plays.davDelete.metricTrendName}{asset:${c.unit + c.size.toString()}}`] = [];
|
||||
return acc;
|
||||
}, {}),
|
||||
};
|
||||
export default (): void => {
|
||||
const filesUploaded: { id: string, name: string, }[] = []
|
||||
const {account, credential} = authFactory;
|
||||
const filesUploaded: { id: string; name: string }[] = [];
|
||||
const { account, credential } = authFactory;
|
||||
|
||||
files.forEach(f => {
|
||||
files.forEach((f) => {
|
||||
const id = f.unit + f.size.toString();
|
||||
|
||||
const asset = utils.buildAsset({
|
||||
name: `${account.login}-dummy.zip`,
|
||||
unit: f.unit as any,
|
||||
unit: f.unit,
|
||||
size: f.size,
|
||||
})
|
||||
});
|
||||
|
||||
plays.davUpload.exec({
|
||||
credential,
|
||||
asset,
|
||||
userName: account.login,
|
||||
tags: {asset: id},
|
||||
tags: { asset: id },
|
||||
});
|
||||
|
||||
filesUploaded.push({id, name: asset.name})
|
||||
})
|
||||
filesUploaded.push({ id, name: asset.name });
|
||||
});
|
||||
|
||||
plays.davPropfind.exec({
|
||||
credential,
|
||||
userName: account.login,
|
||||
})
|
||||
});
|
||||
|
||||
filesUploaded.forEach(f => {
|
||||
filesUploaded.forEach((f) => {
|
||||
plays.davDelete.exec({
|
||||
credential,
|
||||
userName: account.login,
|
||||
path: f.name,
|
||||
tags: {asset: f.id},
|
||||
tags: { asset: f.id },
|
||||
});
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,81 +1,81 @@
|
||||
import {Options} from "k6/options";
|
||||
import {utils, auth, defaults, playbook} from '../../../../../../lib'
|
||||
import {times} from 'lodash'
|
||||
import { Options, Threshold } from 'k6/options';
|
||||
import { utils, auth, defaults, playbook, types } from '../../../../../../lib';
|
||||
import { times } from 'lodash';
|
||||
|
||||
// Unpack standard data tarball, run PROPFIND on each dir
|
||||
|
||||
const files: {
|
||||
size: number;
|
||||
unit: any;
|
||||
}[] = times(1000, () => ({size: 1, unit: 'KB'}))
|
||||
const authFactory = new auth.default(utils.buildAccount({login: defaults.ACCOUNTS.EINSTEIN}));
|
||||
unit: types.AssetUnit;
|
||||
}[] = times(1000, () => ({ size: 1, unit: 'KB' }));
|
||||
const authFactory = new auth.default(utils.buildAccount({ login: defaults.ACCOUNTS.EINSTEIN }));
|
||||
const plays = {
|
||||
davUpload: new playbook.dav.Upload({}),
|
||||
davPropfind: new playbook.dav.Propfind({}),
|
||||
davCreate: new playbook.dav.Create({}),
|
||||
davDelete: new playbook.dav.Delete({}),
|
||||
}
|
||||
davUpload: new playbook.dav.Upload(),
|
||||
davPropfind: new playbook.dav.Propfind(),
|
||||
davCreate: new playbook.dav.Create(),
|
||||
davDelete: new playbook.dav.Delete(),
|
||||
};
|
||||
export const options: Options = {
|
||||
insecureSkipTLSVerify: true,
|
||||
iterations: 3,
|
||||
vus: 1,
|
||||
thresholds: files.reduce((acc: any, c) => {
|
||||
acc[`${plays.davUpload.metricTrendName}{asset:${c.unit + c.size.toString()}`] = []
|
||||
acc[`${plays.davPropfind.metricTrendName}`] = []
|
||||
acc[`${plays.davCreate.metricTrendName}{asset:${c.unit + c.size.toString()}`] = []
|
||||
acc[`${plays.davDelete.metricTrendName}{asset:${c.unit + c.size.toString()}`] = []
|
||||
return acc
|
||||
thresholds: files.reduce((acc: { [name: string]: Threshold[] }, c) => {
|
||||
acc[`${plays.davUpload.metricTrendName}{asset:${c.unit + c.size.toString()}}`] = [];
|
||||
acc[`${plays.davCreate.metricTrendName}{asset:${c.unit + c.size.toString()}}`] = [];
|
||||
acc[`${plays.davDelete.metricTrendName}{asset:${c.unit + c.size.toString()}}`] = [];
|
||||
return acc;
|
||||
}, {}),
|
||||
};
|
||||
export default (): void => {
|
||||
const filesUploaded: { id: string, name: string, folder: string }[] = []
|
||||
const {account, credential} = authFactory;
|
||||
const filesUploaded: { id: string; name: string; folder: string }[] = [];
|
||||
const { account, credential } = authFactory;
|
||||
|
||||
files.forEach(f => {
|
||||
files.forEach((f) => {
|
||||
const id = f.unit + f.size.toString();
|
||||
|
||||
const asset = utils.buildAsset({
|
||||
name: `${account.login}-dummy.zip`,
|
||||
unit: f.unit as any,
|
||||
unit: f.unit,
|
||||
size: f.size,
|
||||
})
|
||||
});
|
||||
|
||||
const folder = times(utils.randomNumber({min: 1, max: 10}), () => utils.randomString()).reduce((acc: string[], c) => {
|
||||
acc.push(c)
|
||||
const folder = times(utils.randomNumber({ min: 1, max: 10 }), () => utils.randomString())
|
||||
.reduce((acc: string[], c) => {
|
||||
acc.push(c);
|
||||
|
||||
plays.davCreate.exec({
|
||||
credential,
|
||||
path: acc.join('/'),
|
||||
userName: account.login,
|
||||
tags: {asset: id},
|
||||
});
|
||||
|
||||
return acc
|
||||
}, []).join('/')
|
||||
plays.davCreate.exec({
|
||||
credential,
|
||||
path: acc.join('/'),
|
||||
userName: account.login,
|
||||
tags: { asset: id },
|
||||
});
|
||||
|
||||
return acc;
|
||||
}, [])
|
||||
.join('/');
|
||||
|
||||
plays.davUpload.exec({
|
||||
credential,
|
||||
asset,
|
||||
path: folder,
|
||||
userName: account.login,
|
||||
tags: {asset: id},
|
||||
tags: { asset: id },
|
||||
});
|
||||
|
||||
filesUploaded.push({id, name: asset.name, folder})
|
||||
})
|
||||
filesUploaded.push({ id, name: asset.name, folder });
|
||||
});
|
||||
|
||||
plays.davPropfind.exec({
|
||||
credential,
|
||||
userName: account.login,
|
||||
})
|
||||
});
|
||||
|
||||
filesUploaded.forEach(f => {
|
||||
filesUploaded.forEach((f) => {
|
||||
plays.davDelete.exec({
|
||||
credential,
|
||||
userName: account.login,
|
||||
path: f.folder.split('/')[0],
|
||||
tags: {asset: f.id},
|
||||
tags: { asset: f.id },
|
||||
});
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,72 +1,72 @@
|
||||
import {Options} from "k6/options";
|
||||
import {utils, auth, defaults, playbook} from '../../../../../../lib'
|
||||
import {times} from 'lodash'
|
||||
import { Options, Threshold } from 'k6/options';
|
||||
import { utils, auth, defaults, playbook, types } from '../../../../../../lib';
|
||||
import { times } from 'lodash';
|
||||
|
||||
// upload, download and delete of many files with several sizes and summary size of 500 MB in one directory
|
||||
|
||||
const files: {
|
||||
size: number;
|
||||
unit: any;
|
||||
unit: types.AssetUnit;
|
||||
}[] = [
|
||||
...times(100, () => ({size: 500, unit: 'KB'})),
|
||||
...times(50, () => ({size: 5, unit: 'MB'})),
|
||||
...times(10, () => ({size: 25, unit: 'MB'})),
|
||||
]
|
||||
const authFactory = new auth.default(utils.buildAccount({login: defaults.ACCOUNTS.EINSTEIN}));
|
||||
...times(100, () => ({ size: 500, unit: 'KB' as types.AssetUnit })),
|
||||
...times(50, () => ({ size: 5, unit: 'MB' as types.AssetUnit })),
|
||||
...times(10, () => ({ size: 25, unit: 'MB' as types.AssetUnit })),
|
||||
];
|
||||
const authFactory = new auth.default(utils.buildAccount({ login: defaults.ACCOUNTS.EINSTEIN }));
|
||||
const plays = {
|
||||
davUpload: new playbook.dav.Upload({}),
|
||||
davDownload: new playbook.dav.Download({}),
|
||||
davDelete: new playbook.dav.Delete({}),
|
||||
}
|
||||
davUpload: new playbook.dav.Upload(),
|
||||
davDownload: new playbook.dav.Download(),
|
||||
davDelete: new playbook.dav.Delete(),
|
||||
};
|
||||
export const options: Options = {
|
||||
insecureSkipTLSVerify: true,
|
||||
iterations: 3,
|
||||
vus: 1,
|
||||
thresholds: files.reduce((acc: any, c) => {
|
||||
acc[`${plays.davUpload.metricTrendName}{asset:${c.unit + c.size.toString()}`] = []
|
||||
acc[`${plays.davDownload.metricTrendName}{asset:${c.unit + c.size.toString()}`] = []
|
||||
acc[`${plays.davDelete.metricTrendName}{asset:${c.unit + c.size.toString()}`] = []
|
||||
return acc
|
||||
thresholds: files.reduce((acc: { [name: string]: Threshold[] }, c) => {
|
||||
acc[`${plays.davUpload.metricTrendName}{asset:${c.unit + c.size.toString()}}`] = [];
|
||||
acc[`${plays.davDownload.metricTrendName}{asset:${c.unit + c.size.toString()}}`] = [];
|
||||
acc[`${plays.davDelete.metricTrendName}{asset:${c.unit + c.size.toString()}}`] = [];
|
||||
return acc;
|
||||
}, {}),
|
||||
};
|
||||
export default (): void => {
|
||||
const filesUploaded: { id: string, name: string, }[] = []
|
||||
const {account, credential} = authFactory;
|
||||
const filesUploaded: { id: string; name: string }[] = [];
|
||||
const { account, credential } = authFactory;
|
||||
|
||||
files.forEach(f => {
|
||||
files.forEach((f) => {
|
||||
const id = f.unit + f.size.toString();
|
||||
|
||||
const asset = utils.buildAsset({
|
||||
name: `${account.login}-dummy.zip`,
|
||||
unit: f.unit as any,
|
||||
unit: f.unit,
|
||||
size: f.size,
|
||||
})
|
||||
});
|
||||
|
||||
plays.davUpload.exec({
|
||||
credential,
|
||||
asset,
|
||||
userName: account.login,
|
||||
tags: {asset: id},
|
||||
tags: { asset: id },
|
||||
});
|
||||
|
||||
filesUploaded.push({id, name: asset.name})
|
||||
})
|
||||
filesUploaded.push({ id, name: asset.name });
|
||||
});
|
||||
|
||||
filesUploaded.forEach(f => {
|
||||
filesUploaded.forEach((f) => {
|
||||
plays.davDownload.exec({
|
||||
credential,
|
||||
userName: account.login,
|
||||
path: f.name,
|
||||
tags: {asset: f.id},
|
||||
tags: { asset: f.id },
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
filesUploaded.forEach(f => {
|
||||
filesUploaded.forEach((f) => {
|
||||
plays.davDelete.exec({
|
||||
credential,
|
||||
userName: account.login,
|
||||
path: f.name,
|
||||
tags: {asset: f.id},
|
||||
tags: { asset: f.id },
|
||||
});
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {Options} from "k6/options";
|
||||
import {utils, auth, defaults, playbook, types} from '../../../../../../lib'
|
||||
import { Options, Threshold } from 'k6/options';
|
||||
import { utils, auth, defaults, playbook, types } from '../../../../../../lib';
|
||||
|
||||
// upload, download and delete of one file with sizes 50kb, 500kb, 5MB, 50MB, 500MB, 1GB
|
||||
|
||||
@@ -7,69 +7,69 @@ const files: {
|
||||
size: number;
|
||||
unit: types.AssetUnit;
|
||||
}[] = [
|
||||
{size: 50, unit: 'KB'},
|
||||
{size: 500, unit: 'KB'},
|
||||
{size: 5, unit: 'MB'},
|
||||
{size: 50, unit: 'MB'},
|
||||
{size: 500, unit: 'MB'},
|
||||
{size: 1, unit: 'GB'},
|
||||
]
|
||||
const authFactory = new auth.default(utils.buildAccount({login: defaults.ACCOUNTS.EINSTEIN}));
|
||||
{ size: 50, unit: 'KB' },
|
||||
{ size: 500, unit: 'KB' },
|
||||
{ size: 5, unit: 'MB' },
|
||||
{ size: 50, unit: 'MB' },
|
||||
{ size: 500, unit: 'MB' },
|
||||
{ size: 1, unit: 'GB' },
|
||||
];
|
||||
const authFactory = new auth.default(utils.buildAccount({ login: defaults.ACCOUNTS.EINSTEIN }));
|
||||
const plays = {
|
||||
davUpload: new playbook.dav.Upload({}),
|
||||
davDownload: new playbook.dav.Download({}),
|
||||
davDelete: new playbook.dav.Delete({}),
|
||||
}
|
||||
davUpload: new playbook.dav.Upload(),
|
||||
davDownload: new playbook.dav.Download(),
|
||||
davDelete: new playbook.dav.Delete(),
|
||||
};
|
||||
export const options: Options = {
|
||||
insecureSkipTLSVerify: true,
|
||||
iterations: 3,
|
||||
vus: 1,
|
||||
thresholds: files.reduce((acc: any, c) => {
|
||||
acc[`${plays.davUpload.metricTrendName}{asset:${c.unit + c.size.toString()}`] = []
|
||||
acc[`${plays.davDownload.metricTrendName}{asset:${c.unit + c.size.toString()}`] = []
|
||||
acc[`${plays.davDelete.metricTrendName}{asset:${c.unit + c.size.toString()}`] = []
|
||||
return acc
|
||||
thresholds: files.reduce((acc: { [name: string]: Threshold[] }, c) => {
|
||||
acc[`${plays.davUpload.metricTrendName}{asset:${c.unit + c.size.toString()}}`] = [];
|
||||
acc[`${plays.davDownload.metricTrendName}{asset:${c.unit + c.size.toString()}}`] = [];
|
||||
acc[`${plays.davDelete.metricTrendName}{asset:${c.unit + c.size.toString()}}`] = [];
|
||||
return acc;
|
||||
}, {}),
|
||||
};
|
||||
|
||||
export default (): void => {
|
||||
const filesUploaded: { id: string, name: string, }[] = []
|
||||
const {account, credential} = authFactory;
|
||||
const filesUploaded: { id: string; name: string }[] = [];
|
||||
const { account, credential } = authFactory;
|
||||
|
||||
files.forEach(f => {
|
||||
files.forEach((f) => {
|
||||
const id = f.unit + f.size.toString();
|
||||
|
||||
const asset = utils.buildAsset({
|
||||
name: `${account.login}-dummy.zip`,
|
||||
unit: f.unit as any,
|
||||
unit: f.unit,
|
||||
size: f.size,
|
||||
})
|
||||
});
|
||||
|
||||
plays.davUpload.exec({
|
||||
credential,
|
||||
asset,
|
||||
userName: account.login,
|
||||
tags: {asset: id},
|
||||
tags: { asset: id },
|
||||
});
|
||||
|
||||
filesUploaded.push({id, name: asset.name})
|
||||
})
|
||||
filesUploaded.push({ id, name: asset.name });
|
||||
});
|
||||
|
||||
filesUploaded.forEach(f => {
|
||||
filesUploaded.forEach((f) => {
|
||||
plays.davDownload.exec({
|
||||
credential,
|
||||
userName: account.login,
|
||||
path: f.name,
|
||||
tags: {asset: f.id},
|
||||
tags: { asset: f.id },
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
filesUploaded.forEach(f => {
|
||||
filesUploaded.forEach((f) => {
|
||||
plays.davDelete.exec({
|
||||
credential,
|
||||
userName: account.login,
|
||||
path: f.name,
|
||||
tags: {asset: f.id},
|
||||
tags: { asset: f.id },
|
||||
});
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user