@skyramp/skyramp 0.5.9 → 0.5.16
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/package.json +6 -3
- package/scripts/download-binary.js +189 -0
- package/src/classes/RequestV2.d.ts +1 -0
- package/src/classes/RequestV2.js +6 -2
- package/src/classes/SkyrampClient.d.ts +20 -15
- package/src/classes/SkyrampClient.js +53 -127
- package/src/lib.js +5 -5
- package/lib/dev-darwin-amd64.dylib +0 -0
- package/lib/dev-darwin-amd64.h +0 -173
- package/lib/dev-darwin-arm64.dylib +0 -0
- package/lib/dev-darwin-arm64.h +0 -173
- package/lib/dev-linux-386.h +0 -173
- package/lib/dev-linux-386.so +0 -0
- package/lib/dev-linux-amd64.h +0 -173
- package/lib/dev-linux-amd64.so +0 -0
- package/lib/dev-windows-amd64.dll +0 -0
- package/lib/dev-windows-amd64.h +0 -173
package/package.json
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skyramp/skyramp",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.16",
|
|
4
4
|
"description": "module for leveraging skyramp cli functionality",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"lint": "eslint 'src/**/*.js' 'src/**/*.ts' --fix",
|
|
7
7
|
"pack": "npm pack",
|
|
8
|
-
"reference-docs": "documentation build src/**/*.js src/classes/**/*.js -f md -o reference.md"
|
|
8
|
+
"reference-docs": "documentation build src/**/*.js src/classes/**/*.js -f md -o reference.md",
|
|
9
|
+
"postinstall": "node scripts/download-binary.js",
|
|
10
|
+
"clean": "rimraf node_modules && rimraf package-lock.json && rimraf skyramp && rimraf lib/*"
|
|
9
11
|
},
|
|
10
12
|
"files": [
|
|
11
|
-
"
|
|
13
|
+
"scripts/*.js",
|
|
12
14
|
"src/*.js",
|
|
13
15
|
"src/*.ts",
|
|
14
16
|
"src/classes/*.js",
|
|
@@ -18,6 +20,7 @@
|
|
|
18
20
|
"author": "",
|
|
19
21
|
"license": "MIT",
|
|
20
22
|
"dependencies": {
|
|
23
|
+
"@aws-sdk/client-s3": "^3.812.0",
|
|
21
24
|
"fs": "^0.0.1-security",
|
|
22
25
|
"js-yaml": "^4.1.0",
|
|
23
26
|
"koffi": "2.5.12"
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
const https = require('https');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const crypto = require('crypto');
|
|
5
|
+
const { S3Client, GetObjectCommand } = require("@aws-sdk/client-s3");
|
|
6
|
+
|
|
7
|
+
function log(level, message) {
|
|
8
|
+
const timestamp = new Date().toISOString();
|
|
9
|
+
console.log(`[${timestamp}] [${level.toUpperCase()}] ${message}`);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
let S3_PRIVATE = process.env.S3_PRIVATE || false; // Set to true if libraries are in a private S3 bucket
|
|
13
|
+
const AWS_REGION = process.env.AWS_REGION || 'us-west-2'; // Set your AWS region
|
|
14
|
+
const SKIP_DOWNLOAD = process.env.SKIP_DOWNLOAD || false; // Set to true to skip the download process
|
|
15
|
+
const PUBLIC_BUCKET_NAME = process.env.INT_LIBRARY_BUCKET || 'skyramp-public'; // Set to your S3 public bucket name
|
|
16
|
+
const PUBLIC_LIBRARY_PATH = process.env.INT_LIBRARY_PATH || `release/v${require('../package.json').version}/lib`; // Set to your S3 public library root path
|
|
17
|
+
const PRIVATE_BUCKET_NAME = process.env.INT_LIBRARY_BUCKET || undefined; // Set to your S3 private bucket name
|
|
18
|
+
const PRIVATE_LIBRARY_PATH = process.env.INT_LIBRARY_PATH || ''; // Set to your S3 private library root path
|
|
19
|
+
|
|
20
|
+
if (SKIP_DOWNLOAD) {
|
|
21
|
+
log('info', "Skipping download as requested by SKIP_DOWNLOAD=true.");
|
|
22
|
+
process.exit(0);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (process.env.CI) {
|
|
26
|
+
log('info', "Running in CI environment. Defaulting to private S3 download.");
|
|
27
|
+
S3_PRIVATE = true;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const archMap = {
|
|
31
|
+
x64: 'amd64',
|
|
32
|
+
ia32: '386',
|
|
33
|
+
arm: 'arm',
|
|
34
|
+
arm64: 'arm64',
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const platformMap = {
|
|
38
|
+
win32: 'windows',
|
|
39
|
+
darwin: 'darwin',
|
|
40
|
+
linux: 'linux',
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const extMap = {
|
|
44
|
+
windows: 'dll',
|
|
45
|
+
darwin: 'dylib',
|
|
46
|
+
linux: 'so',
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const rawPlatform = process.platform;
|
|
50
|
+
const rawArch = process.arch;
|
|
51
|
+
const platform = platformMap[rawPlatform];
|
|
52
|
+
const arch = archMap[rawArch];
|
|
53
|
+
const ext = extMap[platform];
|
|
54
|
+
|
|
55
|
+
if (!platform || !arch || !ext) {
|
|
56
|
+
log('error', `Unsupported platform or architecture: ${rawPlatform} / ${rawArch}`);
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const prefix = 'skyramp';
|
|
61
|
+
const binaryFilename = `${prefix}-${platform}-${arch}.${ext}`;
|
|
62
|
+
const headerFilename = `${prefix}-${platform}-${arch}.h`;
|
|
63
|
+
|
|
64
|
+
const baseUrl = `https://${PUBLIC_BUCKET_NAME}.s3.${AWS_REGION}.amazonaws.com/${PUBLIC_LIBRARY_PATH}/`;
|
|
65
|
+
const localDir = path.join(__dirname, '..', 'lib');
|
|
66
|
+
|
|
67
|
+
const files = [
|
|
68
|
+
{ name: binaryFilename, dest: path.join(localDir, binaryFilename) },
|
|
69
|
+
{ name: headerFilename, dest: path.join(localDir, headerFilename) },
|
|
70
|
+
];
|
|
71
|
+
|
|
72
|
+
async function calculateMD5(filePath) {
|
|
73
|
+
return new Promise((resolve, reject) => {
|
|
74
|
+
const hash = crypto.createHash('md5');
|
|
75
|
+
const stream = fs.createReadStream(filePath);
|
|
76
|
+
stream.on('data', data => hash.update(data));
|
|
77
|
+
stream.on('end', () => resolve(hash.digest('hex')));
|
|
78
|
+
stream.on('error', (err) => {
|
|
79
|
+
log('error', `Failed to calculate MD5 for ${filePath}: ${err.message}`);
|
|
80
|
+
reject(err);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async function getETag(url) {
|
|
86
|
+
return new Promise((resolve, reject) => {
|
|
87
|
+
https.get(url, { method: 'HEAD' }, res => {
|
|
88
|
+
if (res.statusCode !== 200) {
|
|
89
|
+
reject(new Error(`HTTP ${res.statusCode}: ${url}`));
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
resolve(res.headers['etag']?.replace(/"/g, '')); // Remove quotes from ETag
|
|
93
|
+
}).on('error', (err) => {
|
|
94
|
+
log('error', `Error during HEAD request to ${url}: ${err.message}`);
|
|
95
|
+
reject(err);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async function download(url, dest, options = {}) {
|
|
101
|
+
await fs.promises.mkdir(path.dirname(dest), { recursive: true });
|
|
102
|
+
|
|
103
|
+
const { session, bucket, s3Key } = options;
|
|
104
|
+
|
|
105
|
+
return new Promise((resolve, reject) => {
|
|
106
|
+
if (session && bucket && s3Key) {
|
|
107
|
+
// Private S3 download using AWS SDK
|
|
108
|
+
const command = new GetObjectCommand({ Bucket: bucket, Key: s3Key });
|
|
109
|
+
session.send(command).then(response => {
|
|
110
|
+
const stream = response.Body;
|
|
111
|
+
const file = fs.createWriteStream(dest);
|
|
112
|
+
stream.pipe(file);
|
|
113
|
+
stream.on('error', (err) => {
|
|
114
|
+
log('error', `Error streaming file from S3: ${err.message}`);
|
|
115
|
+
reject(err);
|
|
116
|
+
});
|
|
117
|
+
file.on('finish', () => {
|
|
118
|
+
log('info', `Successfully downloaded ${s3Key} to ${dest}`);
|
|
119
|
+
file.close(resolve);
|
|
120
|
+
});
|
|
121
|
+
}).catch(err => {
|
|
122
|
+
log('error', `Failed to download ${s3Key} from S3: ${err.message}`);
|
|
123
|
+
reject(err);
|
|
124
|
+
});
|
|
125
|
+
} else {
|
|
126
|
+
// Public URL download using https
|
|
127
|
+
https.get(url, res => {
|
|
128
|
+
if (res.statusCode !== 200) {
|
|
129
|
+
const error = new Error(`HTTP ${res.statusCode}: ${url}`);
|
|
130
|
+
log('error', `Failed to download ${url}: ${error.message}`);
|
|
131
|
+
reject(error);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
const file = fs.createWriteStream(dest);
|
|
135
|
+
res.pipe(file);
|
|
136
|
+
file.on('finish', () => {
|
|
137
|
+
log('info', `Successfully downloaded ${url} to ${dest}`);
|
|
138
|
+
file.close(resolve);
|
|
139
|
+
});
|
|
140
|
+
}).on('error', (err) => {
|
|
141
|
+
log('error', `Error during download from ${url}: ${err.message}`);
|
|
142
|
+
reject(err);
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
(async () => {
|
|
149
|
+
for (const file of files) {
|
|
150
|
+
let options = {};
|
|
151
|
+
let url = baseUrl + file.name;
|
|
152
|
+
const localFile = file.dest;
|
|
153
|
+
log('info', `Processing ${file.name}...`);
|
|
154
|
+
|
|
155
|
+
try {
|
|
156
|
+
if (S3_PRIVATE) {
|
|
157
|
+
log("Pulling libraries from Private S3.");
|
|
158
|
+
const s3 = new S3Client({region: AWS_REGION});
|
|
159
|
+
|
|
160
|
+
url = null; // No URL needed for S3 private download client
|
|
161
|
+
options = {
|
|
162
|
+
session: s3,
|
|
163
|
+
bucket: PRIVATE_BUCKET_NAME,
|
|
164
|
+
s3Key: `${PRIVATE_LIBRARY_PATH}/${file.name}`
|
|
165
|
+
};
|
|
166
|
+
} else if (fs.existsSync(localFile)) {
|
|
167
|
+
log('info', `Checking ${file.name} for changes...`);
|
|
168
|
+
const remoteETag = await getETag(url);
|
|
169
|
+
const localHash = await calculateMD5(localFile);
|
|
170
|
+
log('debug', `Remote ETag: ${remoteETag}, Local Hash: ${localHash}`);
|
|
171
|
+
|
|
172
|
+
if (remoteETag === localHash) {
|
|
173
|
+
log('info', `✅ ${file.name} is up-to-date.`);
|
|
174
|
+
continue;
|
|
175
|
+
} else {
|
|
176
|
+
log('info', `🔄 ${file.name} differs, downloading...`);
|
|
177
|
+
}
|
|
178
|
+
} else {
|
|
179
|
+
log('info', `⬇️ ${file.name} not found locally, downloading...`);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
await download(url, file.dest, options);
|
|
183
|
+
log('info', `✅ Saved ${file.name} to ${file.dest}`);
|
|
184
|
+
} catch (e) {
|
|
185
|
+
log('error', `❌ Failed to process ${file.name}: ${e.message}`);
|
|
186
|
+
process.exit(1);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
})();
|
package/src/classes/RequestV2.js
CHANGED
|
@@ -20,6 +20,7 @@ class RequestV2 {
|
|
|
20
20
|
* @param {string} [options.expectedCode=''] - The expected HTTP status code of the response.
|
|
21
21
|
* @param {string} [options.funcHandler=''] - The dynamic handler function for the request.
|
|
22
22
|
* @param {string} [options.funcHandlerType=''] - The type of the dynamic handler (e.g., 'python', 'javascript').
|
|
23
|
+
* @param {boolean} [options.insecure=false] - Skip cert verification if set.
|
|
23
24
|
*/
|
|
24
25
|
constructor(options = {}) {
|
|
25
26
|
this.url = options.url || '';
|
|
@@ -35,6 +36,7 @@ class RequestV2 {
|
|
|
35
36
|
this.expectedCode = options.expectedCode || '';
|
|
36
37
|
this.funcHandler = options.funcHandler || '';
|
|
37
38
|
this.funcHandlerType = options.funcHandlerType || '';
|
|
39
|
+
this.insecure = options.insecure || false;
|
|
38
40
|
}
|
|
39
41
|
|
|
40
42
|
toYaml() {
|
|
@@ -52,7 +54,8 @@ class RequestV2 {
|
|
|
52
54
|
formParams: 'form_params',
|
|
53
55
|
expectedCode: 'expected_code',
|
|
54
56
|
funcHandler: 'func_handler',
|
|
55
|
-
funcHandlerType: 'func_handler_type'
|
|
57
|
+
funcHandlerType: 'func_handler_type',
|
|
58
|
+
insecure: 'insecure'
|
|
56
59
|
};
|
|
57
60
|
|
|
58
61
|
const { body, ...rest } = this;
|
|
@@ -90,7 +93,8 @@ class RequestV2 {
|
|
|
90
93
|
formParams: 'form_params',
|
|
91
94
|
expectedCode: 'expected_code',
|
|
92
95
|
funcHandler: 'func_handler',
|
|
93
|
-
funcHandlerType: 'func_handler_type'
|
|
96
|
+
funcHandlerType: 'func_handler_type',
|
|
97
|
+
insecure: 'insecure'
|
|
94
98
|
};
|
|
95
99
|
|
|
96
100
|
const { ...rest } = this;
|
|
@@ -3,7 +3,6 @@ import { Endpoint } from './Endpoint';
|
|
|
3
3
|
import { Scenario } from './Scenario';
|
|
4
4
|
import {TrafficConfig} from './TrafficConfig';
|
|
5
5
|
import { Protocol } from './Protocol';
|
|
6
|
-
import {oauthResponseType} from './SkyrampClient';
|
|
7
6
|
|
|
8
7
|
export enum Language {
|
|
9
8
|
PYTHON = 'python'
|
|
@@ -61,9 +60,16 @@ interface SkyrampClientOptions {
|
|
|
61
60
|
local_image?: boolean;
|
|
62
61
|
}
|
|
63
62
|
|
|
63
|
+
interface AnalyzeOpenAPIOptions {
|
|
64
|
+
apiSchema: string;
|
|
65
|
+
uri: string;
|
|
66
|
+
}
|
|
67
|
+
|
|
64
68
|
interface TraceCollectOptions {
|
|
65
69
|
output?: string;
|
|
66
70
|
workerContainerName?: string;
|
|
71
|
+
playwright?: boolean;
|
|
72
|
+
playwrightOutput?: string;
|
|
67
73
|
}
|
|
68
74
|
|
|
69
75
|
interface GenerateRestTestOptions {
|
|
@@ -87,21 +93,24 @@ interface GenerateRestTestOptions {
|
|
|
87
93
|
responseStatusCode?: string;
|
|
88
94
|
force?: boolean;
|
|
89
95
|
deployDashboard?: boolean;
|
|
90
|
-
formParams?:
|
|
91
|
-
pathParams?:
|
|
92
|
-
queryParams?:
|
|
96
|
+
formParams?: string;
|
|
97
|
+
pathParams?: string;
|
|
98
|
+
queryParams?: string;
|
|
93
99
|
apiSchema?: string[];
|
|
94
100
|
traceFilePath?: string;
|
|
95
101
|
generateInclude?: string[];
|
|
96
102
|
generateExclude?: string[];
|
|
97
103
|
generateInsecure?: boolean;
|
|
98
104
|
assertOption?: string;
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
+
playwright?: boolean;
|
|
106
|
+
playwrightOutput?: string;
|
|
107
|
+
playwrightInput?: string;
|
|
108
|
+
loadCount?: string;
|
|
109
|
+
loadDuration?: string;
|
|
110
|
+
loadNumThreads?: string;
|
|
111
|
+
loadRampupDuration?: string;
|
|
112
|
+
loadRampupInterval?: string;
|
|
113
|
+
loadTargetRPS?: string;
|
|
105
114
|
unblock?: boolean;
|
|
106
115
|
}
|
|
107
116
|
|
|
@@ -134,11 +143,6 @@ export declare class SkyrampClient {
|
|
|
134
143
|
isDockerenv: boolean): Promise<void>;
|
|
135
144
|
|
|
136
145
|
testerStartV1(options: testerStartV1Options): Promise<void>;
|
|
137
|
-
testerStartvalidateToken(userToken: string): Promise<void>;
|
|
138
|
-
readCredential(): Promise<credResponseType>;
|
|
139
|
-
getOAuthURL(provider: string, port: number): string;
|
|
140
|
-
runOAuthLoopback(provider: string, port: number): Promise<oauthResponseType>;
|
|
141
|
-
registerUser(provider: string, email: string, oauthToken: string): Promise<string>;
|
|
142
146
|
|
|
143
147
|
testerGenerate(
|
|
144
148
|
protocol: Protocol,
|
|
@@ -158,4 +162,5 @@ export declare class SkyrampClient {
|
|
|
158
162
|
|
|
159
163
|
generateRestTest(options: GenerateRestTestOptions): Promise<string>;
|
|
160
164
|
traceCollect(options: TraceCollectOptions): Promise<string>;
|
|
165
|
+
analyzeOpenapi(options: AnalyzeOpenAPIOptions): Promise<string>;
|
|
161
166
|
}
|
|
@@ -3,19 +3,6 @@ const koffi = require('koffi');
|
|
|
3
3
|
const TrafficConfig = require('./TrafficConfig');
|
|
4
4
|
const RequestV2 = require('./RequestV2');
|
|
5
5
|
const ResponseV2 = require('./ResponseV2');
|
|
6
|
-
const oauthResponseType = koffi.struct({
|
|
7
|
-
emails: koffi.array('char*', 10),
|
|
8
|
-
num_emails: 'int',
|
|
9
|
-
token: 'char*',
|
|
10
|
-
error: 'char*'
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
const credResponseType = koffi.struct({
|
|
14
|
-
email: 'char*',
|
|
15
|
-
user_token: 'char*',
|
|
16
|
-
provider: 'char*',
|
|
17
|
-
error: 'char*',
|
|
18
|
-
});
|
|
19
6
|
|
|
20
7
|
const workerInfoType = koffi.struct({
|
|
21
8
|
container_name: 'char*',
|
|
@@ -64,19 +51,13 @@ const deployTargetWrapper = lib.func('deployTargetWrapper', 'string', ['string',
|
|
|
64
51
|
const deleteTargetWrapper = lib.func('deleteTargetWrapper', 'string', ['string', 'string', 'string', 'string', 'string']);
|
|
65
52
|
const runTesterGenerateRestWrapper = lib.func('runTesterGenerateRestWrapper', testerGenerateType, ['string', 'string', 'string', 'string', 'string', 'string', 'string', 'string', 'int', 'bool', 'bool', 'bool']);
|
|
66
53
|
|
|
67
|
-
const generateRestTestWrapper = lib.func('generateRestTestWrapper', 'string', ['string', 'string', 'string', 'string', 'string', 'string', 'string', 'string', 'string', 'int', 'string', 'string', 'string', 'string', 'string', 'string', 'string', 'string', 'bool', 'bool', 'string', 'string', 'string', 'string', 'string', 'string', 'string', 'bool', 'string', '
|
|
68
|
-
const traceCollectWrapper = lib.func('traceCollectWrapper', 'string', ['string', 'string']);
|
|
69
|
-
|
|
70
|
-
// credential / oauth related
|
|
71
|
-
const readCredentialWrapper = lib.func('readCredentialWrapper', credResponseType, []);
|
|
72
|
-
const validateTokenWrapper = lib.func('validateTokenWrapper', 'string', ['string']);
|
|
73
|
-
const registerUserWrapper = lib.func('registerUserWrapper', 'string', ['string', 'string', 'string']);
|
|
74
|
-
const getOAuthURL = lib.func('getOAuthURLWrapper', 'string', ['string', 'int']);
|
|
75
|
-
const runOAuthLoopback = lib.func('runOAuthLoopback', oauthResponseType, ['string', 'int']);
|
|
54
|
+
const generateRestTestWrapper = lib.func('generateRestTestWrapper', 'string', ['string', 'string', 'string', 'string', 'string', 'string', 'string', 'string', 'string', 'int', 'string', 'string', 'string', 'string', 'string', 'string', 'string', 'string', 'bool', 'bool', 'string', 'string', 'string', 'string', 'string', 'string', 'string', 'bool', 'string', 'bool', 'string', 'string', 'string', 'string', 'string', 'string', 'string', 'string', 'bool']);
|
|
55
|
+
const traceCollectWrapper = lib.func('traceCollectWrapper', 'string', ['string', 'string', 'bool', 'string']);
|
|
56
|
+
const analyzeOpenapiWrapper = lib.func('analyzeOpenapiWrapper', 'string', ['string', 'string']);
|
|
76
57
|
|
|
77
58
|
// contract test
|
|
78
59
|
// func sendRequestWrapper(address, namespace, kubePath, kubeContext, clusterName, request, dockerNetwork, workerImage *C.char, localImage bool) *C.char {
|
|
79
|
-
const sendRequestWrapper = lib.func('sendRequestWrapper', contractResponseType, ['string', 'string', 'string', 'string', 'string', 'string', 'string', 'string', 'bool']);
|
|
60
|
+
const sendRequestWrapper = lib.func('sendRequestWrapper', contractResponseType, ['string', 'string', 'string', 'string', 'string', 'string', 'string', 'string', 'string', 'bool']);
|
|
80
61
|
|
|
81
62
|
// dashboard
|
|
82
63
|
const deployDockerDashboardWrapper = lib.func('deployDockerDashboardWrapper', 'string', ['string']);
|
|
@@ -138,7 +119,7 @@ class SkyrampClient {
|
|
|
138
119
|
if (options.k8SConfigPath) {
|
|
139
120
|
this.kubeconfigPath = options.k8SConfigPath;
|
|
140
121
|
}
|
|
141
|
-
}
|
|
122
|
+
}
|
|
142
123
|
|
|
143
124
|
if (this.kubeconfigPath || this.clusterName || this.context) {
|
|
144
125
|
this.addKubeConfig(this.context, this.clusterName, this.kubeconfigPath);
|
|
@@ -146,10 +127,10 @@ class SkyrampClient {
|
|
|
146
127
|
// set default worker image
|
|
147
128
|
if (options.workerImage) {
|
|
148
129
|
this.workerImage = options.workerImage;
|
|
149
|
-
}
|
|
130
|
+
}
|
|
150
131
|
if (options.local_image) {
|
|
151
132
|
this.local_image = options.local_image;
|
|
152
|
-
}
|
|
133
|
+
}
|
|
153
134
|
} else {
|
|
154
135
|
if (kubeconfigPathOrOptions || clusterName || context) {
|
|
155
136
|
this.addKubeConfig(context, clusterName, kubeconfigPathOrOptions);
|
|
@@ -160,89 +141,6 @@ class SkyrampClient {
|
|
|
160
141
|
}
|
|
161
142
|
}
|
|
162
143
|
|
|
163
|
-
setUserToken(userToken) {
|
|
164
|
-
this.userToken = userToken;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
getOAuthURL(provider, port) {
|
|
168
|
-
return getOAuthURL(provider, port);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
getUserEmail() {
|
|
172
|
-
return this.userEmail;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
getUserToken() {
|
|
176
|
-
return this.userToken;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
getUserProvider() {
|
|
180
|
-
return this.userProvider;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
async readCredential() {
|
|
184
|
-
return new Promise((resolve, reject) => {
|
|
185
|
-
readCredentialWrapper.async((err, res) => {
|
|
186
|
-
if (err) {
|
|
187
|
-
reject(err);
|
|
188
|
-
} else if (res) {
|
|
189
|
-
if (res.error != null) {
|
|
190
|
-
reject(res.error);
|
|
191
|
-
} else {
|
|
192
|
-
this.userToken = res.user_token;
|
|
193
|
-
this.userEmail = res.email;
|
|
194
|
-
this.userProvider = res.provider;
|
|
195
|
-
resolve(res);
|
|
196
|
-
}
|
|
197
|
-
} else {
|
|
198
|
-
reject(new Error('failed to read credential'));
|
|
199
|
-
}
|
|
200
|
-
});
|
|
201
|
-
});
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
async runOAuthLoopback(provider, port) {
|
|
205
|
-
return new Promise((resolve, reject) => {
|
|
206
|
-
runOAuthLoopback.async(provider, port, (err, res) => {
|
|
207
|
-
if (err) {
|
|
208
|
-
reject(err);
|
|
209
|
-
} else if (res) {
|
|
210
|
-
resolve(res);
|
|
211
|
-
} else {
|
|
212
|
-
reject(new Error("failed to get oauth token"));
|
|
213
|
-
}
|
|
214
|
-
});
|
|
215
|
-
});
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
async validateToken(userToken) {
|
|
219
|
-
return new Promise((resolve, reject) => {
|
|
220
|
-
validateTokenWrapper.async(userToken, (err, res) => {
|
|
221
|
-
if (err) {
|
|
222
|
-
reject(err);
|
|
223
|
-
} else if (res) {
|
|
224
|
-
resolve(new Error(res));
|
|
225
|
-
} else {
|
|
226
|
-
resolve();
|
|
227
|
-
}
|
|
228
|
-
});
|
|
229
|
-
});
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
async registerUser(provider, email, oauthToken) {
|
|
233
|
-
return new Promise((resolve, reject) => {
|
|
234
|
-
registerUserWrapper.async(provider, email, oauthToken, (err, res) => {
|
|
235
|
-
if (err) {
|
|
236
|
-
reject(err);
|
|
237
|
-
} else if (res) {
|
|
238
|
-
reject(new Error(res));
|
|
239
|
-
} else {
|
|
240
|
-
resolve();
|
|
241
|
-
}
|
|
242
|
-
});
|
|
243
|
-
});
|
|
244
|
-
}
|
|
245
|
-
|
|
246
144
|
/**
|
|
247
145
|
* Applies local changes to the Kubernetes cluster configuration.
|
|
248
146
|
*
|
|
@@ -338,7 +236,7 @@ class SkyrampClient {
|
|
|
338
236
|
* @returns {Promise} - A Promise that resolves if deployment is successful, and rejects with an error if any error occurs during deployment.
|
|
339
237
|
* @throws {Error} - If there is no cluster to deploy the worker to.
|
|
340
238
|
*/
|
|
341
|
-
async deploySkyrampWorker(namespace, workerImage = '', localImage = false, kubePath='', kubeContext='', clusterName='') {
|
|
239
|
+
async deploySkyrampWorker(namespace, workerImage = '', localImage = false, kubePath = '', kubeContext = '', clusterName = '') {
|
|
342
240
|
return new Promise((resolve, reject) => {
|
|
343
241
|
deploySkyrampWorkerWrapper.async(namespace, kubePath, kubeContext, clusterName, workerImage, localImage, (err, res) => {
|
|
344
242
|
if (err) {
|
|
@@ -360,7 +258,7 @@ class SkyrampClient {
|
|
|
360
258
|
* @returns {Promise} - A promise that resolves with no value upon successful deletion.
|
|
361
259
|
* @throws {Error} - If there is no cluster to delete the worker from or if there is no worker to delete from the specified namespace.
|
|
362
260
|
*/
|
|
363
|
-
async deleteSkyrampWorker(namespace, kubePath='', kubeContext='', clusterName='') {
|
|
261
|
+
async deleteSkyrampWorker(namespace, kubePath = '', kubeContext = '', clusterName = '') {
|
|
364
262
|
if (this.kubeConfigPath === null) {
|
|
365
263
|
throw new Error('No cluster to delete worker from.');
|
|
366
264
|
}
|
|
@@ -538,7 +436,7 @@ class SkyrampClient {
|
|
|
538
436
|
const testYamlContent = getYamlBytes(testDescription);
|
|
539
437
|
const stringifiedHeaders = JSON.stringify(globalHeaders);
|
|
540
438
|
|
|
541
|
-
return this.runTesterStartv1(
|
|
439
|
+
return this.runTesterStartv1(namespace,
|
|
542
440
|
kubePath,
|
|
543
441
|
kubeContext,
|
|
544
442
|
clusterName,
|
|
@@ -673,7 +571,7 @@ class SkyrampClient {
|
|
|
673
571
|
|
|
674
572
|
return mockDescription;
|
|
675
573
|
}
|
|
676
|
-
|
|
574
|
+
|
|
677
575
|
/**
|
|
678
576
|
* Generates test scenarios based on the provided parameters.
|
|
679
577
|
*
|
|
@@ -726,7 +624,7 @@ class SkyrampClient {
|
|
|
726
624
|
const req = new RequestV2(options);
|
|
727
625
|
return new Promise((resolve, reject) => {
|
|
728
626
|
const jsonRequest = req.toJson();
|
|
729
|
-
sendRequestWrapper.async(this.address, this.namespace, this.kubeconfigPath, this.context, this.clusterName, jsonRequest, this.dockerNetwork, this.workerImage, this.local_image, (err, res) => {
|
|
627
|
+
sendRequestWrapper.async(this.address, this.namespace, this.kubeconfigPath, this.context, this.clusterName, jsonRequest, this.dockerNetwork, this.workerImage, this.clientID, this.local_image, (err, res) => {
|
|
730
628
|
if (err) {
|
|
731
629
|
reject(err);
|
|
732
630
|
} else if (res) {
|
|
@@ -776,11 +674,39 @@ class SkyrampClient {
|
|
|
776
674
|
});
|
|
777
675
|
}
|
|
778
676
|
|
|
677
|
+
/**
|
|
678
|
+
* Analyzes an OpenAPI schema and URI.
|
|
679
|
+
*
|
|
680
|
+
* @param {Object} options - The options for analysis.
|
|
681
|
+
* @param {string} options.apiSchema - The OpenAPI schema to analyze.
|
|
682
|
+
* @param {string} options.uri - The URI to analyze.
|
|
683
|
+
* @returns {Promise<string>} A promise that resolves with the analysis result.
|
|
684
|
+
*/
|
|
685
|
+
async analyzeOpenapi(options) {
|
|
686
|
+
return new Promise((resolve, reject) => {
|
|
687
|
+
analyzeOpenapiWrapper.async(
|
|
688
|
+
options.apiSchema || "",
|
|
689
|
+
options.uri || "",
|
|
690
|
+
(err, res) => {
|
|
691
|
+
if (err) {
|
|
692
|
+
reject(err);
|
|
693
|
+
} else if (res.error) {
|
|
694
|
+
reject(new Error(res));
|
|
695
|
+
} else {
|
|
696
|
+
resolve(res);
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
);
|
|
700
|
+
});
|
|
701
|
+
}
|
|
702
|
+
|
|
779
703
|
async traceCollect(options) {
|
|
780
704
|
return new Promise((resolve, reject) => {
|
|
781
705
|
traceCollectWrapper.async(
|
|
782
706
|
options.output || "",
|
|
783
707
|
options.workerContainerName || "",
|
|
708
|
+
options.playwright || false,
|
|
709
|
+
options.playwrightOutput || "",
|
|
784
710
|
(err, res) => {
|
|
785
711
|
if (err) {
|
|
786
712
|
reject(err);
|
|
@@ -795,7 +721,6 @@ class SkyrampClient {
|
|
|
795
721
|
}
|
|
796
722
|
|
|
797
723
|
async generateRestTest(options) {
|
|
798
|
-
// TODO: Fix the k8sConfig default value
|
|
799
724
|
return new Promise((resolve, reject) => {
|
|
800
725
|
generateRestTestWrapper.async(
|
|
801
726
|
options.testType || "",
|
|
@@ -818,29 +743,30 @@ class SkyrampClient {
|
|
|
818
743
|
options.responseStatusCode || "",
|
|
819
744
|
options.force || false,
|
|
820
745
|
options.deployDashboard || false,
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
746
|
+
options.formParams || "",
|
|
747
|
+
options.pathParams || "",
|
|
748
|
+
options.queryParams || "",
|
|
824
749
|
JSON.stringify(options.apiSchema || []),
|
|
825
750
|
options.traceFilePath || "",
|
|
826
751
|
JSON.stringify(options.generateInclude || []),
|
|
827
752
|
JSON.stringify(options.generateExclude || []),
|
|
828
753
|
options.generateInsecure || false,
|
|
829
754
|
options.assertOption || "",
|
|
830
|
-
options.
|
|
831
|
-
options.
|
|
832
|
-
options.
|
|
833
|
-
options.
|
|
834
|
-
options.
|
|
835
|
-
options.
|
|
755
|
+
options.playwright || false,
|
|
756
|
+
options.playwrightOutput || "",
|
|
757
|
+
options.playwrightInput || "",
|
|
758
|
+
options.loadCount || "0",
|
|
759
|
+
options.loadDuration || "0",
|
|
760
|
+
options.loadNumThreads || "0",
|
|
761
|
+
options.loadRampupDuration || "0",
|
|
762
|
+
options.loadRampupInterval || "0",
|
|
763
|
+
options.loadTargetRPS || "0",
|
|
836
764
|
options.unblock || false,
|
|
837
765
|
(err, res) => {
|
|
838
766
|
if (err) {
|
|
839
767
|
reject(err);
|
|
840
|
-
} else if (res) {
|
|
841
|
-
reject(new Error(res));
|
|
842
768
|
} else {
|
|
843
|
-
resolve();
|
|
769
|
+
resolve(res);
|
|
844
770
|
}
|
|
845
771
|
}
|
|
846
772
|
);
|
package/src/lib.js
CHANGED
|
@@ -7,18 +7,18 @@ let libPath = '';
|
|
|
7
7
|
|
|
8
8
|
if (platform === 'linux') {
|
|
9
9
|
if (arch === 'x64') {
|
|
10
|
-
libPath = '
|
|
10
|
+
libPath = 'skyramp-linux-amd64.so';
|
|
11
11
|
} else if (arch === 'ia32') {
|
|
12
|
-
libPath = '
|
|
12
|
+
libPath = 'skyramp-linux-386.so';
|
|
13
13
|
}
|
|
14
14
|
} else if (platform === 'darwin') {
|
|
15
15
|
if (arch === 'x64') {
|
|
16
|
-
libPath = '
|
|
16
|
+
libPath = 'skyramp-darwin-amd64.dylib';
|
|
17
17
|
} else if (arch === 'arm64') {
|
|
18
|
-
libPath = '
|
|
18
|
+
libPath = 'skyramp-darwin-arm64.dylib';
|
|
19
19
|
}
|
|
20
20
|
} else if (platform === 'win32') {
|
|
21
|
-
libPath = '
|
|
21
|
+
libPath = 'skyramp-windows-amd64.dll';
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
if (!libPath) {
|
|
Binary file
|