@kumologica/sdk 3.0.27-beta3 → 3.0.27-beta5

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.
@@ -309,27 +309,12 @@ class TestSuiteController {
309
309
  return flowFileJson.filter((node) => node.type === 'TestCase' || node.type === 'HTTPTestCase');
310
310
  }
311
311
 
312
- async runTestSuite(testcase) {
313
- const flowFileAbsPath = path.join(
314
- this._appServer.settings.userDir,
315
- this._appServer.settings.flowFile
316
- );
317
- let testCases = this.findTestCasesFromFlow(flowFileAbsPath);
318
- if (!testCases || (testCases && testCases.length === 0)) {
319
- logError(`No testcases found on flow file: ${flowFileAbsPath}`);
320
- process.exit(1);
321
- }
322
-
323
- // If defined, filter the testcase that you want to test
324
- if (testcase) {
325
- testCases = testCases.filter(tc => tc.name.toLowerCase() === testcase.toLowerCase());
326
- if (testCases && testCases.length === 0){
327
- logError(`TestCase: "${testcase}" cannot be found`);
328
- process.exit(1);
329
- }
330
-
331
- }
332
-
312
+ /**
313
+ *
314
+ * @param {*} testcasesSelected - array of {id: nodeId, name: nodeName}
315
+ * @returns
316
+ */
317
+ async runTestSuite(testcasesSelected) {
333
318
  // === Starting the testSuite ===
334
319
  this._appServer.events.emit('runtime-event', {
335
320
  id: runtimeEvents.TEST_TESTSUITE_START,
@@ -337,7 +322,7 @@ class TestSuiteController {
337
322
  });
338
323
 
339
324
  // === Iterate over all the testCases ===
340
- await this.runTestCases(testCases);
325
+ await this.runTestCases(testcasesSelected);
341
326
  await this.waitForResults();
342
327
  const errorsNum = this._testReporter.getFailedTestCases().length;
343
328
 
@@ -3,6 +3,7 @@ const { Select } = require('enquirer');
3
3
  const fs = require('fs');
4
4
  const { logError } = require('./utils');
5
5
  const path = require('path');
6
+ const wcmatch = require('wildcard-match');
6
7
 
7
8
  const { AppServer } = require('@kumologica/runtime');
8
9
  const { TestSuiteController } = require('./test-utils/TestSuiteController');
@@ -11,7 +12,7 @@ const { codegen } = require('@kumologica/builder');
11
12
  const log = console.log;
12
13
  const APP_SERVER_PORT = 1990;
13
14
 
14
- async function runTest(flowFilePath, testcase, iterative) {
15
+ async function runTest(flowFilePath, testcaseSelected, iterative) {
15
16
  log(`\n> Starting runtime on port ${APP_SERVER_PORT}...`);
16
17
 
17
18
  let appServer = new AppServer({
@@ -28,24 +29,31 @@ async function runTest(flowFilePath, testcase, iterative) {
28
29
  await appServer.start();
29
30
  log(`> FlowFile to be tested: ${chalk.bold(path.resolve(flowFilePath))} \n`);
30
31
  let testSuiteController = new TestSuiteController(appServer);
31
- let testcasesAvailable = testSuiteController.findTestCasesFromFlow(flowFilePath).map(tc => {
32
- return tc.name;
33
- })
34
- testcasesAvailable.push('Run all TestCases...');
35
- // Iterative ?
36
- // Check if iterative testing has been selected
32
+
33
+ // If testcase is null, default to universal wildcard
34
+ testcaseSelected = testcaseSelected || "**";
35
+
36
+ // Find out all testcases available on the flow
37
+ let testcasesAvailable = testSuiteController.findTestCasesFromFlow(flowFilePath);
38
+ if (!testcasesAvailable || (testcasesAvailable && testcasesAvailable.length === 0)) {
39
+ logError(`No testcases found on flow file: ${flowFileAbsPath}`);
40
+ process.exit(1);
41
+ };
42
+ let testcaseAvailableNames = testcasesAvailable.map(tc=>tc.name);
43
+
44
+ // Capture the testcase from user on iterative mode
37
45
  if (iterative) {
38
46
  const prompt = new Select({
39
47
  name: 'testcase',
40
48
  message: 'What testcase do you want to run?',
41
- choices: testcasesAvailable
49
+ choices: [...testcaseAvailableNames, 'Run all TestCases...']
42
50
  });
43
51
  await prompt.run()
44
52
  .then(tc => {
45
53
  if (tc === 'Run all TestCases...'){
46
- testcase = null;
54
+ testcaseSelected = "**";
47
55
  }else {
48
- testcase = tc;
56
+ testcaseSelected = tc;
49
57
  }
50
58
  })
51
59
  .catch(err => {
@@ -54,15 +62,31 @@ async function runTest(flowFilePath, testcase, iterative) {
54
62
  });
55
63
  }
56
64
 
65
+ // Filter all testcases to be part of the test suite
66
+ const isMatch = wcmatch(testcaseSelected);
67
+ let testCasesSelected = [];
68
+ testcasesAvailable.forEach(async tc => {
69
+ if (isMatch(tc.name)){
70
+ testCasesSelected.push({ name: tc.name, id: tc.id });
71
+ }
72
+ });
73
+
74
+ // Execute the testcasesIds if any, otherwise throw an error
75
+ if (testCasesSelected.length === 0){
76
+ logError(`No matched testcases found`);
77
+ process.exit(1);
78
+ } else {
79
+ const errors = await testSuiteController.runTestSuite(testCasesSelected);
80
+ process.exit(errors > 0);
81
+ }
57
82
 
58
- const errors = await testSuiteController.runTestSuite(testcase); // no need to wait for response
59
- process.exit(errors > 0);
60
83
  } catch (err) {
61
84
  log(
62
85
  chalk.red(
63
86
  `Unexpected error occurred while starting server due to <${err.message}>`
64
87
  )
65
88
  );
89
+ console.log(err);
66
90
  process.exit(1);
67
91
  }
68
92
  }
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "productName": "Kumologica Designer",
4
4
  "copyright": "Copyright 2020 Kumologica Pty Ltd, All Rights Reserved.",
5
5
  "author": "Kumologica Pty Ltd <contact@kumologica.com>",
6
- "version": "3.0.27-beta3",
6
+ "version": "3.0.27-beta5",
7
7
  "description": "Kumologica Designer, harnessing Serverless for your cloud integration needs",
8
8
  "main": "src/app/main.js",
9
9
  "files": [
@@ -65,9 +65,9 @@
65
65
  "license": "Proprietary",
66
66
  "dependencies": {
67
67
  "@electron/remote": "^2.0.8",
68
- "@kumologica/builder": "3.0.27-beta3",
69
- "@kumologica/devkit": "3.0.27-beta3",
70
- "@kumologica/runtime": "3.0.27-beta3",
68
+ "@kumologica/builder": "3.0.27-beta5",
69
+ "@kumologica/devkit": "3.0.27-beta5",
70
+ "@kumologica/runtime": "3.0.27-beta5",
71
71
  "adm-zip": "0.4.13",
72
72
  "ajv": "8.10.0",
73
73
  "aws-sdk": "2.513.0",
@@ -117,6 +117,7 @@
117
117
  "tcp-port-used": "1.0.2",
118
118
  "util": "0.12.1",
119
119
  "when": "3.7.8",
120
+ "wildcard-match": "^5.1.2",
120
121
  "ws": "7.1.1",
121
122
  "xterm": "4.1.0",
122
123
  "xterm-addon-fit": "0.2.1",
@@ -196,8 +196,7 @@ class AWSCFTemplate {
196
196
 
197
197
  } else if (nodes[i].type === 'Lambda') {
198
198
  //arn:aws:lambda:ap-southeast-2:174450237637:function:kumologica-deployments-flow-lambda
199
- console.log(`lambda ${JSON.stringify(lambda)} node ${JSON.stringify(nodes[i])}`)
200
- let lambdaArn = this.handleValue(lambda, nodes[i].LambdaArn);
199
+ let lambdaArn = this.handleValue(lambda, nodes[i].LambdaArn);
201
200
  let lambdaParts = lambdaArn.split(":");
202
201
  let lambdaName = '*';
203
202
 
@@ -220,10 +219,23 @@ class AWSCFTemplate {
220
219
  this.handlePolicy(lambdaRole, `KLSES`, `ses:${nodes[i].operation}`, '*');
221
220
 
222
221
  } else if (nodes[i].type === 'SSM') {
223
- const key = this.handleValue(lambda, nodes[i].Key);
224
- const ssmArn = { "Fn::Sub": `arn:aws:ssm:\${AWS::Region}:\${AWS::AccountId}:parameter/${key}` };
225
- this.handlePolicy(lambdaRole, `KLSSM${key}`, `ssm:${nodes[i].operation}`, ssmArn);
222
+ let key;
223
+ if (nodes[i].operation === "GetParametersByPath") {
224
+ key = this.handleValue(lambda, nodes[i].Path);
225
+ } else {
226
+ key = this.handleValue(lambda, nodes[i].Key);
227
+ }
228
+
229
+ if (key.startsWith('/')) {
230
+ key = key.substring(1);
231
+ }
232
+ const ssmArn = {'Fn::Sub': 'arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/' + key};
233
+ this.handlePolicy(lambdaRole, `KLSSM${new Date().valueOf()}`, `ssm:${nodes[i].operation}`, ssmArn);
226
234
 
235
+ if (nodes[i].operation === "GetParameter" && nodes[i].Key.startsWith("/aws/reference/secretsmanager/")) {
236
+ const smArn = {'Fn::Sub': 'arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:*'};
237
+ this.handlePolicy(lambdaRole, `KLSM${new Date().valueOf()}`, "secretsmanager:GetSecretValue", smArn);
238
+ }
227
239
  } else if (nodes[i].type === 'S3') {
228
240
  let bucketName = this.handleValue(lambda, nodes[i].Bucket);
229
241
  const bucketArn = `arn:aws:s3:::${bucketName}/*`;
@@ -260,6 +272,7 @@ class AWSCFTemplate {
260
272
  if (!params.role) {
261
273
  template.Resources['LambdaRole'] = lambdaRole;
262
274
  }
275
+
263
276
  return template;
264
277
  }
265
278
 
@@ -279,7 +292,6 @@ class AWSCFTemplate {
279
292
  // to determine the value
280
293
  handleValue(lambda, key) {
281
294
  let value;
282
- console.log(`key= ${key}`);
283
295
 
284
296
  if (!key) {
285
297
  return key;
@@ -287,7 +299,6 @@ class AWSCFTemplate {
287
299
  let keyValue = key.replace(/\s+/g, '');
288
300
 
289
301
  if (keyValue.startsWith("env.")) {
290
- console.log(`keyValue= ${keyValue}`);
291
302
  keyValue = keyValue.replace("env.", "");
292
303
  value = lambda.Properties.Environment.Variables[keyValue];
293
304
  if (!value) {
@@ -316,7 +327,6 @@ class AWSCFTemplate {
316
327
  // - updates existing resource policy (if found) with new permissions
317
328
  //
318
329
  handlePolicy(lambdaRole, policyName, operation, id) {
319
- console.log(`policyName: ${policyName}`);
320
330
  policyName = policyName.replace('/', '-').replace('*', 'all');
321
331
  let policy = jp.query(lambdaRole.Properties, `Policies[?(@.PolicyName=='${policyName}')]`);
322
332
 
@@ -373,7 +383,7 @@ class AWSCFTemplate {
373
383
  throw new Error(`Missing Trigger Parameter: SQS url`);
374
384
  }
375
385
  return {
376
- PolicyName: 'KumologicaLambdaSQSPolicy',
386
+ PolicyName: 'KLSQSPolicy'+process.hrtime(),
377
387
  PolicyDocument: {
378
388
  Version: '2012-10-17',
379
389
  Statement: [
@@ -241,7 +241,7 @@ class AWSDeployer {
241
241
  );
242
242
 
243
243
  flowListeners = this.processFlow(nodes);
244
-
244
+
245
245
  const stackDetails = await this.executeStack(
246
246
  settings,
247
247
  params,
@@ -278,7 +278,7 @@ class AWSDeployer {
278
278
  response = await this.runTriggers(params, settings, lambdaArn);
279
279
  if (response) {
280
280
  const url = `https://${response.apiId}.execute-api.${AWS.config.region}.amazonaws.com/${response.stage}`;
281
- this.printSignature(url, flowListeners);
281
+ this.printSignature(url, flowListeners, params);
282
282
  }
283
283
  } catch (error) {
284
284
  this.log(`${this.chalk('redBright', 'Trigger creation failed.')}`);
@@ -288,8 +288,9 @@ class AWSDeployer {
288
288
  return response;
289
289
  }
290
290
 
291
- printSignature(url, s) {
291
+ printSignature(url, s, p) {
292
292
  this.log(' ')
293
+
293
294
  if (s.api && s.api.length > 0) {
294
295
  this.log('API Gateway:');
295
296
  s.api.forEach(a => this.log(` ${(' ' + a.verb.toUpperCase()).slice(-6)} ${url}${a.url}`), this);
@@ -326,10 +327,13 @@ class AWSDeployer {
326
327
  this.log('');
327
328
  }
328
329
 
329
- if (s.sqs && s.sqs.length > 0) {
330
- this.log('SQS URL:');
331
- s.sqs.forEach(a => this.log(` ${a.queueUrl}`), this);
332
- this.log('');
330
+ if (p.events && p.events.length > 0) {
331
+ const sqs = p.events.filter(i => i.source == 'sqs');
332
+ if (sqs && sqs.length > 0) {
333
+ this.log('SQS URL:');
334
+ sqs.forEach(a => this.log(` ${a.url}`), this);
335
+ this.log('');
336
+ }
333
337
  }
334
338
 
335
339
  if (s.alexa && s.alexa.length > 0) {
@@ -588,6 +592,7 @@ class AWSDeployer {
588
592
  if (!params.events[i].stream) {
589
593
  throw Error(`Missing Trigger Parameter: SQS Queue Url.`);
590
594
  }
595
+ params.events[i].url = params.events[i].stream;
591
596
  params.events[i].stream = await this.sqs.getQueueArn(
592
597
  params.events[i].stream
593
598
  );
package/src/app/main.js CHANGED
@@ -314,7 +314,7 @@ ipcMain.on('restart-requested', async (event, msg) => {
314
314
  // reload the nodes available in the palette
315
315
  try {
316
316
  await requestAsync({
317
- uri: `http://127.0.0.1:${PORT}/nodes-reload`,
317
+ uri: `http://127.0.0.1:${RUNTIME_PORT}/nodes-reload`,
318
318
  method: 'POST',
319
319
  json: true,
320
320
  });
@@ -330,7 +330,7 @@ ipcMain.on('modal-node-library:restart-requested', async (event, msg) => {
330
330
  // reload the nodes available in the palette
331
331
  try {
332
332
  await requestAsync({
333
- uri: `http://127.0.0.1:${PORT}/nodes-reload`,
333
+ uri: `http://127.0.0.1:${RUNTIME_PORT}/nodes-reload`,
334
334
  method: 'POST',
335
335
  json: true,
336
336
  });