@skyramp/skyramp 1.0.0-sha.b2dfe11 → 1.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +10 -17
- package/package.json +14 -5
- package/scripts/download-binary.js +189 -0
- package/src/classes/Asserts.d.ts +16 -0
- package/src/classes/Asserts.js +41 -0
- package/src/classes/AsyncScenario.d.ts +133 -0
- package/src/classes/AsyncScenario.js +324 -0
- package/src/classes/AsyncTestStatus.d.ts +172 -0
- package/src/classes/AsyncTestStatus.js +488 -0
- package/src/classes/DelayConfig.d.ts +4 -0
- package/src/classes/DelayConfig.js +25 -0
- package/src/classes/Endpoint.d.ts +2 -2
- package/src/classes/Endpoint.js +81 -43
- package/src/classes/GrpcEndpoint.d.ts +1 -1
- package/src/classes/GrpcEndpoint.js +24 -3
- package/src/classes/LoadTestConfig.d.ts +131 -0
- package/src/classes/LoadTestConfig.js +186 -0
- package/src/classes/Protocol.d.ts +5 -0
- package/src/classes/Protocol.js +8 -0
- package/src/classes/RequestV2.d.ts +30 -0
- package/src/classes/RequestV2.js +181 -0
- package/src/classes/RequestValue.d.ts +24 -0
- package/src/classes/RequestValue.js +113 -0
- package/src/classes/ResponseV2.d.ts +24 -0
- package/src/classes/ResponseV2.js +96 -0
- package/src/classes/ResponseValue.d.ts +21 -0
- package/src/classes/ResponseValue.js +93 -0
- package/src/classes/RestEndpoint.d.ts +11 -2
- package/src/classes/RestEndpoint.js +90 -5
- package/src/classes/RestParam.d.ts +4 -0
- package/src/classes/RestParam.js +32 -0
- package/src/classes/Scenario.d.ts +48 -0
- package/src/classes/Scenario.js +208 -0
- package/src/classes/SkyrampClient.d.ts +184 -4
- package/src/classes/SkyrampClient.js +774 -40
- package/src/classes/Step.d.ts +28 -0
- package/src/classes/Step.js +113 -0
- package/src/classes/TrafficConfig.d.ts +6 -0
- package/src/classes/TrafficConfig.js +28 -0
- package/src/function.js +46 -0
- package/src/index.d.ts +14 -1
- package/src/index.js +36 -3
- package/src/lib.js +6 -6
- package/src/utils.js +180 -20
- package/src/utils.d.ts +0 -5
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
const lib = require('../lib');
|
|
2
|
+
const { createTestDescriptionFromScenario, getYamlBytes, readDataFromFile } = require('../utils');
|
|
3
|
+
const Asserts = require('./Asserts');
|
|
4
|
+
const RequestValue = require('./RequestValue');
|
|
5
|
+
const Step = require('./Step');
|
|
6
|
+
const buildRequestsWrapper = lib.func('buildRequestsWrapper', 'string', ['string']);
|
|
7
|
+
const writeTestDescriptionWrapper = lib.func('writeTestDescriptionWrapper', 'string', ['string', 'string']);
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* The `Scenario` class allows you to define test scenarios by adding requests and asserts.
|
|
11
|
+
* @class
|
|
12
|
+
*/
|
|
13
|
+
class Scenario {
|
|
14
|
+
static requests = [];
|
|
15
|
+
static scenarios = [];
|
|
16
|
+
static services = [];
|
|
17
|
+
static endpoints = [];
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Initializes a new instance of the Scenario class with the given name.
|
|
21
|
+
* @constructor
|
|
22
|
+
*
|
|
23
|
+
* @param {string} name - The name of the scenario.
|
|
24
|
+
*/
|
|
25
|
+
constructor(...args) {
|
|
26
|
+
if (args.length === 1 && typeof args[0] === 'object') {
|
|
27
|
+
const { name, startAt = 1, headers, vars, ignore } = args[0];
|
|
28
|
+
Object.assign(this, { name, startAt, headers, vars, ignore });
|
|
29
|
+
} else if (args.length === 1 && typeof args[0] === 'string') {
|
|
30
|
+
this.name = args[0];
|
|
31
|
+
}
|
|
32
|
+
this.steps = [];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Adds a request to the scenario.
|
|
37
|
+
*
|
|
38
|
+
* @param {AddRequestOption} option - The options for adding the request.
|
|
39
|
+
* @returns {string} - The name of the request.
|
|
40
|
+
* @throws {Error} - Throws an error if the option is not of type RequestValue or an object with a request property of type RequestValue.
|
|
41
|
+
*/
|
|
42
|
+
addRequestV1(option) {
|
|
43
|
+
if (!(option instanceof RequestValue) && !(option.request instanceof RequestValue)) {
|
|
44
|
+
throw new Error('Invalid argument: option must be of type RequestValue or an object with a request property of type RequestValue');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const request = option instanceof RequestValue ? option : option.request;
|
|
48
|
+
option = { ...option, step: request };
|
|
49
|
+
|
|
50
|
+
const step = new Step(option);
|
|
51
|
+
this.steps.push(step.toJson());
|
|
52
|
+
Scenario.requests.push(request.asRequestDict());
|
|
53
|
+
|
|
54
|
+
const newService = request.endpointDescriptor.services[0];
|
|
55
|
+
if (!Scenario.services.some(s => s.name === newService.name)) {
|
|
56
|
+
Scenario.services.push(newService);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (!Scenario.endpoints.find(ep => ep === request.endpointDescriptor.endpoint)) {
|
|
60
|
+
Scenario.endpoints.push(request.endpointDescriptor.endpoint);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return request.name;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Prepares a test description by creating a data structure with a root scenario and child scenarios for a test description.
|
|
69
|
+
*
|
|
70
|
+
* @returns {Object} - The test description object containing the root scenario, child scenarios, endpoints, services, and requests.
|
|
71
|
+
*/
|
|
72
|
+
prepareTestDescription() {
|
|
73
|
+
let scenarios = []
|
|
74
|
+
// add ourself as root scenario
|
|
75
|
+
scenarios.push({
|
|
76
|
+
name: this.name,
|
|
77
|
+
...(this.vars != undefined && { vars: this.vars }),
|
|
78
|
+
...(this.headers != undefined && { headers: this.headers }),
|
|
79
|
+
...(this.ignore != undefined && { ignore: this.ignore }),
|
|
80
|
+
steps: this.steps,
|
|
81
|
+
})
|
|
82
|
+
// add all client scenarios
|
|
83
|
+
Scenario.scenarios.forEach((scenario) => {
|
|
84
|
+
const s = {
|
|
85
|
+
name: scenario.name,
|
|
86
|
+
...(scenario.vars != undefined && { vars: scenario.vars }),
|
|
87
|
+
...(scenario.headers != undefined && { headers: scenario.headers }),
|
|
88
|
+
...(scenario.ignore != undefined && { ignore: scenario.ignore }),
|
|
89
|
+
steps: scenario.steps,
|
|
90
|
+
}
|
|
91
|
+
scenarios.push(s);
|
|
92
|
+
})
|
|
93
|
+
return {
|
|
94
|
+
name: this.name,
|
|
95
|
+
scenarios: scenarios,
|
|
96
|
+
endpoints: Scenario.endpoints,
|
|
97
|
+
services: Scenario.services,
|
|
98
|
+
requests: Scenario.requests,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
addScenarioV1(option) {
|
|
103
|
+
let scenario = option.scenario;
|
|
104
|
+
if (!(option.scenario instanceof Scenario)) {
|
|
105
|
+
throw new Error('Invalid argument: option.scenario must be of type Scenario');
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
option.step = scenario;
|
|
109
|
+
const step = new Step(option);
|
|
110
|
+
this.steps.push(step.toJson());
|
|
111
|
+
|
|
112
|
+
if (!Scenario.scenarios.find(s => s === scenario)) {
|
|
113
|
+
Scenario.scenarios.push(scenario);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
toJson() {
|
|
118
|
+
return {
|
|
119
|
+
steps: this.steps,
|
|
120
|
+
services: this.services,
|
|
121
|
+
endpoints: this.endpoints,
|
|
122
|
+
requests: this.requests,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
addRequest(endpoint, methodName, requestObject = undefined, dynamic = false) {
|
|
127
|
+
this.buildRequestsFromEndpoint(endpoint);
|
|
128
|
+
for (const request of Scenario.requests) {
|
|
129
|
+
if (request.methodName === methodName) {
|
|
130
|
+
if (dynamic) {
|
|
131
|
+
request.javascriptPath = requestObject;
|
|
132
|
+
delete request.blob;
|
|
133
|
+
} else if (requestObject !== undefined) {
|
|
134
|
+
request.blob = requestObject.requestValue.blob;
|
|
135
|
+
}
|
|
136
|
+
this.steps.push({ requestName: request.name });
|
|
137
|
+
return request.name;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
throw new Error(`Method ${methodName} not found`);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
addRequestFromFile(endpoint, methodName, requestFile) {
|
|
144
|
+
const [jsonData, dynamic] = readDataFromFile(requestFile);
|
|
145
|
+
return this.addRequest(endpoint, methodName, jsonData, dynamic);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
buildRequestsFromEndpoint(endpoint) {
|
|
149
|
+
if (Scenario.endpoints.indexOf(endpoint.endpoint) !== -1) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
Scenario.services.push(...endpoint.services);
|
|
154
|
+
Scenario.endpoints.push(endpoint.endpoint);
|
|
155
|
+
|
|
156
|
+
const yamlContent = getYamlBytes(endpoint.mockDescription);
|
|
157
|
+
const response = buildRequestsWrapper(yamlContent);
|
|
158
|
+
try {
|
|
159
|
+
const requests = JSON.parse(response);
|
|
160
|
+
Scenario.requests.push(requests[0]);
|
|
161
|
+
} catch (error) {
|
|
162
|
+
throw new Error(response);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Adds an assertion to the scenario that checks if the value of value1 is equal to value2.
|
|
168
|
+
* @param {string} value1 - The first value to compare.
|
|
169
|
+
* @param {string} value2 - The second value to compare.
|
|
170
|
+
* @returns {string} - The assertion string.
|
|
171
|
+
*/
|
|
172
|
+
addAssertEqual(value1, value2) {
|
|
173
|
+
const assertion = `requests.${value1} == "${value2}"`;
|
|
174
|
+
this.steps.push({ asserts: assertion });
|
|
175
|
+
return assertion;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
addAssertV1(option) {
|
|
179
|
+
let assert = new Asserts(option);
|
|
180
|
+
const step = new Step({
|
|
181
|
+
stepName: option.stepName,
|
|
182
|
+
description: option.description,
|
|
183
|
+
if: option.if_,
|
|
184
|
+
step: assert,
|
|
185
|
+
});
|
|
186
|
+
this.steps.push(step.toJson());
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
writeTestConfigurationToFile() {
|
|
190
|
+
const testDescription = createTestDescriptionFromScenario({
|
|
191
|
+
scenario: this.prepareTestDescription()
|
|
192
|
+
});
|
|
193
|
+
const yamlContent = getYamlBytes(testDescription);
|
|
194
|
+
return new Promise((resolve, reject) => {
|
|
195
|
+
writeTestDescriptionWrapper.async(yamlContent, this.name, (err, res) => {
|
|
196
|
+
if (err) {
|
|
197
|
+
reject(err);
|
|
198
|
+
} else if (res) {
|
|
199
|
+
reject(new Error(res));
|
|
200
|
+
} else {
|
|
201
|
+
resolve();
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
module.exports = Scenario;
|
|
@@ -1,10 +1,190 @@
|
|
|
1
|
+
import { ResponseValue } from '..';
|
|
1
2
|
import { Endpoint } from './Endpoint';
|
|
3
|
+
import { Scenario } from './Scenario';
|
|
4
|
+
import {TrafficConfig} from './TrafficConfig';
|
|
5
|
+
import { Protocol } from './Protocol';
|
|
6
|
+
import { AsyncScenario } from './AsyncScenario';
|
|
7
|
+
import { LoadTestConfig } from './LoadTestConfig';
|
|
8
|
+
import { AsyncTestStatus } from './AsyncTestStatus';
|
|
9
|
+
|
|
10
|
+
export enum Language {
|
|
11
|
+
PYTHON = 'python'
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface testerStartV1Options {
|
|
15
|
+
namespace?: string;
|
|
16
|
+
kubePath?: string;
|
|
17
|
+
kubeContext?: string;
|
|
18
|
+
clusterName?: string;
|
|
19
|
+
address?: string;
|
|
20
|
+
scenario: Scenario | [Scenario];
|
|
21
|
+
testName: string;
|
|
22
|
+
globalHeaders?: {[headerName: string]: string};
|
|
23
|
+
globalVars?: {[variableName: string]: string};
|
|
24
|
+
generateTestReport?: boolean;
|
|
25
|
+
isDockerenv?: boolean;
|
|
26
|
+
}
|
|
27
|
+
interface MockerApplyV1Options {
|
|
28
|
+
namespace: string;
|
|
29
|
+
kubeConfig: string;
|
|
30
|
+
kubeContext: string;
|
|
31
|
+
clusterName: string;
|
|
32
|
+
address: string;
|
|
33
|
+
response: ResponseValue | ResponseValue[];
|
|
34
|
+
trafficConfig: TrafficConfig;
|
|
35
|
+
}
|
|
36
|
+
interface SendRequestV2Options {
|
|
37
|
+
url: string;
|
|
38
|
+
path: string;
|
|
39
|
+
method: string;
|
|
40
|
+
body?: string;
|
|
41
|
+
headers?: {[headerName: string]: string};
|
|
42
|
+
cookies?: {[cookieName: string]: string};
|
|
43
|
+
dataOverride?: {[dataName: string]: string | number | boolean | object | null};
|
|
44
|
+
pathParams?: {[pathName: string]: string | number | boolean | object | null};
|
|
45
|
+
queryParams?: {[queryName: string]: string | number | boolean | object | null};
|
|
46
|
+
formParams?: {[formParamName: string]: string | number | boolean | object | null};
|
|
47
|
+
expectedCode?: string;
|
|
48
|
+
description?: string;
|
|
49
|
+
insecure?: boolean;
|
|
50
|
+
funcHandler?: string;
|
|
51
|
+
funcHandlerType?: string;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
interface SkyrampClientOptions {
|
|
55
|
+
runtime?: string;
|
|
56
|
+
dockerNetwork?: string;
|
|
57
|
+
dockerSkyrampPort?: number;
|
|
58
|
+
k8SNamespace?: string;
|
|
59
|
+
k8SConfigPath?: string;
|
|
60
|
+
clusterName?: string;
|
|
61
|
+
k8SContext?: string;
|
|
62
|
+
userToken?: string;
|
|
63
|
+
address?: string;
|
|
64
|
+
workerImage?: string;
|
|
65
|
+
local_image?: boolean;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
interface AnalyzeOpenAPIOptions {
|
|
69
|
+
apiSchema: string;
|
|
70
|
+
uri: string;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
interface TraceCollectOptions {
|
|
74
|
+
output?: string;
|
|
75
|
+
workerContainerName?: string;
|
|
76
|
+
playwright?: boolean;
|
|
77
|
+
playwrightOutput?: string;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
interface GenerateRestTestOptions {
|
|
81
|
+
testType?: string;
|
|
82
|
+
uri?: string;
|
|
83
|
+
method?: string;
|
|
84
|
+
language?: string;
|
|
85
|
+
framework?: string;
|
|
86
|
+
output?: string;
|
|
87
|
+
outputDir?: string;
|
|
88
|
+
runtime?: string;
|
|
89
|
+
dockerNetwork?: string;
|
|
90
|
+
dockerWorkerPort?: string;
|
|
91
|
+
k8sNamespace?: string;
|
|
92
|
+
k8sConfig?: string;
|
|
93
|
+
k8sContext?: string;
|
|
94
|
+
authHeader?: string;
|
|
95
|
+
authType?: string;
|
|
96
|
+
requestData?: string;
|
|
97
|
+
responseData?: string;
|
|
98
|
+
responseStatusCode?: string;
|
|
99
|
+
force?: boolean;
|
|
100
|
+
deployDashboard?: boolean;
|
|
101
|
+
formParams?: string;
|
|
102
|
+
pathParams?: string;
|
|
103
|
+
queryParams?: string;
|
|
104
|
+
apiSchema?: string[];
|
|
105
|
+
traceFilePath?: string;
|
|
106
|
+
generateInclude?: string[];
|
|
107
|
+
generateExclude?: string[];
|
|
108
|
+
generateNoProxy?: string[];
|
|
109
|
+
generateInsecure?: boolean;
|
|
110
|
+
assertOption?: string;
|
|
111
|
+
playwright?: boolean;
|
|
112
|
+
playwrightOutput?: string;
|
|
113
|
+
playwrightInput?: string;
|
|
114
|
+
loadCount?: string;
|
|
115
|
+
loadDuration?: string;
|
|
116
|
+
loadNumThreads?: string;
|
|
117
|
+
loadRampupDuration?: string;
|
|
118
|
+
loadRampupInterval?: string;
|
|
119
|
+
loadTargetRPS?: string;
|
|
120
|
+
unblock?: boolean;
|
|
121
|
+
entrypoint?: string;
|
|
122
|
+
accessToken?: string;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
interface SendScenarioOptions {
|
|
126
|
+
until?: string;
|
|
127
|
+
loadTestConfig?: LoadTestConfig;
|
|
128
|
+
dependenciesFilepath?: string;
|
|
129
|
+
blocked?: boolean;
|
|
130
|
+
debug?: boolean;
|
|
131
|
+
skipCertVerification?: boolean;
|
|
132
|
+
}
|
|
133
|
+
|
|
2
134
|
export declare class SkyrampClient {
|
|
3
|
-
constructor(kubeconfigPath?: string, clusterName?: string, context?: string,
|
|
135
|
+
constructor(kubeconfigPath?: string, clusterName?: string, context?: string, userToken?: string);
|
|
136
|
+
constructor(options: SkyrampClientOptions);
|
|
4
137
|
applyLocal(): Promise<void>;
|
|
5
138
|
addKubeconfig(context: string, clusterName: string, kubeconfigPath: string): Promise<void>;
|
|
6
|
-
removeCluster(clusterName?: string): Promise<void>;
|
|
7
139
|
removeLocal(): Promise<void>;
|
|
8
|
-
|
|
9
|
-
|
|
140
|
+
removeCluster(clusterName?: string): Promise<void>;
|
|
141
|
+
mockerApply(namespace: string, kubePath: string, kubeContext: string, clusterName: string, address: string, endpoint: Endpoint): Promise<void>;
|
|
142
|
+
deploySkyrampWorker(namespace?: string, workerImage?: string, localImage?: boolean, kubePath?: string, kubeContext?: string, clusterName?: string): Promise<void>
|
|
143
|
+
deleteSkyrampWorker(namespace?: string, kubePath:string, kubeContext?: string, clusterName?: string): Promise<void>
|
|
144
|
+
runDockerSkyrampWorker(workerImage?:string, workerTag?:string, hostPost?:int, targetNetworkName?:string): Promise<void>
|
|
145
|
+
removeDockerSkyrampWorker() : Promise<void>
|
|
146
|
+
mockerApplyV1(options: MockerApplyV1Options): Promise<void>;
|
|
147
|
+
mockerApplyV1(namespace: string, kubePath: string, kubeContext: string, clusterName: string, address: string, response: ResponseValue | ResponseValue[], trafficConfig: TrafficConfig): Promise<void>;
|
|
148
|
+
mockerApplyFromFile(namespace: string, kubePath: string, kubeContext: string, clusterName: string, address: string, filePath: string): Promise<void>;
|
|
149
|
+
applyMockDescription(namespace: string, address: string, mockYamlContent: string): Promise<void>;
|
|
150
|
+
testerStart(namespace: string, kubePath: string, kubeContext: string, clusterName: string, address: string, scenario: Scenario): Promise<void>;
|
|
151
|
+
testerStartV1(namespace: string,
|
|
152
|
+
kubePath: string,
|
|
153
|
+
kubeContext: string,
|
|
154
|
+
clusterName: string,
|
|
155
|
+
address: string,
|
|
156
|
+
scenario: Scenario,
|
|
157
|
+
testName: string,
|
|
158
|
+
globalHeaders: {[headerName: string]: string},
|
|
159
|
+
generateTestReport: boolean,
|
|
160
|
+
isDockerenv: boolean): Promise<void>;
|
|
161
|
+
|
|
162
|
+
testerStartV1(options: testerStartV1Options): Promise<void>;
|
|
163
|
+
|
|
164
|
+
testerGenerate(
|
|
165
|
+
protocol: Protocol,
|
|
166
|
+
apiSchemaPath: string,
|
|
167
|
+
alias: string,
|
|
168
|
+
endpointPath: string,
|
|
169
|
+
language: Language,
|
|
170
|
+
tag: string,
|
|
171
|
+
sampleRequestPath: string,
|
|
172
|
+
port: int,
|
|
173
|
+
generateRobot: boolean,
|
|
174
|
+
functionalScenario: boolean,
|
|
175
|
+
negativeScenario: boolean): Promise<string[]>;
|
|
176
|
+
|
|
177
|
+
sendRequest(options: SendRequestV2Options): Promise<void>;
|
|
178
|
+
deployDashboard(network: string): Promise<void>;
|
|
179
|
+
|
|
180
|
+
generateRestTest(options: GenerateRestTestOptions): Promise<string>;
|
|
181
|
+
traceCollect(options: TraceCollectOptions): Promise<string>;
|
|
182
|
+
analyzeOpenapi(options: AnalyzeOpenAPIOptions): Promise<string>;
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Sends a scenario for load testing using the V2 API
|
|
186
|
+
* @param scenario The scenario object or array of scenarios to run
|
|
187
|
+
* @param options Additional options for the load test
|
|
188
|
+
*/
|
|
189
|
+
sendScenario(scenario: AsyncScenario | AsyncScenario[], options?: SendScenarioOptions): Promise<AsyncTestStatus>;
|
|
10
190
|
}
|