Stubbing Sinatra helper in Cucumber - ruby

I am currently struggling with stubbing out a helper method of my Sinatra app from within Cucumber.
I have a Sinatra app with simple session authentication (by cookies) and I want to turn of authentication by stubbing out the logged_in? helper method for my Cucumber scenarios.
There seems to be a problem with Sinatra and Cucumber concerning sessions so I thought about just using Mocha to work around the problem.
However I don't know how I can access the Sinatra::Application instance from within a Given-Block to stub out the method.

It seems like I need to directly override my Authentication mechanism within a Before do ... end-block
So I ended up with a hooks.rb placed in features/support/ file overwriting my logged_in? and the current_user method.
Before do
MySinatraApplicationClass.class_eval do
helpers do
def logged_in?
return true
end
def current_user
# This returns a certain Username usually stored
# in the session, returning it like
# that prohibits different user logins, but for
# now this is enough for me
"Walter"
end
end
end
end
The only thing I had to take care of, is that the no other actions within the application directly read from session but rather use those helpers.
Sadly I think this way of handling session based Sinatra applications through Cucumber is already described somewhere else and I just thought my problem was different.

You can get the right context by using Sinatra::Application.class_eval
Edit: See original poster's answer for full explanation.

Related

How do I test methods in a Sinatra app?

How do I access the app instance so I can test the foobar() method?
class App < Sinatra::Base
get '/' do
return foobar
end
def foobar
"hello world"
end
end
This is a late reply, but I am trying to find a flexible way to do that too.
I found in Sinatra's source code (1.4.5) that creating an instance of the app with new! allows testing the app's methods directly. Exert from a test setup with Test::Unit and Shoulda.
class AppTest < Test::Unit::TestCase
setup do
#app = App.new! # here is the point.
end
should 'say hello to the world' do
assert_equal "hello world", #app.foobar # or #app.send(:foobar) for private methods.
end
end
There are consequences. Using new! does not create the usual Sinatra::Wrapper that becomes the entry point to the middleware pipeline and the app in normal settings. So the new! approach will work only if the tested methods are really "helpers" that do not rely on middleware functionalities (e.g. SSL).
Alternatively, a post on Rspec proposes an alternative solution. I used something similar in the past, but it requires more work that is not always the best choice. It had the advantage to offer broader coverage of code to test. The isolation of the app with new! sounds good though, if we are taking about "unit" testing.
Note on #three's comment: A non-trivial app should separate API methods (usually in the app) from all helpers, etc. Helpers ending up in a separate file are cleaner, easier to maintain, and easier to test. But I definitely understand cases where a first version of an app would include a few helpers, with awareness that refactoring will be necessary. And even then having tests brings in some more confidence in the software itself, and in the future refactoring as well.
It doesn't matter what you test - it is how :) => http://www.sinatrarb.com/testing.html

Debugging controller methods by running functional tests

I am in a situation where I need to step through the controller method when I run a functional test. I use ruby-debug to debug through my application. My app is a rails 3.1 app which uses ruby-1.8.7 . I can debug my code by using
rails server --debugger OR
rails console --debugger
I can also stop the code by inserting "debugger" in a model and run it's respective unit test.
But I am not able to do the same thing with the controllers. That is I am not able to stop the code by inserting "debugger" in the methods of the controller and run it's respective functional test.
Has anyone faced this issue before?
Also I use devise for authentication so I need to add the following lines to my test_helper
class ActionController::TestCase
include Devise::TestHelpers
def login_user
#request.env["devise.mapping"] = Devise.mappings[:user]
#user.confirm!
sign_in #user
end
end
Not sure I that is going to effect the debugger in anyway.
I was unable to stop at a debugger inserted in my controller method when I ran the functional tests because I was hitting a before_filter

Ruby: Get currently logged in user on windows

In C# I can get the current user of a web app using the HttpContext, however, I can't figure out how to do this in Ruby. Is there any way of doing this?
FOR THOSE OF YOU SAYING IT IS IMPOSSIBLE, HERES PROOF:
http://www.codeproject.com/KB/aspnet/How_to_NT_User_Name.aspx
Well, to get the current username, there's this:
puts ENV['USERNAME']
Or go to the Win32API.
require 'dl/win32'
def get_user_name
api = Win32API.new(
'advapi32.dll',
'GetUserName',
'PP',
'i'
)
buf = "\0" * 512
len = [512].pack('L')
api.call(buf,len)
buf[0..(len.unpack('L')[0])]
end
puts get_user_name
Edit: And I'm an idiot. This isn't what you asked for at all. Oh well, it took me time to dig this out of my code, so it might as well stay here for anyone else wondering :P
Edit again: OK, it turns out I'm not an idiot after all. This is what you want. When I went back and re-read your question, the HttpContext threw me off, and I thought it was the current username from HTTP auth or something.
To get the username of the current user on client machine you can use this
ENV['USERNAME']
If you're using Rails try: request.env['HTTP_REMOTE_USER']
I think what you mean is how you can retrieve the username that the user used to login to the web application. That will differ depending on what authentication mechanism you're using. Some Apache authentication modules, for example, will pass REMOTE_USER (e.g. the Kerberos module), the CAS Single-Sign-On module passes CAS-USER, etc. Standard digest authentication and such uses the Authentication header. You should be able to access these using request.env[HEADER] as someone else pointed out above. Check out the documentation on how your authentication layer is passing on the user in the HTTP request.
Is your c# code running as a .NET plugin/client-side code or is it ENTIRELY server side? Your ruby code would be entirely server side. According to the MS docs, only stuff running in the CLR sandbox can really get to that information:
http://msdn.microsoft.com/en-us/magazine/cc163700.aspx (under Defining the sandbox).
One thing interesting to note is that sites registered under LocalIntranet have access to that information. I'm not sure off hand how this maps to security zones in IE though.
The thing to understand is that LOGON_USER is NOT visible to the browser sandbox anymore than the browser can see the contents of a filesystem path on your system. The fact that your c# code sees it almost certainly indicitive of some clientside component passing it upstream.
You have the option of implementing mod_ntlm under apache and pushing the headers downstream. I don't have the points to post a second link but google 'rails ntlm sso' and see the rayapps.com link.
but if your app isn't Rails based, you'll have to port that to your server code. You can also checkout rack-ntlm if your app is rack compliant.
[RUBY ON RAILS ONLY]
This is what worked for me but there are some limitations:
won't work in Chrome: undefined method 'encode' for nil:NilClass
won't validate user credentials
If you don't care about these issues, go ahead:
In your rails application, add Rekado's gem to your Gemfile: gem 'ntlm-sso', '=0.0.1'
Create an initialiser config/initializers/ntlm-sso.rb with:
require 'rack'
require 'rack/auth/ntlm-sso'
class NTLMAuthentication
def initialize(app)
#app = app
end
def call(env)
auth = Rack::Auth::NTLMSSO.new(#app)
return auth.call(env)
end
end
On your application.rb file, add the line: config.middleware.use "NTLMAuthentication"
Call request.env["REMOTE_USER"] on your view or controller to get current username.
PS: Let me know if you find anyway to make it work on Chrome or to validate user credentials.

Rack::Test not able to find web app cookie

While testing a Sinatra app with Cucumber, Rack::Test was not able to find the cookie that my app created, even though I could clearly see that it was in the Rack::Test::CookieJar object by dumping it with "p".
I'm answering my own question in order to share the solution with others:
Rack::Test::CookieJar#[] will only return the value of a cookie if it also matches the domain and path. Unfortunately, unless your app's domain is "example.org" you're out of luck.
Fortunately, there's an easy fix: If you're testing with Sinatra, paste the following monkey patch anywhere in your env.rb file in the outermost (global) scope:
module Rack
module Test
DEFAULT_HOST='localhost'
end
end
That's it!

Stubbing a controller method with Sinatra and rspec

So I'm trying to figure out a way of stubbing a controller method in rspec for a Sinatra app. The main reason for this is to test the logical flow of the application and to make sure it calls the necessary functions when certain conditions are met. So, in essence, I want to be able to do something like
controller.should_receive(:fancy_method).and_return("This is a string")
What I'm having difficulty doing is accessing the controller instance within the sinatra app. I am able to override the current functions using a class_eval on the sinatra controller class, but I'd love to assert that these functions actually run.
Anyone have any advice?
Thanks.
Dan, I believe what you really want is to just test the controller actions. From a tester's perspective you shouldn't really care about what it actually called but rather for the output, given a specific input and maybe some other special conditions (that is mocking or stubbing other classes) (1).
You can check the official documentation for Sinatra + Rack::Test or this blog post from devver.net.
(1) : If your controller pages are calling some other classes (models, services, etc) you could mock these instead and put expectations on them. For example :
SomeClass.should_receive(:msg).with(:arg).and_return(:special_value)
Some more info for mocking (with RSpec in this exmaple) can be found on the RSpec documentation pages.

Resources