How to unit test web sockets - JavaScript - javascript

I would like to test web sockets that have been implemented using sockjs.
var sock = new SockJS('http://mydomain.com/my_prefix');
sock.onopen = function() {
console.log('open');
};
sock.onmessage = function(e) {
console.log('message', e.data);
};
sock.onclose = function() {
console.log('close');
};
I goggled and only found this article. This is not good enough because it's making actual connection rather than faking it.
I also tried SO but only found an unanswered question here.
Someone suggested sinonjs but I'm not able to find any decent example.
I'll appreciate if someone can shed some light on this topic.

When you want to unit-test a feature which accesses an external resource, like in your case a websocket server, the usual approach is to use a mock-object to represent the external resource. A mock-object is an object which looks and behaves like the external resource, but doesn't actually access it. Additionally, it can have logging functionality which allows it to report to the test-code if the tested code behaved like expected.
In your case you would create a mock-SockJS object which has all the relevant properties and methods of a normal SockJS object, but its implementation doesn't actually contact a server. It only logs the method calls and returns the expected response an existing server would send.
Then you would refactor the code you want to test so that it doesn't create the socket itself but instead gets a socket object assigned from the outside (this is called "dependency injection" and is a crucial idiom for writing unit-testable code).
In your real code, you assign a real SockJS object. But in your unit-test, you assign your mock-object. After you called your test-methods you can examine the mock-object to check if the unit sent the expected data to the server.

Related

How to prevent invoking 'Meteor.call' from JavaScript Console?

I just noticed that Meteor.call, the concept that prevent user from invoke collection's insert, update, remove method, still able to be invoked from JavaScript console.
For client's example:
// client
...
Meteor.call('insertProduct', productInfo);
...
Here's the server part:
// server
Meteor.methods({
insertProduct: function( productInfo ){
Product.insert(...);
}
})
OK, I know people can't invoke Product.insert() directly from their JavaScript console.
But if they try a little bit more, they'd find out there's Meteor.call() in client's JavaScript from Developer tool's resource tab.
So now they can try to invoke Meteor.call from their console, then try to guessing what should be productInfo's properties.
So I wonder how can we prevent this final activity?
Does Meteor.call done the job well enough?
or I'm missing something important?
Meteor.call is a global function, just like window.alert(). Unfortunately, there is nothing you can do from preventing a user calling Meteor.call. However, you can validate the schema of data and the actual data of what a user is sending. I'd recommend https://github.com/aldeed/meteor-simple-schema (aldeed:simple-schema as the meteor package name) to ensure you don't get garbage data in your project.
As others pointed out, "Meteor.call" can surely be used from the console. The subtle issue here is that there could be a legal user of a meteor app who can in turn do bad things on the server. So even if one checks on the server if the user is legal, that by itself does not guarantee that the data is protected.
This is not an issue only with Meteor. I think all such apps would need to potentially protect against corruption of their data, even through legal users
One way to protect such corruption is by using IIFE (Immediately Invoked Function Expression)
Wrap your module in a IIFE. Inside the closure keep a private variable which stores a unique one time use key (k1). That key needs to be placed there using another route -- maybe by ensuring that a collection observer gets fired in the client at startup. One can use other strategies here too. The idea is to squirrel in the value of k1 from the server and deposit it in a private variable
Then each time you invoke a Meteor.call from inside you code, pass k1 along as one of the parameter. The server in turn checks if k1 was indeed legal for that browser connection
As k1 was stored inside a private variable in the closure that was invoked by the IIFE, it would be quite difficult for someone at the browser console to determine the value of k1. Hence, even though "Meteor.call" can indeed be called from the browser console, it would not cause any harm. This approach should be quite a good deterrent for data corruption
As mentionned by #Faysal, you have several ways to ensure your calls are legit. An easy step to do so is to implement alanning:roles and do role checks from within your method like the following:
Meteor.methods({
methodName: function() {
if (!Roles.userIsInRole(this.userId, 'admin')) {
throw new Meteor.Error(403, 'not authorized);
} else { yourcode });
This way, only admin users can call the method.
Note that you can also check this.connection from within the method and determine if the call comes from the server (this.connection === false) or from the client.
Generally speaking, doing checks and data manipulations from your methods is a nice way to go. Allow/deny are nice to begin with but become really hard to maintain when your collections get heavier and your edge-cases expand.
You cannot block Meteor.call from the console, just like you can't block CollectionName.find().count() from the console. These are global functions in meteor.
But there are simple steps you can take to secure your methods.
Use aldeed:simple-schema to set the types of data your collection can accept. This will allow you to set the specific keys that your collection takes as well as their type (string, boolean, array, object, integer) https://github.com/aldeed/meteor-simple-schema
Ensure that only logged in users can update from your method. Or set global Allow/Deny rules. https://www.meteor.com/tutorials/blaze/security-with-methods && https://www.discovermeteor.com/blog/allow-deny-a-security-primer/
Remove packages insecure and autopublish
The simple combo of schema and allow/deny should do you just fine.
As you know by now that you can't really block calling Meteor.call from Javascript console, what i'd like to add as a suggestion with #Stephen and #thatgibbyguy that, be sure to check your user's role when adding documents into the collection. Simple-Schema will help you prevent inserting/updating garbage data into the collection. and alanning:roles package certainly makes your app secure by controlling who has the permission to write/read/update your collection documents.
Alanning:roles Package

Meteor.call (Meteor.methods) seem to run on both client and server--causing issues

I execute Meteor.call from the client side to a Meteor.methods method and as I console.log things, they are logged in both the command prompt and the browser console.
The issue with this is that it actually seems to be executing on the client side--which does not have access to the proper entities. While I get no errors on the command prompt, here's what is shown on the client side:
Exception while simulating the effect of invoking 'createInvite'
Meteor.makeErrorType.errorClass {error: "not-found", reason:
"evaluator_invite__entity_not_found", details: undefined, message:
"evaluator_invite__entity_not_found [not-found]", errorType:
"Meteor.Error"…} Error: evaluator_invite__entity_not_found [not-found]
at Meteor.methods.createInvite (http://localhost:3000/lib/collections/invites.js?505cdea882e0f829d521280c2057403ec134b075:38:15)
Is it actually running on the client side? Should this error be there?
Meteor methods are expected to run on both environments if defined globally, this allows for a nice feature which is called latency compensation.
The whole latency compensation concept is off topic but basically it means simulating client-side what the server would actually do like inserting documents in the database right-away to design fluid UX. You're essentially predicting server behavior before it's even happening to make your client experience ultra-responsive by eliminating network latency.
An example of this might be inserting a comment in the database immediately after the user submitted it. In this case the Meteor method calls getting executed on both the server and the client will share the same code.
Sometimes it makes absolutely no sense to provide a client-only simulation - or "stub" - when designing a method responsible for sending emails for example.
Some other times it makes sense to share some part of the code but you need to access environment specific objects : for example a method to insert comments might use Email.send on the server to notify an author a comment has been added on his post.
Meteor.methods({
insertComment: function(comment){
check(comment, [...]);
if(! this.isSimulation){
Email.send([...]);
}
return Comments.insert(comment);
}
});
Ultimately, you have to structure your code differently depending on how your method is supposed to behave.
For server-only methods, define them under the server directory, with no client-side counterpart.
For shared methods that can share exactly the same code on both environments, just define them globally.
For shared methods that just slightly differ, you can use Meteor.isClient / Meteor.isServer or method only property isSimulation to check against the current environment and execute specific code accordingly.
For shared methods that share little to no code, I personally use a pattern where I define the Meteor method on both client and server environment and take care of shared behavior like checking arguments validity, then I call a function responsible for actually implementing the correct behavior.
lib/method.js
Meteor.method({
method: function(args){
check(args, [...]);
//
return implementation(args);
}
});
The trick is to define the implementation separately on client and server, depending on the context, the correct function will get called.
client/method.js
implementation = function(args){
// define your client simulation / stub
};
server/method.js
implementation = function(args){
// define your server implementation
};
Read how to structure your app: http://docs.meteor.com/#/full/structuringyourapp
If you want your methods to be run only on the server, put files with methods into server folder.
If you want latency compensation you can use conditionals in your methods:
Meteor.methods({
method1: function() {
if (Meteor.isClient) {
//Do client side stuff
}
if (Meteor.isServer) {
//Do server side stuff
}
}
});

In Meteor, how can i identify connection / a user of a site on the server, regardless of whether or not they're logged in?

How can i identify a specific connection on the server in Meteor. Similar to what you could accomplish with Session on the client - somewhere to put data related to the current connection.
Sort of like this issue, but on the server, not the client.
I can see that the Meteor Accounts package uses the following code in the Meteor.userId method:
var currentInvocation = Meteor._CurrentInvocation.get();
if (!currentInvocation)
throw new Error("Meteor.userId can only be invoked in method calls. Use this.userId in publish functions.");
But when I try to use Meteor._CurrentInvocation in my code, it is undefined, rather than a Meteor.EnvironmentVariable object, as implied in the livedata package. And, as evidenced by the prefixing underscore, it's a private API, and should probably be avoided in general application code ;)
Any help would be greatly appreciated!
OK - i was overcomplicating the issue, and coming at it from completely the wrong direction.
The context of any Meteor.method calls has a connection property as described here. This connection property is described here, and can be used to persist data across method calls for the duration of the connection.
It is accessible in publish functions and Meteor.methods methods.

Prevent return until condition is met

I know these types of question come up fairly often, but I need help with a wait-like mechanism in JavaScript. I know setTimeout-based solutions are going to come up, but I'm not sure how to pull it off in my case.
I'm writing an API that uses a WebSocket internally. There's a connect() method that sets up the WebSocket, and I need to make it not return until after the WebSocket is set up. I'd like it to return a value for whether or not the connection was successful, but that's not the main problem.
The issue I'm hitting is that after a user calls connect(), they may call another method that relies on the WebSocket to be properly set up. If it's called too early, an error is thrown stating that the object is not usable.
My current solution is setting a "connected" flag when I've determined a successful connection and in each method checking for it in each method. If it's not connected, I add the method call to a queue that is ran through by the same code that sets the flag. This works, but it introduces that style of code all over my methods and also seems misleading from the user-perspective, since the call of those functions is deferred. Also, if there is other user code that relies on those calls being completed before it gets to them, it won't behave as expected.
I've been racking my brain with how to handle this case. The easiest solution is to just find a way to block returning from connect until after the WebSocket is set up, but that's not really the JavaScript way. The other option was to make them provide the rest of their code in a callback, but that seems like a weird thing to do in this case. Maybe I'm over-thinking it?
Edit: To better illustrate my problem, here's a example of what the user could do:
var client = new Client(options);
client.connect();
client.getServerStatus();
The getServerStatus() method would be using the WebSocket internally. If the WebSocket is not set up yet, the user will get that not usable error.
Todays Javascript does not really work like that unfortunately. In the future (ECMA6) there may be new language features that address this issue more directly. However for now you are stuck with the currently accepted method of handling asynchronous events, which is limited to callbacks. You may also want to explore 'promises' to handle 'callback hell' however you will need a library for this.
And yes it does seem strange to have callbacks everywhere, especially for someone new to web programming, however it is really the only way to go about it at this stage (assuming you want a cross-browser friendly solution).
"Wait" is almost the keyword you are looking for. Actually, it's yield that does this. See e.g. MDN's documentation.
There's a connect() method that sets up the WebSocket, and I need to make it not return until after the WebSocket is set up
That isn't going to happen unless you rewrite the javascript execution engine.
Either the code trying to send data will need to check the socket state (I'd go with encapsulating the socket in a object, supplying a method which sets a member variable on the open/close events and poll the state of that member variable from the external code). Alternatively you could add messages and call backs to a queue and process the queue when the socket connects.

Where are the `req` and `res` coming from?

NOTE: This question has very little jQuery, Drupal, or node.js it's more of a generic question on "how frameworks achieve X, where X is something any of the frameworks I mentioned also provides.
I saw an example node.js code that looks like this:
var http = require('http');
var server = http.createServer();
server.listen(8000);
server.on('request', function(req, res) {
//do something with req and res here
});
There is no obvious place where req and res are coming from. In fact, what does 'request' mean? Where is it supplied from?
I have noticed similar things in jQuery .get() and .post() functions, and looking at the source did not help as much as I would like. I've even seen this being done in Drupal; a function is defined in the theme layer or as a module_hook with specific naming conventions by me, but arguments appear outta nowhere and there is a predictable structure of data (specified in the manual) inside those magic variables.
So what is this technique called, and how does it work. I've heard tell of Dependency Injection... is this it? If it is, could you explain in n00b terms how it is accomplished?
This is particularly confusing because I coded in procedural from the start, and we always know where a variable is coming from and how a function is being called...
The framework constructs the objects for you, and passes them to your callback.
N.B. req and res are just parameter names; you could call them spam and eggs, or hocus and pocus, for all it matters.
In fact, what does request mean? Where is it supplied from?
Whenever you want to access a web site, you're using a special protocol, the hypertext transfer protocol (HTTP). This protocol mainly uses two things:
a question from the client like "what is / on your server?" (the request)
an answer from the server like "it's a text/html, the length is 2000 bytes, and here is the document" (the response).
This request-response model is used directly in node.js, as the server you're using is a HTTP server.
[...] could you explain in n00b terms how it is accomplished?
Do you know what a main-loop or event-loop is? Almost every GUI application has one. It's basically a loop like this:
while(waitForNewEvent(&event)){
handleMsg(&event);
}
This event can be anything, from keyboard input to another software trying to bring your window to front. It can also be something like "are you ready for standby?".
node.js uses such a event-loop in it's server implementation. server.on('request', callback) basically tells node.js that you want callback to be used whenever a request is coming:
while(waitForNewEvent(&event)){
if(event == "request"){
callback(request,&response);
responseToClient(response);
}
}
Intern example
Or even simplier: think of a intern, who's just running around in circles in a building. He's the event-loop. Now in your server room someone tells him that every request should be brought to them. He writes this down and continues on his never-ending tour.
Then someone stands in front of the building and wants to check his bank-account. He simply throws a request into a post box and the intern rushes to the server room and tells the technicians that the specific site has been requested and gives them the necessary information. However, he needs to wait on their response, since their response isn't on his list.
The technicians check the request and find out that the user isn't qualified for the given request(*). They prepare an error message and give it to the intern. He now returns to the front of the building, gives the error message to the first client and is ready for other messages.
(*): At this point they might need to check something in a database, which might take some time. They could tell the intern to come back later and call him if they're ready. In this case the intern could continue his way until the technicians are ready.
You're passing the function to the .on() function. When the event occurs, some internal code invokes the function you passed, and provides the arguments to it.
Here's an example. The server object has a method named on. It takes a name string and a callback function.
It uses setTimeout to wait one second before invoking the callback it was given. When it invokes it, it passes to it the name that was provided, as well as a static message "hi there".
// Think of this as the internal Node code...
var server = { // v---this will be the function you pass
on: function(name, callback) {
setTimeout(function() {
callback(name, "hi there"); // here your function is invoked
}, 1000);
}
};
So here we call .on(), and pass it the name "foo", and the callback function. When the callback is invoked, it will be given the name, and the "hi there" message.
// ...and this is your code.
server.on("foo", function(name, message) {
console.log(name, message);
});
They are short for "Request" and "Response." It is typical of many web frameworks to pass these two objects into a request handling method (action or whatever you want to call it).

Categories