Replicating "Concourse CI" Node Call / Debugging process.stdin Net.socket - node.js

I've built a customer resource using node. The resource code looks okay, but once compiled and placed into Concourse, the "Check" in the resource is failing.
Concourse is not giving any useful information except "Unexpected end of JSON"
I'd like to replicate exactly how Concourse calls the build, but I don't know how to find out what it calls?
My assumption was /opt/resource/check which has #!/usr/bin/env node
so just calling this should be sufficient, but I do not get the same behavior.
What I can determine is that it's hanging on my socket that fetches the params passed via stdIn, code below:
export async function retrieveRequestFromStdin<T extends any>(): Promise<T> {
return new Promise<T>((resolve, reject) => {
let inputRaw = "";
process.stdin.on("data", (chunk) => {
process.stdout.write(chunk);
inputRaw += chunk;
});
process.stdout.write(inputRaw);
process.stdin.on("end", async () => {
try {
const json = JSON.parse(inputRaw) as T;
if (!json.source.server_url.endsWith("/")) {
// Forgive input errors and append missing slash if the user did not honor the docs.
json.source.server_url = `${json.source.server_url}/`;
}
resolve(json);
} catch (e) {
reject(e);
}
});
});
}
This is the check code:
(async () => {
try {
const request: ICheckRequest = await retrieveRequestFromStdin<ICheckRequest>();
// Removed unnecessary items
} catch (e) {
stderr.write(e);
process.exit(1);
}
})();
How do I call a NodeJS script the same way as Concourse, so I can find out exactly what the problem is?
Note, I'm compiling Javascript from Typescript

For a resource check, Concourse will run /opt/resource/check passing in the source information from the resource configuration in on stdin. For example, if you configured the pipeline with:
resources:
- name: resource-name
type: your-new-node-resource-type
source:
server_url: https://someurl.com
the first time check runs, your script would receive this on stdin:
{"source": {"server_url": "https://someurl.com"}}
Your script is then expected to return the "current" version of the resource on stdout. In the example below, I've named the key version-example, but you can name that anything you want. You can also add other keys too if you want. This allows you flexibility in uniquely identifying a version.
[{"version-example": "46"}]
Subsequent calls from Concourse to your check script will also include the latest version it knows about, so continuing the example, the next call will pass this to your script:
{"source": {"server_url": "https://someurl.com"},
"version": {"version-example": "46"}}
Your check script should now return (on stdout) an array of any new versions that it finds in order:
[{"version-example": "47"},
{"version-example": "48"},
{"version-example": "49"}]
For more details, you can check out the official docs, which should also be useful when implementing the in and out scripts.
Taking a quick look at your code, it seems that it's writing stdin twice to stdout, which results in the Unexpected end of JSON message. e.g.:
{"source": {"server_url": "https://someurl.com"}}
{"source": {"server_url": "https://someurl.com"}}

Related

Having trouble importing an async function into another file

I've been working on a Guilded Bot that automatically runs a function after x amount of MS. My goal is to automate this function to check a website for new posts. The issue I'm encountering is when trying to import the function and call on it within another file. None of the recommended methods I've found seem to work. Below is my code.
//relay.ts under ./automations/
async function patchNotes(message:Message) {
}
export { patchNotes }
//The main file in src its called index.ts
import path from "path";
import { BotClient, Client, Message } from "#guildedjs/gil";
const { token, token2 } = require('./config.json');
import { patchNotes } from './automations/relay';
const client = new BotClient({
token: token,
prefix: "/",
});
client.once('ready', () => console.log('Ready! Shut down using "ctrl+c"'));
client.login();
process.on("unhandledRejection", console.log)
//setTimeout(() => console.log(client.commands), 600);
// Automations
patchNotes
setInterval(() => patchNotes, 6000);
Currently, this method doesn't return console errors for both Types and other stuff. But it also doesn't run the code at all? I've tried other methods too but none have worked so far. Below are what packages I'm using.
ts-node "10.8.1"
typescript "4.7.4"
It's running Node.js and all files are written in TS. If you need any more details, I'd be happy to give them. Really hoping to get past this issue instead of just putting the function in my main file.
So I've actually just found the answer. So it seems I can use setInterval with async tasks. Below is the code I use to achieve this.
setInterval(async () => {
await function();
}, delay)
As for my other issue. I've figured out that I could just write client.messages.send instead of putting message. in front of it. Reason I didn't follow the advice of the recent comment is because this function shouldn't have any values returning. The reason I added message: Message is because there is a line in my code that uses "message". Which is the one mentioned above. Shoulda added that to this thread. Thanks for the response though. Resolved.

JSON file can't be modified

I am currently creating a web that uses a variable that I can store in a JSON format. My plan is to modify the value of the JSON every time there's a connection to a certain route. The problem is it just won't write.
I have tried to use fs.writeFile and fs.writeFileSync but none of them seem to work.
// Code I Have tried
const kwitansi = require('./no_kwitansi.json')
app.get('', async (req, res) => {
kwitansi.no_kwitansi += await 1
await fs.writeFile('../no_kwitansi.json', JSON.stringify(kwitansi, null, 2), function (e) {
if (e) {
throw new Error
} else {
console.log('Wrote to file')
}
})
await console.log(kwitansi)
await res.send(kwitansi)
})
// An Example of my JSON File
{
"no_kwitansi":4
}
You are trying to write to a place where you do not have permission. Note that you opened ./no_kwitansi.json, but you are trying to write to ../no_kwitansi.json (one directory back). If you are sure you can replace the original file, remove the extra . in the write line.
If the error persists, you also need to be sure that you have the proper permissions to write the file. If you are using *nix or mac, you can check this link.

Calling http GET requests from ibm cloud functions using nodejs

while developing the cloud function I got the following error.
i created a cloud action and used that action name inside the json response in watson assistance. then once the intent is matched it call the cloud function. I selected nodejs as developing language of the cloud function.
now my real requirement is to call a https get request from that cloud function. for that i need to use nodejs library called node-rest-client.
normally we need to install it by typing "npm install node-rest-client" in the terminal. since there is no terminal in IBM nodejs editor i got, could you please let me know how to do that.
As a substitute i used https library which is already in nodejs package. and wrote the following code in the editor
const https = require('https');
function main() {
https.get('https://f6054382.ngrok.io/webhook/testRequest', (resp) => {
resp.on('data', (d) => {
process.stdout.write(d);
});
});
}
main();
once I type "node init" in local folder and add the above code to index.js file and then run it using the command "node index.js" code works successfully by giving me the expected output from the webservice.
But I do not get that result in IBM nodejs editor
https://console.bluemix.net/openwhisk/details/action/dialogif.psi%2540gmail.com_dev/webhookCall/code
once i save the above code and invoke by clicking the button in right upper i get the successes response in green as follows.
Activation ID:
341d4e5bc81f4e489d4e5bc81f2e4888
Results:
{}
Logs:
[]
could you please help me to sort this out
Thank you
When executing an asynchronous operation, e.g. HTTP request, you need to return a Promise from the action handler. This ensures the platform will block on that asynchronous result before completing the invocation.
function main() {
return new Promise((resolve, reject) => {
https.get('https://f6054382.ngrok.io/webhook/testRequest', (resp) => {
resp.on('data', (d) => {
process.stdout.write(d);
resolve({})
});
});
})
}
The underlying issue is that your code runs asynchronously and does not return a Promise to indicate a result will be available in the future.
I'd suggest to use the request-promises, which comes pre-packaged with OpenWhisk's Node.js runtime.
const request = require('request-promise');
function main(params) {
return request("https://f6054382.ngrok.io/webhook/testRequest").then(response => {
process.stdout.write(response);
});
}

Why does the selenium function elementLocated in node.js throw an error only on Jenkins?

I'm using the function driver.wait(until.elementLocated()) below, written with node.js, as an explicit wait on my Selenium tests to ensure that the pages in my test load properly. When I run the tests from my local CLI they work perfectly, headlessly and with GUI.
const loadMyPage = {
loadThePage: async function(driver) {
try {
await driver.wait(
until.elementLocated(
By.css("div.radio-select span:nth-child(7)")
),
20000
);
} catch (e) {
console.trace(loadMyPage.loadThePage);
throw e;
}
}
However, when I run the tests in Jenkins headlessly I receive the following error every time I use the function elementLocated().
TypeError: Wait condition must be a promise-like object, function, or a Condition object[0m[90m
at Driver.wait (node_modules/selenium-webdriver/lib/webdriver.js:928:13)
at Object.loadMyPage (foobar-tests/page.js:35:20)
at Context.<anonymous> (foobar-tests/foobar.test.js:32:30)
at <anonymous>
Is there anything specific that could cause this error in Jenkins? I have managed to narrow it down to this specific function, elementLocated().
I was able to find a workaround for my issue, however it appears that there is a larger issue at play with selenium. More information on the core issue can be found at https://github.com/SeleniumHQ/selenium/issues/5560.
I updated my explicit wait by passing an additional async function, and this cleared up the problem entirely in Jenkins. Example is below.
loadMyPage: async () => {
//The second async is necessary to run explicit wait functions like the one below.
//This issue is specific to selenium, more information can be found at https://github.com/SeleniumHQ/selenium/issues/5560.
loadThePage: async () {
try {
async driver =>
await driver.wait(
until.elementLocated(
By.css("div.radio-select span:nth-child(7)")
),
10000
);
} catch (e) {
console.trace(loadMyPage.loadThePage);
throw e;
}
}

casperJS - grunt-casper: Running multiple Test-Suites in a loop

Preparation
Hi i am using CasperJS in combination with grunt-casper (github.com/iamchrismiller/grunt-casper) for running automated functional and regression tests in our GUI Development process for verification.
We use it like this, casper runner in gruntfile.js:
casper: {
componentTests: {
options: {
args: ['--ssl-protocol=any', '--ignore-ssl-errors=true', '--web-security=no'],
test: true,
includes: ['tests/testutils/testutils.js']
},
files: {
'tests/testruns/logfiles/<%= grunt.template.today("yyyy-mm-dd-hhMMss") %>/componenttests/concat-testresults.xml': [
'tests/functionaltests/componenttests/componentTestController.js']
}
},
so as it can be seen here we just normally run casper tests with SSL params and calling only ONE Controllerclass here instead of listing the single tests (this is one of the roots of my problem). grunt-casper delivers the object which is in charge for testing and inside every single Controllerclass the tests are included and concatenated....
...now the componentTestController.js looks like the following:
var config = require('../../../testconfiguration');
var urls = config.test_styleguide_components.urls;
var viewportSizes = config.test_styleguide_components.viewportSizes;
var testfiles = config.test_styleguide_components.testfiles;
var tempCaptureFolder = 'tests/testruns/temprun/';
var testutils = new testutils();
var x = require('casper').selectXPath;
casper.test.begin('COMPONENT TEST CONTROLLER', function(test) {
casper.start();
/* Run tests for all given URLs */
casper.each(urls, function(self, url, i) {
casper.thenOpen(url, function() {
/* Test different viewport resolutions for every URL */
casper.each(viewportSizes, function(self, actViewport, j) {
/* Reset the viewport */
casper.then(function() {
casper.viewport(actViewport[0], actViewport[1]);
});
/* Run the respective tests */
casper.then(function() {
/* Single tests for every resolution and link */
casper.each(testfiles, function(self, actTest, k) {
casper.then(function() {
require('.'+actTest);
});
});
});
});
});
});
casper.run(function() {
test.done();
});
});
Here you can see that we running a 3 level loop for testing
ALL URLs given in a JSON config file which are contained in an ARRAY of String ["url1.com","url2.com"....."urln.com"]
ALL VIEWPORT SIZES so that every URL is tested in our desired Viewport resolutions to test the correct Responsibility behaviour of the components
ALL TESTFILES, all testfiles only include a TEST STUB what means, no start, begin or something else, its all in a large Testsourrounding.
MAYBE this is already mocky and can be done in a bette way, so if this is the case i would glad if someone has proposals here, but don't forget that grunt-casper is involved as runner.
Question
So far, so good, the tool in general works fine and the construction we built works as we desired. But the problem is, because all testfiles are ran in a large single context, one failing component fails the whole suite.
In normal cases this is a behaviour i would support, but in our circumstances i do not see any proper solution than log the error / fail the single testcomponent and run on.
Example:
I run a test, which is setUp like described above and in this part:
/* Single tests for every resolution and link */
casper.each(testfiles, function(self, actTest, k) {
casper.then(function() {
require('.'+actTest);
});
});
we include 2 testfiles looking like the following:
Included testfile1.js
casper.then(function () {
casper.waitForSelector(x("//a[normalize-space(text())='Atoms']"),
function success() {
casper.test.assertExists(x("//a[normalize-space(text())='Atoms']"));
casper.click(x("//a[normalize-space(text())='Atoms']"));
},
function fail() {
casper.test.assertExists(x("//a[normalize-space(text())='Atoms']"));
});
});
Included testfile2.js
casper.then(function () {
casper.waitForSelector(x("//a[normalize-space(text())='Buttons']"),
function success() {
casper.test.assertExists(x("//a[normalize-space(text())='Buttons']"));
casper.click(x("//a[normalize-space(text())='Buttons']"));
},
function fail() {
testutils.createErrorScreenshot('#menu > li.active > ul > li:nth-child(7)', tempCaptureFolder, casper, 'BUTTONGROUPS#2-buttons-menu-does-not-exist.png');
casper.test.assertExists(x("//a[normalize-space(text())='Buttons']"));
});
});
So if the assert in testfile1.js fails, everthing failes. So how can i move on to testfile2.js, even if the first fails? Is this possible to configure? Can it be encapsulated somehow?
FYI, this did not work:
https://groups.google.com/d/msg/casperjs/3jlBIx96Tb8/RRPA9X8v6w4J
Almost similar problems
My problem is almost the same like this here:
https://stackoverflow.com/a/27755205/4353553
And this guy here has almost another approach i tried but got his problems too because multiple testsuites ran in a loop occuring problems:
groups.google.com/forum/#!topic/casperjs/VrtkdGQl3FA
MUCH THANKS IN ADVICE
Hopefully I understood what you ware asking - is there a way to suppress the failed assertion's exception throwing behavior?
The Tester's assert method actually allows for overriding the default behavior of throwing an exception on a failed assertion:
var message = "This test will always fail, but never throw an exception and fail the whole suite.";
test.assert(false, message, { doThrow: false });
Not all assert helpers have this option though and the only other solution I can think of is catching the exception:
var message = "This test will always fail, but never throw an exception and fail the whole suite.";
try {
test.assertEquals(true, false, message);
} catch (e) { /* Ignore thrown exception. */ }
Both of these approaches are far from ideal since the requirement in our cases is to not throw for all assertions.
Another short term solution that requires overriding the Tester instance's core assert method is (but is still quite hacky):
// Override the default assert method. Hopefully the test
// casper property doesn't change between running suites.
casper.test.assert =
casper.test.assertTrue = (function () {
// Save original assert.
var __assert = casper.test.assert;
return function (subject, message, context) {
casper.log('Custom assert called!', 'debug');
try {
return __assert.apply(casper.test, arguments);
}
catch (error) {
casper.test.processAssertionResult(error.result);
return false;
}
};
})();
That said, I'm currently looking for a non-intrusive solution to this "issue" (not being able to set a default value for doThrow) as well. The above is relative to Casper JS 1.1-beta3 which I'm currently using.

Resources