Testing redis key expiration - ruby-on-rails

I was wondering if anyone has a clever way of testing behavior after a redis key expires. I am essentially building a small redis backed cache for my application and would like to test what happens after a redis key is set to expire.
I am using rspec as my testing framework. I tried to use Timecop to change the time during testing but realized that it would only effect the testing frame work and not the external redis server.
I can set the TTL to 1 and then use a sleep(1) but I would rather not introduce sleeps into my tests.
Does anyone have a good way of testing this?

Why not use http://redis.io/commands/expire to expire the key right away?

The proper way to fix this for the testing environment is to mock out the redis client and have it return the expected value. I have confidence redis will do the right thing and is implemented correctly so mocking this interaction out is probably better than letting the test actually hit redis.
redis_client.should_receive(:ttl).with(key).then_return(-1)
or just mock out the request for the key
redis_client.should_receive(:get).with(key).then_return(nil)
With the newer RSpecs version,
expect(redis_client).to receive(:get).with(key).and_return(value)

Related

Caching an HTTP request made from a Rails API (google-id-token)?

ok, first time making an API!
My assumption is that if data needs to be stored on the back end such that it persists across multiple API calls, it needs to be 1) in cache or 2) in a Database. is that right?
I was looking at the code for the gem "google-id-token". it seems to do just what i need for my google login application. My front end app will send the google tokens to the API with requests.
the gem appears to cache the public (PEM) certificates from Google (for an hour by default) and then uses them to validate the Google JWT you provide.
but when i look at the code (https://github.com/google/google-id-token/blob/master/lib/google-id-token.rb) it just seems to fetch the google certificates and put them into an instance variable.
am i right in thinking that the next time someone calls the API, it will have no memory of that stored data and just fetch it again?
i guess its a 2 part question:
if i put something in an #instance_variable in my API, will that data exist when the next API call comes in?
if not, is there any way that "google-id-token" is caching its data correctly? maybe HTTP requests are somehow cached on the backend and therefore the network request doesnt actually happen over and over? can i test this?
my impulse is to write "google-id-token" functionality in a way that caches the google certs using MemCachier. but since i dont know what I'm doing i thought i would ask.? Maybe the gem works fine as is, i dont know how to test it.
Not sure about google-id-token, but Rails instance variables are not available beyond single requests and views (and definitely not from one user's session to another).
You can low-level cache anything you want with Rails.cache.fetch this is put in a block, takes a key name, and an expiration. So it looks like this:
Rails.cache.fetch("google-id-token", expires_in: 24.hours) do
#instance_variable = something
end
If the cache exists and it is not past its expiration date/time, Rails grabs it from the cache; otherwise, it would make your API request.
It's important to note that low-level caching doesn't work with mem_store (the default for development) and so you need to implement a solution with redis or memcached or something like that for development, too. Also, make sure the file tmp/cache.txt exists. You can run rails dev:cache or just touch it to create it.
More on Rails caching

Xcode Dev: save api response for future tests during development

I'm building an app that relies heavily on an api response. The app needs to make this request every time it is launched. However this request takes 60~ seconds. Is there any way to save the response between tests so I can build/test the features that rely on the response?
In short, I don't want to call the server every time I test the app. I'm in swift
What I do is to write conditional code, dependent upon some environment variable, so that I'm not contacting the server but using some constant instead.
Thus, when I'm just testing and developing the rest of the my app, I just throw the environment variable switch, and presto, I'm using that constant.

Thread safety in rails with slack-api gem

I have just started using rails. In my app I have to access Slack apis, so I am using the slack-api gem. The way to configure that is
Slack.configure do |config|
config.token = "token"
end
I am wondering since the token is configured at class level 'Slack', would that cause any inconsistent behaviour? One request might set it to value A and before it is done, another request may set it to value B.
While Ruby web frameworks are generally single-threaded, this is not always the case. So it likely will cause problems if the token is different across multiple requests, will be hard to reason about or become a problem in the long run.
Try the newer gem, https://github.com/dblock/slack-ruby-client which will take a token in the initializer, ie. Slack::Web::Client.new(token: 'token') or Slack::RealTime::Client.new(token: 'token'), should avoid the problem altogether.

Mantain session between tests using Geb

I'm testing my application using Geb, and I want to mantain session between tests so I can avoid to log in in every tests (this is annoying when watching the tests in the browser).
Is there a way to mantain the session?
By default Geb test integrations clear all the cookies after every test which means that you loose your web sessions. You can easily change that behaviour by using the following configuration option in your GebConfig.groovy:
autoClearCookies = false
You can read more about using configuration here.
So yes, it is possible to maintain session between tests.
If you are using Spock, one option that you can do is to structure your "features" (test methods) in a linear fashion and use the #Stepwise annotation on the class. This will ensure that the cookies and browser object are not reset/replaced between features/test-methods
Yup, it isnt possible now. My specs start by logging in and finish by logging out.

Ruby on Rails: Best way to test a failed call to a third party API

I call a third party web service right now as part of my application. I am using the RestClient gem in order to do this. There are a ton of tools available to do the same thing, so that should not matter.
What I'm curious about is having good enough tests, nothing too fancy, where I can simulate how my application responds when the third party web service is unavailable for whatever reason. Be it that I exceeded a rate limit or a timeout due to network latency/complications, I just want to be able to take something like an HTTP status code and test what my application does in that event.
What's the best way to do this with Test::Unit? Right now the call to the third party service is encapsulated inside of one of my controllers. I have a simple module with some wrapper methods for the different end points of the remote service. I just want to make sure that my application does the right things when the service is or isn't available.
Is using an additional framework next to Test::Unit that can 'stub' the right way to go about doing this? Obviously I can't force a network timeout and starting to hack with things like IPtables just for tests is not worth the time. I'm sure this problem has been solved a million times as integrating things such as Facebook and Twitter into web applications is so popular these days. How do you test for failure when reaching those APIs in a robust/controlled format?
I would recommend using something like webmock to mock all of your http requests (not just to mock a failed request); it'll greatly speed up your test suite instead of having to actually hit the third party service every time you run the tests.
Webmock supports Rest Client and Test::Unit. Just put this code in your test/test_helper.rb file:
require 'webmock/test_unit'
As an example, to test a network timeout:
stub_request(:any, 'www.example.net').to_timeout
RestClient.post('www.example.net', 'abc') # ===> RestClient::RequestTimeout
railscast: 291 (subscriber only) talks about testing with VCR and rspec (i know, not it's not Test:Unit)
anyway you could look into using VCR for this sort of thing

Resources