Category Archives: Sinatra

Working toward a testable Sinatra application

One of the prime goals I had when starting writing a simple Sintra application was to make sure unit testing was done from the start, a vague sort of TDD, given that I’m not  professional developer and I’m not mad about ideaology; I’d had made very little trying to build unit tests for Rails applications, especially when it comes to sessiosn and authentication. No testing, no application.

Even though Sinatra is a small footprint and quick to get going, I still found it very opaque and the Rack test library very secretive and deceptive. It took me 10 days trying to figure out 4 tests for my application, though, as painful as it was, I do have a better (and more coherent – never my strong point) application as a result.

Ultimately, however, I found it much easier to design the testing code for the transactions I wanted using curl because it is so much easier to figure out what is going on.  I really wanted to run a command that I *knew* was submitting data in the format I wanted so that I could sort the routing code around it. Something like,

curl -v http://localhost:4567/package-inventory/packages/new -H 'Content-Type: application/json' -d '{"hostname": "thisbox", "packages": {"first-package": "4.9.", "my-package": "1.2.", "your-package": "4.5.6-0."}}'

Once the server is reponding as expected, it can easily be added to an integration test with a snippet like

jdata = {}
 jdata[:hostname] = hostname
jdata[:packages] = {}
 ["first-package 4.9.0", "my-package 1.2.3", "your-package 4.5.6-0.1"].each do |pkg|
  jdata[:packages].merge! Hash[*pkg.chop.split(/ /)]
 end

The submission can be completed using something like

 request = '/package-inventory/packages/new'
 headers = { 'CONTENT_TYPE' => 'application/json' }
 post request, jdata.to_json, headers
 assert last_response.ok?

On the receiving end of the POST we hve to remember that the incoming data is a SringIO object and as such is accessed like a file stream,

jd = request.body.read.to_s
 jdata = JSON.parse jd

I initially made the mistake of treating the request body as an array to be referenced several times and wondering why it had disappeared: assign it to a variable an be done with it! I also spent some time trying to access the submission through the params hash without realising that that only applies to symbolised references on the incoming request.

After parsing, we then have our data to do as we please. Based on an example, I maintained the return messages (for status or data return) as a hash finishing off each route with,

return_message.to_json

helping ensure that all inbound and outbound requests are in the same format.

I still wouldn’t say that I’m fully comfortable with the unit tests, but they do work mostly as expected, even for failure conditions.

But as a comparative exercise, I’m going to produce Python version of the same service using Flask and a unit test process, bearing in mind that this will be my first ever Python program; the early signs are quite promising.

References:

I found the last comment at http://stackoverflow.com/questions/18449428/sinatra-unit-test-post-with-json-body (eventually) useful, but ignore the comment advising against using JSON to transfer data; such is the variability of the Stack.

 

 

 

Advertisements

Posting JSON to Sinatra using curl

Because of the difficulties (opacity) of trying to develop unit tests with Rack on a Sinatra application, I decided to try get something working with curl: we have much better control of the post process and is something we can actually troubleshoot.

Of all the posts I have seen regarding to Rack applications, the one that sticks with me is http://lightyearsoftware.com/2013/02/sending-json-post-data-in-an-integration-test http://lightyearsoftware.com/2013/02/sending-json-post-data-in-an-integration-test/, simply because the author says that it is not straightforward and doesn’t expect it to continue working with future versions of Ruby or Rails.

I’ll put together another post shortly describing in a bit more detail, not just the POSTing, but the receiving end as well. It’s been painful.

Why so hard to do the right thing?

Just when I thought I’d found something really cool in Ruby that was going to produce simple applications and exploring a development lifecycle…

I really, really want to be able to write unit and integration tests for teh code I produce. With Rails, rspec is a nightmare, especially when combined with sessions and authentication.

So I take a step down to Sinatra and Rack. I get some simple code for a little service and the GET request for resource works as expected. But 3 days trying to get the unit test function to be able to post data is just too much. None of the official documentation mentions it never mind examples; so many variations on StackOverflow; verbatim copied code from blogs that has syntax errors.

It’s not even that my  server app can’t process POST data, it is that the unit test gem makes it impossible to debug the transfer, whether or not I’m a numpty.

This time I’ll abandon the project and the follow-up applications I had in mind for Sinatra and write it off as another Ruby dead-end. I’m sure people do get it working but I give up.

Testing Sinatra applications

I have been mucking around a bit more with my Sinatra application, running it via Rack with a config.ru file and some code improvements (though everything I write still looks like it was done by a ten-year-old) and I decided it ought to be fairly straightforward to prepare some test cases since I’m only handling two routes.

Not so. This is Ruby after all.

There’s quite a long testing page, http://www.sinatrarb.com/testing.html, but at no point does it give a command that will actually run the tests listed on the page! And none of the tests include POST data.

Every time I’ve tried to spend time figuring out how to run simple application tests with Rails, and now Sinatra, I just want to tear my hair out and just give up.

I know I’m a numpty coder, but it’s so difficult trying to do the right thing.

Writing a Sintra microservice

Have just embarked on trying to write a simple microservice to record lists of installed packages from clients and then be  able to serve them back to a different client that uses the records to populate database.

https://github.com/slugbucket/package-inventory-server

The initial code is very ropy but good fun to write and I’m just discovering the wonders of Sinatra for providing this kind of service.

If I make any kind of progress here, and I want to try out some mock testing without requiring an actual database, there are a few other applications I can think of that would benefit from a lightweight touch such as this.