How to log correctly with Mocha/Velocity (Meteor testing)? - testing

What's the correct way to go about logging out information about tests using the velocity framework with Meteor?
I have some mocha tests that I'd like to output some values from, I guess it'd be good if the output could end up in the logs section of the velocity window... but there doesn't seem to be any documentation anywhere?

I haven't seen it documented either.
I don't know how to log messages into the Velocity window, though I don't like the idea of logging into the UI.
What I've done is created a simple Logger object that wraps all of my console.{{method}} calls and prevents logging if process.env.IS_MIRROR. That will only output test framework messages on the terminal. If I need to debug an specific test, I activate logging output for a while on Logger.

This is a terrible hack. It will expose an unprotected method that writes to your DB.
But it works.
I was really annoyed to lack this feature so I digged into the Velocity code to find out that they have a VelocityLogs collection that is globally accessible. But you need to access it from your production, not testing, instance to see it in the web reporter.
So it then took me a good while to get Meteor CORS enabled, but I finally managed - even for Firefox - to create a new route within IronRouter to POST log messages to. (CORS could be nicer with this suggestion - but you really shouldn't expose this anyway.)
You'll need to meteor add http for this.
Place outside of /tests:
if Meteor.isServer
Router.route 'log', ->
if #request.method is 'OPTIONS'
#response.setHeader 'Access-Control-Allow-Origin', '*'
#response.setHeader 'Access-Control-Allow-Methods', 'POST, OPTIONS'
#response.setHeader 'Access-Control-Max-Age', 1000
#response.setHeader 'Access-Control-Allow-Headers', 'origin, x-csrftoken, content-type, accept'
#response.end()
return
if #request.method is 'POST'
logEntry = #request.body
logEntry.level ?= 'unspecified'
logEntry.framework ?= 'log hack'
logEntry.timestamp ?= moment().format("HH:mm:ss.SSS")
_id = VelocityLogs.insert(logEntry)
#response.setHeader 'Access-Control-Allow-Origin', '*'
#response.end(_id)
return
, where: 'server'
Within tests/mocha/lib or similar, as a utility function:
#log = (message, framework, level) ->
HTTP.post "http://localhost:3000/log",
data: { message: message, framework: framework, level: level}
(error) -> console.dir error
For coffee haters: coffeescript.org > TRY NOW > Paste the code to convert > Get your good old JavaScript.

Related

Returning Variable from Feature File With Multiple Scenarios - Karate

We already know that scenarios are run paralelly. But we had the case where we need to return variables from feature files (that are gonna be called from another feature file).
We had multiple scenarios in the feature file as below:
#mutation
Feature: Test GraphQL Create Item
Background:
Given url baseUrl
* configure headers = { Authorization: '#(token)' }
#negative
Scenario: Create item unauthorized
* configure headers = { Authorization: ""}
#Features calling function and others
And match response.errors[0].message == errorUnauthorized
Scenario: Create story authorized
#Features calling function and others
And def idItem = response.data.CreateItem.id
We are reusing the feature file above to obtain variable to be used on another feature file. However it seems that the other feature files fail intermittently complaining the variables obtained from the other feature file is null.
My assumption is that the returned variable is not returned properly since there are more than one scenarios on the feature file. We tried deleting the #negative scenario and have only exactly 1 scenario. Suddenly the intermittent failures gone.
Is there any way to avoid this intermittent failures while still retaining the ability to run scenarios paralelly?
Thanks
Can't say without seeing your code. But you can try using the #parallel=false annotation in the "calling" feature file: https://github.com/intuit/karate#parallelfalse
Otherwise this may be a bug in Karate - so please follow this process: https://github.com/intuit/karate/wiki/How-to-Submit-an-Issue

hubot-auth not authenticating

I have just installed hubot and I'm trying some basic tests.
I have this basic script in /scripts:
module.exports = (robot) ->
robot.respond /myscript status/i, (msg) ->
if robot.auth.hasRole(msg.envelope.user, 'test')
msg.reply "Success"
else
msg.reply "Sorry. Need 'test' role."
I issue the appropriate Slack commands:
schroeder has test role
"OK, schroeder has the 'test' role."
myscript status
"Sorry. Need 'test' role."
I have:
tried to reverse the logic (if vs unless)
verified that the scripts are being updated (by changing responses)
verified that the redis backend is storing the role (connected via redis-cli and inspected the key).
After re-reading all the documentation and looking up bug reports I still cannot see what I'm missing. It has got to be something simple, but I'm out of ideas. It is almost as though the script is not able to view the stored role (hubot-auth can, but my script cannot).
Even though on start, hubot says that it is connecting to a local Redis server:
INFO hubot-redis-brain: Using default redis on localhost:6379
It isn't... At least not in a way that you would expect.
If redis is, in fact running, you should get an extra message:
INFO hubot-redis-brain: Data for hubot brain retrieved from Redis
That message does not appear and there is no warning or error that Redis is not running.
If you have not set up hubot-redis-brain properly, you will get strange errors and inconsistencies, like hubot-auth role check functions failing.
In addition, I found that even after I set Redis up properly, my test script did not work. Even though all the tutorials I found test the msg.envelope.user, this did not work for me. I needed to use the msg.message.user.name and resolve with the brain class:
module.exports = (robot) ->
robot.respond /fbctf status/i, (msg) ->
user = robot.brain.userForName(msg.message.user.name)
if robot.auth.hasRole(user, 'test')
msg.reply "Success"
else
msg.reply "Sorry. Need 'test' role."

JayData oData request with custom headers - ROUND 2

Few month back I was working on some Odata WCF project and I had some problems with parsing custom headers for token auth (apiKey).
At that time, being quite a noob (still am!), I posted this SO question: JayData oData request with custom headers
Today I am working on a new project with Jaydata Odata server and client library and this:
application.context.prepareRequest = function (r) {
r[0].headers['apikey'] = '123456';
};
was working fine till I had to do a MERGE request. I found out that somehow MERGE request was overriding my headers so I investigated further.
It appears at first that in the oDataProvider.js (~line 617) in the _saveRest method the headers are not inherited:
request = {
requestUri: this.providerConfiguration.oDataServiceHost + '/',
headers: {
MaxDataServiceVersion: this.providerConfiguration.maxDataServiceVersion
}
};
but a few lines later we get:
this.context.prepareRequest.call(this, requestData);
which "should" call my own prepareRequest, but doesnt... Instead it still points to:
//Line 11302 jaydata.js
prepareRequest: function () { },
which of course does... nothing! Funnilly enough, when you execute a simple GET the same code supposedly on the same context instance works and points to my prepareRequest override.
I can assert with enough confidence that somehow the context between GET/MERGE is not the same instance. I cant see, however, any place where the context instance is reassigned.
Has anyone got a clue?
PS: this is NOT a CORS issue. My OPTIONS is passing fine and manually feeding the headers in oDataProvider works.
More
I followed the lead on different context instances and found something interesting. calling EntitySet.save() ends up calling the EntityContext constructor. see trace:
$data.Class.define.constructor (jaydata.js:10015)
EntityContext (VM110762:7)
Service (VM110840:8)
storeToken.factory (jaydata.js:14166)
$data.Class.define._getContextPromise (jaydata.js:13725)
$data.Class.define._getStoreContext (jaydata.js:13700)
$data.Class.define._getStoreEntitySet (jaydata.js:13756)
$data.Class.define.EntityInstanceSave (jaydata.js:13837)
$data.Entity.$data.Class.define.save (jaydata.js:9774)
(anonymous function) (app.js:162) // My save()
That explains why I get two different instances...
Hack
Replacing the prepareRequest function direcly in the class definition works, but its ugly!
for now I can cope with this:
$data.EntityContext.prototype.prepareRequest = function (r) {
r[0].headers['apikey'] = '12345';
};
This works fine as long as you only need to talk to a single endpoint.
Final word based on my experience
As much as I like JayData, it is obvious that they created a monster and its getting out of their hands (poor forum, no community, half-documented,...).
I chose JD because I was lazy and wanted to keep working with my old WCF DataService. Switching to Web API seemed wrong or too much work for me.
Also as a .net dev I liked strong typing of my entities and the ability to work with a concrete model generated from the JD tools. However, in the end, I was adding confusion. Every time my server side model changed I had to fetch the new metadata and scaffold a new entityModel.
I ended up by switching to Web Api and migrated my data service layer to Breeze. And seriously! its a breeze to work with it!
The documentation is absolutely brilliant and here on S.O you can always count on Ward or Jay Tarband to reply with a very high amount of professionalism.
In the end I realize this should probably be more a wiki than a Question.....

What is the correct way to launch your server from vows for testing?

I have an express server which I am testing using vows. I want to run the server from within the vows test suite, so that I dont need to have it running in the background in order for the test suite to work, then I can just create a cake task which runs the server and tests it in isolation.
In server.coffee I have created the (express) server, configured it, set up routes and called app.listen(port) like this:
# Express - setup
express = require 'express'
app = module.exports = express.createServer()
# Express - configure and set up routes
app.configure ->
app.set 'views', etc....
....
# Express - start
app.listen 3030
In my simple routes-test.js I have :
vows = require('vows'),
assert = require('assert'),
server = require('../app/server/server');
// Create a Test Suite
vows.describe('routes').addBatch({
'GET /' : respondsWith(200),
'GET /401' : respondsWith(401),
'GET /403' : respondsWith(403),
'GET /404' : respondsWith(404),
'GET /500' : respondsWith(500),
'GET /501' : respondsWith(501)
}).export(module);
where respondsWith(code) is similar in functionality to the one in the vows doc...
When I require server in the above test, it automatically begins running the server and the tests run and pass, which is great, but I dont feel like I am doing it the 'right' way.
I dont have much control over when the server begins, and what happens if I want to configure the server to point to a 'test' environment rather than the default one, or change the default logging level for when im testing?
PS I am going to convert my vows to Coffeescript but for now its all in js as im in learning mode from the docs!
That is an interesting question because exactly last night I did what you want to do. I have a little CoffeScript Node.js app which happened to be written like the one you showed. Then, I refactored it, creating the following app.coffee:
# ... Imports
app = express.createServer()
# Create a helper function
exports.start = (options={port:3000, logfile:undefined})->
# A function defined in another module which configures the app
conf.configure app, options
app.get '/', index.get
# ... Other routes
console.log 'Starting...'
app.listen options.port
Now I have an index.coffee (equivalent to your server.coffee) as simple as:
require('./app').start port:3000
Then, I wrote some tests using Jasmine-node and Zombie.js. The test framework is different but the principle is the same:
app = require('../../app')
# ...
# To avoid annoying logging during tests
logfile = require('fs').createWriteStream 'extravagant-zombie.log'
# Use the helper function to start the app
app.start port: 3000, logfile: logfile
describe "GET '/'", ->
it "should have no blog if no one was registered", ->
zombie.visit 'http://localhost:3000', (err, browser, status) ->
expect(browser.text 'title').toEqual 'My Title'
asyncSpecDone()
asyncSpecWait()
The point is: what I did and I would suggest is to create a function in a module which starts the server. Then, call this function wherever you want. I do not know if it is "good design", but it works and seems readable and practical to me.
Also, I suspect there is no "good design" in Node.js and CoffeScript yet. Those are brand new, very innovative technologies. Of course, we can "feel something is wrong" - like this situation, where two different people didn't like the design and changed it. We can feel the "wrong way", but it does not mean there is a "right way" already. Summing up, I believe we will have to invent some "right ways" in your development :)
(But it is good to ask about good ways of doing things, too. Maybe someone has a good idea and the public discussion will be helpful for other developers.)

Asterisk with new functions

I created a write func odbc list records files in sql table:
[R]
dsn=connector
write=INSERT INTO ast_records (filename,caller,callee,dtime) VALUES
('${ARG1}','${ARG2}','${ARG3}','${ARG4}')
prefix=M
and set it in dialplan :
exten => _0X.,n,Set(
M_R(${MIXMONITOR_FILENAME}\,${CUSER}\,${EXTEN}\,${DTIME})= )
when I excute it I get an error : ast_func_write: M_R Function not registered:
note that : asterisk with windows
First thing I saw was you were performing the call to the function incorrectly...you need to be assigning values, not arguments....try this:
func_odbc.conf:
[R]
dsn=connector
prefix=M
writesql=INSERT INTO ast_records (filename,caller,callee,dtime) VALUES('${VAL1}','${VAL2}','${VAL3}','${VAL4}');
dialplan:
exten => _0X.,1,Set(M_R()=${MIXMONITOR_FILENAME}\,${CUSER}\,${EXTEN}\,${DTIME})
If that doesn't help you, continue on in my list :)
Make sure func_odbc.so is being loaded by Asterisk. (from the asterisk CLI: module show like func_odbc)... If it's not loaded, it can't "build" your custom odbc query function.
Make sure your DSN is configured in /etc/odbc.ini
Make sure that /etc/asterisk/res_odbc.conf is properly configured
Make sure you're calling the DSN by the right name (I see it happen all the time)
enable verbose and debug in your Asterisk logging, do a logger reload, core set verbose 5, core set debug 5, and then try the call again. when the call finishes, review the log, you'll see much more output regarding what happened...
Regarding the answer from recluze...Not to call you out here, but using a PHP AGI is serious overkill here. The func_odbc function works just fine, why create more overhead and potential security issues by calling an external script (which has to use a interpreter program on TOP itself)?
you should call func odbc function as "ODBC_connector". connector should be use in the func_odbc.conf file [connector]. In the dialplan it should call like this.
exten=> _0x.,n,ODBC_connector(${arg1},${arg2})
I don't really understand the syntax you're trying to use but how about using AGI (with php) for this. Just define your logic in a php script and call it from your dialplan as:
exten => _0X.,n,AGI(script-filename.php,${CUSER},${EXTEN},${DTIME})