Testing Restify services with Mocha-Cakes, and Coffescript, use of done() in async causes timeout issues - testing

I am running into some timing issues with some mocha-cakes test scripts that run against restify services. I'm using the Restify JSON client to issue the calls, which use callbacks rather than promises. I've passed in the done function to my Givens and Whens, so that I can perform the necessary blocking against these async calls, which prevents inconsistent test suite runs (without the dones, it's a tossup which and how many Thens and Ands will pass).
I am moderately skilled with coffescript, and only a novice when it comes to mocha/mocha-cakes, so I am most certainly doing something wrong in my code. Here is an example of a couple of the test cases that are failing:
require 'mocha-cakes'
should = require 'should'
restify = require 'restify'
Feature "Account API",
"In order to have control over structured Account documents",
"as a consumer of investment account information,",
"I need a RESTful service API.", ->
Scenario "GET /account/:userid", ->
client = restify.createJSONClient
url: "http://localhost:8080",
version: "*"
_e1 = null
_r1 = null
_e2 = null
_r2 = null
_d2 = null
# GET non-existent account
Given "I have not yet created the Account", ->
When "I request the Account", (done) ->
client.get "/account/99", (err, req, res, obj) ->
_e1 = err
_r1 = res
done()
err
Then "it should respond with an error", ->
_e1.should.be.ok
And "the status code should be 404", ->
_r1.should.have.status 404
# GET existent account
Given "I have created the Account", (done) ->
client.post "/account", { userId: 1, accountType: 0, accountCategories: [], beneficiaries: [], accountOwner: { firstName: "Test", lastName: "User" } }, (err) ->
done()
err
When "I request the Account", (done) ->
client.get "/account/1", (err, req, res, obj) ->
_e2 = err
_r2 = res
_d2 = obj
done()
err
Then "it should responond with a document", ->
_d2.should.be.ok
And "it should have the userId 1", ->
_d2.userId.should.eql 1
And "it should have an accountOwner property", ->
_d2.accountOwner.should.be.ok
And "the status code should be 200", ->
_r2.should.have.status 200
When I run this, my output is always the following:
c:\Development\Clients\Pensco\AngularJS\Pensco\newaccountwizard.api>mocha
test/AccountAPITests.coffee -r should -R spec --compilers
coffee:coffee-script/register
Feature: Account API
In order to have control over structured Account documents
as a consumer of investment account information,
I need a RESTful service API.
Scenario: GET /account/:userid
◦
- ◊ Given: I have not yet created the Account (pending)
◦
1) When: I request the Account
◦
√ Then: it should respond with an error
◦
√ And: the status code should be 404
◦
2) Given: I have created the Account
◦
3) When: I request the Account
◦
√ Then: it should responond with a document
◦
√ And: it should have the userId 1
◦
√ And: it should have an accountOwner property
◦
√ And: the status code should be 200
6 passing (6s) 1 pending 3 failing
1) Feature: Account API
In order to have control over structured Account documents
as a consumer of investment account information,
I need a RESTful service API.
Scenario: GET /account/:userid ◦ When: I request the Account:
Error: timeout of 2000ms exceeded
at [object Object].<anonymous> (C:\Users\Jon\AppData\Roaming\npm\node_modules\mocha\lib\runnable.js:139:19)
at Timer.listOnTimeout [as ontimeout] (timers.js:110:15)
2) Feature: Account API
In order to have control over structured Account documents
as a consumer of investment account information,
I need a RESTful service API.
Scenario: GET /account/:userid ◦ Given: I have created the Account:
Error: timeout of 2000ms exceeded
at [object Object].<anonymous> (C:\Users\Jon\AppData\Roaming\npm\node_modules\mocha\lib\runnable.js:139:19)
at Timer.listOnTimeout [as ontimeout] (timers.js:110:15)
3) Feature: Account API
In order to have control over structured Account documents
as a consumer of investment account information,
I need a RESTful service API.
Scenario: GET /account/:userid ◦ When: I request the Account:
Error: timeout of 2000ms exceeded
at [object Object].<anonymous> (C:\Users\Jon\AppData\Roaming\npm\node_modules\mocha\lib\runnable.js:139:19)
at Timer.listOnTimeout [as ontimeout] (timers.js:110:15)
Now, I know that my REST calls via client.get/client.post occur almost instantaneously. When I remove the dones, and run without them, with the exception of the first run after restarting my restify service server, usually only the first or second Then/And fails, the rest succeed. There is a timing issue of maybe a few milliseconds, but definitely not 2000ms. I'm curious why my Givens and Whens suddenly start timing out when I throw in the done() calls.
I am pretty sure I am misunderstanding how mocha-cakes is transforming the coffescript Feature->Scenario->Given/When->Then/And/... into describe/it calls. I suspect that somehow the scope within which done applies is larger than it would seem to be given the nature of mocha-cakes script structure...I'm just not sure exactly what that scope is.

I am also not familiar with mocha-cakes. I am using mocha/(lit)coffee to test restify. I have found it convenient to wrap my calls in promises, as latest mocha is promise-aware. Then I don't have to bother with "done". Also note you may need to call res.end() or res.resume() (See this explanation)
For just "GET":
Promise = require('bluebird') # or whatever, I presume
port = 8776 # ditto
getHttpJson = (addr)->
addr = normalizeUrl(addr)
new Promise ( resolve, reject )->
req = http.get(addr, _completeResponse(resolve) )
.on( 'error', reject )
req.end()
General case:
requestHttpJson = (method, addr, data)->
if data?
data = JSON.stringify(data)
urlBits = getUrlBits(addr)
new Promise (resolve, reject)->
req = http.request(
method: method
headers: {
"Content-Type": "application/json" }
hostname: urlBits.hostname
port: urlBits.port
path: urlBits.pathname
, _completeResponse(resolve) )
req.on( 'error', reject )
if data?
req.write( data )
req.end()
postHttpJson = (addr, data)->
requestHttpJson('POST', addr, data)
putHttpJson = (addr, data)->
requestHttpJson('PUT', addr, data)
deleteHttpJson = (addr, data)->
requestHttpJson('DELETE', addr, data)
Break down address into components and add defaults. ("port" is a module global.)
getUrlBits = (addr)->
bits = url.parse(addr)
bits.port = bits.port || port
bits.hostname = bits.hostname || 'localhost'
bits.protocol = bits.protocol || 'http'
return bits
normalizeUrl = (addr)->
url.format(getUrlBits(addr))
Utility to parse body of request & resolve.
_completeResponse = (resolve)->
(res)->
body = []
res.on 'data', (data)->
body.push data
res.on 'end', ->
body = body.join ''
content = if body == '' then null else JSON.parse(body)
resolve([res,content])

Related

Provider Error : Provider : Transaction Reverted without Reason String

We have been working on Document Signing App which sends an email when a user uploads a document and sends it to sign to another 3-4 users.
The user gets the email and tries to sign the document which does a blockchain transaction whose status is always failed.
We have been trying to debug this but unfortunately we haven’t any details lately, We have tried various codes but no changes have changed the status of transaction.
Our System Details :
Provider : Alchemy
Network : Goerli / Localhost ( Hardhat node )
Local Dev : Hardhat
We also tried to use hardhat console.sol but we could not get any logs in the contract when using Hardhat node, No logs were printed using npx hardhat test.
We have been facing this problem since almost a week now and the transaction is stil failing.
Snapshot of Local Error :
ProviderError: Error: Transaction reverted without a reason string
at HttpProvider.request (node_modules/hardhat/src/internal/core/providers/http.ts:78:19)
at GanacheGasMultiplierProvider.request (node_modules/hardhat/src/internal/core/providers/gas-providers.ts:312:34)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
Smart Contract that is failing in actual transaction :
function sign(bytes32 hash, bytes32 signatureHash, address signer) public {
console.log("Entered Sign Function");
require(checkDoc(hash),"check doc failed");
require(documents[hash].signers[signer] == 1, "signer failed");
documents[hash].remainingSignatures--;
documents[hash].signers[signer] = block.timestamp;
emit Signature(hash, signatureHash, signer, 'Signature');
if (documents[hash].remainingSignatures == 0){
documents[hash].status = currentState.signed;
emit Signed(hash, 'Signed');
}
Require is not the issue because when we comment out require statements the transaction is still failing.
Code for Test case that is failing :
it("Signing contract", async function () {
const DocumentSigning = await ethers.getContractFactory("DocumentSigning");
const document_signing = await DocumentSigning.deploy();
const transactionOptions = {
gasLimit: 2500000
}
await document_signing.sign("0x46742b637a5c1d01460033c3bd178d1fafe78e0dffa5d2d1841dcccaf70d30a9", "0xef02795fa1b0c97abe843fb461b4625a6a24662bff227862d7d292c9fc69c1ab", "0x07906aae1204f6f3b81673562db7776af9acf83c", transactionOptions);
});
});
The values for test cases have been hardcoded for now to test the actual transaction flow.
Can some help on this as soon as possible?
Adding link to a sample transaction that failed :
https://goerli.etherscan.io/tx/0x4c1665f793541846457a27467236d5fccca63588be3064c78682f666393adc74

Junit assertions don't work when called inside a Javalin handler

I have this test that launches a service at port 7000 and inside the only endpoint I do a failing assertion:
#Test
fun `javalin assertion should fail`() {
Javalin.create()
.get("/") { assertTrue(false) }
.start()
newHttpClient().send(
HttpRequest.newBuilder()
.uri(URI.create("http://localhost:7000/"))
.GET().build(),
discarding()
)
}
The problem is that the test always passes (but it should fail):
(same behavior happens by running ./gradlew test)
... even though there's a console output claiming that a test failed:
[Test worker] INFO io.javalin.Javalin - Listening on http://localhost:7000/
[Test worker] INFO io.javalin.Javalin - Javalin started in 356ms \o/
[qtp2100106358-22] ERROR io.javalin.Javalin - Exception occurred while servicing http-request
org.opentest4j.AssertionFailedError: expected: <true> but was: <false>
at org.junit.jupiter.api.AssertionUtils.fail(AssertionUtils.java:55)
..
Probably, it's being run in another thread, but I wonder if there's a way to attach it to the same context.
(Weirdly, in another scenario in my app - that I couldn't isolate - it properly fails.)
TLDR
To make the test fail as you'd expect, add an assertion on the response you get from your Javalin instance.
#Test
fun `javalin assertion should fail`() {
Javalin.create()
.get("/") { assertTrue(false) } // or any expression that throws an Exception, like Kotlin's TODO()
.start()
val javalinResponse: HttpResponse<Void> = newHttpClient().send(
HttpRequest.newBuilder()
.uri(URI.create("http://localhost:7000/"))
.GET().build(),
discarding()
)
assertThat(javalinResponse.statusCode()).isEqualTo(200) // will fail with Expected: 200, Actual: 500
}
Details
There're two distinct steps in the test: new Javalin instance configuration + build, and calling that instance with a HttpClient.
In Javalin configuration + build step it gets instructed to do assertTrue(false) when called on the / endpoint. assertTrue(false) will throw an AssertionFailedError, but the behavior will be the same if you throw something else there. Now, as many (all?) other webservers, Javalin / Jetty will try to catch any uncaught exceptions that happen within it and return a HTTP response with code 500 (Internal Server Error).
Indeed, this all happens in another thread, as internally a Jetty webserver instance is being launched, which does the port listening, HTTP request / response handling and other important stuff.
So when later in the test an HTTP call is performed to the new Javalin instance, it gets the 500 (Internal Server Error) response successfully, and as originally there are no assertions on the response and there were no uncaught exceptions, the test is deemed successful.
Never do assertions inside the Javalin handler, because if the test fails, the JUnit exception is swallowed by Javalin and the test fails silently (better explained in the other answer). The solution is to make an assertion outside, in the end, as in the Arrange, Act, Assert pattern.
How? You store what you want to assert inside the handler and assert it later. For example, if it's a POST.
var postedBody: String? = null
fakeProfileApi = Javalin.create().post("profile") {
postedBody = it.body()
}.start(1234)
val profileGateway = ProfileGateway(apiUrl = "http://localhost:1234")
profileGateway.saveProfile( // contains the HTTP POST
Profile(id = "abc", email = "john.doe#gmail.com".toEmail())
)
JSONAssert.assertEquals(
""" { "id": "abc", "email": "johndoe#gmail.com" } """,
postedBody, true
)
If it's a GET, it's easier:
fakeProfileApi = Javalin.create().get("profile/abc") {
it.result(""" {"id": "abc", "email": "johndoe#gmail.com"} """)
}.start(1234)
val profileGateway = ProfileGateway(apiUrl = "http://localhost:1234")
val result = profileGateway.fetchProfile("abc") // contains the HTTP GET
assertEquals(
Profile(id = "abc", email = "john.doe#gmail.com".toEmail()),
result
)
More info: Unit testing a gateway with Javalin

How to fix "The OAuth client was not found" error from a Bing Ads script

We've got scripts on Bing to automatically adjust ad bids based on ad performance and client goals, which are stored in a Google spreadsheet.
We had a contractor set this up initially, and it worked. But I guess that the contractor was using a temp Google account and when it went away the bidders stopped working. Because it did work before, it's likely a configuration error on my part that's breaking it now, but the contractor pointed us to the steps I was already following to no avail (https://learn.microsoft.com/en-us/advertising/scripts/examples/authenticating-with-google-services#option2).
Stuff already tried
double checked for errant whitespace around the client ID and client secret
created new client secrets
created new client IDs
made sure that the project name, application name, and OAuth client id name were all the same
created whole new projects from scratch (configured to match the article cited above) to see if that would kick something loose
tried a different token URL (https://oauth2.googleapis.com/token) that appears in the client_secret JSON downloaded from Google
function main() {
const credentials = {
accessToken: '',
client_id: 'REDACTED.apps.googleusercontent.com', // from Google developer console
client_secret: 'REDACTED', // from Google developer console
refresh_token: 'REDACTED' // created at https://developers.google.com/oauthplayground
};
var access_token = '';
if (credentials.accessToken) {
access_token = credentials.accessToken;
}
var tokenResponse = UrlFetchApp.fetch('https://www.googleapis.com/oauth2/v4/token', { method: 'post', contentType: 'application/x-www-form-urlencoded', muteHttpExceptions: true, payload: { client_id: credentials.clientId, client_secret: credentials.clientSecret, refresh_token: credentials.refreshToken, grant_type: 'refresh_token' } });
var responseCode = tokenResponse.getResponseCode();
var responseText = tokenResponse.getContentText();
if (responseCode >= 200 && responseCode <= 299) {
access_token = JSON.parse(responseText)['access_token'];
}
throw responseText;
// use the access token to get client targets from the spreadsheet
A JSON encoded access token is the expected response, but instead, we get HTTP 400 with the message "The OAuth client was not found."
Manually creating an access token on the OAuth playground (https://developers.google.com/oauthplayground) works as a stopgap, but this should work. This has worked. :P
The fix in this case switching the Application Type on console.developers.google.com > Credentials > OAuth consent screen to Internal instead of Public.
That wasn't in the steps provided by Microsoft, and I'm not sure if that will have implications down the road, but at least we're off the manual process for now.

Android publisher permission Denied only check payment(other api successfully)

I'm trying to call api Purchases.products: get to verify your purchase
it yields such a result
{
"error": {
"errors": [
{
"domain": "androidpublisher",
"reason": "permissionDenied",
"message": "The current user has insufficient permissions to perform the requested operation."
}
],
"code": 401,
"message": "The current user has insufficient permissions to perform the requested operation."
}
}
the project is tied properly
A new service account with owner rights has been created
This service account has been granted rights in the google play console
Documentation here says what you can do
the received token does not work only for purchase checks for any other api it returns the result(Inappproducts: list is work)
The verification url is built right because if you get a token client to server then this api works too - but I need a server to server auth
scopes = ['https://www.googleapis.com/auth/androidpublisher']
authorization = Google::Auth.get_application_default(scopes)
uri = "https://www.googleapis.com/androidpublisher/v3/applications/#{ENV['ANDROID_PACKAGE_NAME']}/purchases/products/#{purchasable.purchase_uuid}/tokens/#{purchase_token}?access_token=#{authorization.fetch_access_token!['access_token']}"
response = RestClient::Request.execute method: :get,
url: uri,
headers: {'Content-Type':'application/json'}
and
file = File.read('config/google_key.json')
values = JSON.parse(file)
oauth = Signet::OAuth2::Client.new(
issuer: values[:client_email]",
audience: "https://www.googleapis.com/oauth2/v4/token",
scope: "https://www.googleapis.com/auth/androidpublisher",
client_id: values[:client_id],
signing_key: OpenSSL::PKey::RSA.new(values[:private_key]),
)
jwt = oauth.to_jwt
url = "https://www.googleapis.com/oauth2/v4/token"
begin
response = RestClient::Request.execute method: :post,
url: url,
headers: {'Content-Type': 'application/json'},
payload: {
grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
assertion: jwt
}
result = JSON.parse response.body
rescue => e
puts e.response.to_str
result = JSON.parse(e.response.to_s)
end
I expect this result
update 1
add tokeninfo
I love google.
after 7 days with my first service account it worked - but 7 days !!!! 7 days !!!! it's just horror
Guys in Google you need 7 days to give access to api!! - this is ridiculous
Okay, you need to do this to get access
create service account in google cloud (admin rights)
create google play console and link project google cloud
add email service account in google play console
after 1 week it will work

How is everyone going about implementing scheduled jobs / cloud jobs on parse-server?

According to the parse-server migration guide we could use something like Kue and Kue-UI to emulate the parse.com scheduled jobs functionality.
I haven't implemented Kue or Kue-ui, but looking at the guides, it doesn't look like it provides anywhere close to the same level of functionality as the existing parse.com scheduled jobs. Is this observation correct? Has someone implemented this? Is it true that jobs have to be scheduled through Kue in javascript and Kue-ui only provides a summary of the current status of the jobs and new schedules can't be added through Kue-ui?
Has anyone tried to achieve the same outcome with something like Jenkins? So this is what I had in mind:
each job would still be defined in the cloud code Parse.Cloud.job("job01", function(request, response) {));
modify parse-server slightly to expose job at a similar url to existing cloud functions e.g. /parse/jobs/job01 (this might exist in parse-server soon: github.com/ParsePlatform/parse-server/pull/2560)
create a new jenkins job do a curl at that url
define a cron like schedule for that jenkins job from within the jenkins web ui
I can see the benefits being:
little to no coding
setting up jenkins sounds like much less work then setting up kue, redis and kue-ui
existing cloud job / definitions stay exactly the same
schedule and manually trigger jobs through the jenkins web ui
The only thing that the current parse.com schedule jobs / cloud jobs can do that a jenkins based solution can't is being able to select a job name to create a new schedule for from a drop down list.
Am I missing something? How is everyone else going about this? Thanks.
I ended up doing this with ´node-schedule´. Not sure if it is the best option but it is working fine for me.
index.js
var schedule = require('node-schedule');
var request = require('request');
schedule.scheduleJob('*/15 * * * *', function() {
var options = {
url: serverUrl + '/functions/{function name}}',
headers: {
'X-Parse-Application-Id': appID,
'X-Parse-Master-Key': masterKey,
'Content-Type': 'application/json'
}
};
request.post(options, function (error, response, body) {
if (!error && response.statusCode == 200) {
console.log(body);
}
});
});
main.js
Parse.Cloud.define('{function name}', function(req, res) {
//Check for master key to prevent users to call this
if (req.master === true) {
//Do operations here
} else {
res.error('Need Master Key');
}
});
I use kue for this purpose. I've described the appoach in my article. In short, this function:
Parse.Cloud.job("sendReport", function(request, response) {
Parse.Cloud.httpRequest({
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
url: "https://example.com/url/", // Webhook url
body: "body goes here",
success: function(httpResponse) {
console.log("Successfully POSTed to the webhook");
},
error: function(httpResponse) {
console.error("Couldn't POST to webhook: " + httpResponse);
}
});
});
becomes this:
// Create a kue instance and a queue.
var kue = require('kue-scheduler');
var Queue = kue.createQueue();
var jobName = "sendReport";
// Create a job instance in the queue.
var job = Queue
.createJob(jobName)
// Priority can be 'low', 'normal', 'medium', 'high' and 'critical'
.priority('normal')
// We don't want to keep the job in memory after it's completed.
.removeOnComplete(true);
// Schedule it to run every 60 minutes. Function every(interval, job) accepts interval in either a human-interval String format or a cron String format.
Queue.every('60 minutes', job);
// Processing a scheduled job.
Queue.process(jobName, sendReport);
// The body of job goes here.
function sendReport(job, done) {
Parse.Cloud.httpRequest({
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
url: "https://example.com/url/", // Webhook url
body: "body goes here"}).then(function(httpResponse) {
console.log("Successfully POSTed to the webhook");
// Don't forget to run done() when job is done.
done();
}, function(httpResponse) {
var errorMessage = "Couldn't POST to webhook: " + httpResponse;
console.error(errorMessage);
// Pass Error object to done() to mark this job as failed.
done(new Error(errorMessage));
});
}
It works fine, though I noticed that sometimes kue-scheduler fires the event more often than needed. See this issue for more info: https://github.com/lykmapipo/kue-scheduler/issues/45
If you are on AWS this may be an option:
Create a AWS CloudWatch Event Rule that is triggered at specific intervals and calls a Lambda function. The Event Rule can pass parameters to the Lambda function.
Create a simple Lambda function that calls a Cloud Code function / job. If you receive the cloud code function name and other parameters from the Event Rule, you only need one generic Lambda function for any Cloud Code call.
This has several advantages as Event Rules are part of AWS infrastructure and can be easily integrated with other AWS services. For example, you can set up intelligent queueing of Event Rule calls so that if the previous call did not complete yet, you discard the next call in the queue, overflow to another queue, notify an operator, etc.
You can use the parse-server-scheduler npm-module.
It does not require any external server and simply allows you to setup scheduling in parse-dashboard.