Semintelligent - Max Schubert

My Bain Huuts!

Testing Log Messages With Rspec and Padrino

| Comments

.

And if you could could go ahead and get a can of pesticide and take care
of the roach problem we’ve been having that would be great.

Bill Lumbergh Office Space

While as a general rule testing log output can make tests brittle because logs are free text and can change easily, there are certainly cases where testing them makes sense.

Our application was missing some really important business flow logging that we discovered was needed when we attempted to troubleshoot a production issue. We had to spend a significant amount of time hunting something down that would have been trivial to find in a well formatted info log message. I added that logging to the application and then wanted to make sure these business level log messages were being emitted at the right places in the application.

To test log messages in Padrino, I added the following helper to our spec/support/spec_helpers.rb file:

spec/helpers/spec_helpers.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Pass a block and log output will be captured in that block and
# returned as an array of lines for testing.
def capture_logger_output
  logger.flush
  # This causes messages to be captured in the internal logger array
  # that can be accessed via logger.buffer.
  logger.auto_flush = false

  # Run user's code
  yield

  # Save the log lines captured during the test block
  # NOTE: have to clone otherwise flush clears the referred to array
  buffer = logger.buffer.clone

  logger.flush
  logger.auto_flush = true

  buffer
end

Now in your tests you can run test code and capture any log messages that happened during the code run!

spec/helpers/spec_helpers.rb
1
2
3
4
5
6
7
it should test something do
  messages = capture_logger_output do
    post %{/to/some/url}, params, set_csrf
  end
  expect( last_response.status ).to eq 200
  expect( messages.select{ |line| line =~ /general match/ }.first ).to match /specific-pattern/
end

Happy log testing!

When Writing Rspec Tests 15 Pieces of Flair Is Perfect Just Ignore Brian

| Comments

Stan, Chotchkie’s Manager: Now, you know it’s up to you whether or not
you want to just do the bare minimum. Or… well, like Brian, for
example, has thirty seven pieces of flair, okay. And a terrific smile.

Office Space

Forget Brian, when it comes to writing rspec tests let your lazy come out. Do the minimum. Write a test that just does enough to prove that your feature or component behaves as expected.

Do

  • Test all known user story / requirement business paths ( “happy paths” ) related to the component or feature.
  • Write a test that really exercises them with real data ( not mocks unless you have no other choice but to use mocks ).
  • Write it so it both proves your code does what it is supposed to do and so that it teaches other developers looking at it how that part of the application or component should behave

Don’t

  • Write a placeholder or filler test just so you can say you have test coverage
  • Validate every single attribute or piece of data related to the test; that makes your test very tightly coupled to the implementation and means that any tiny change to the code requires the test to be updated as well. This makes developers hate you and your overly high-maintenance tests.
  • Be obscure nor clever. Make the test direct and simple – the way we’d all like our English to be!
  • Use mocks unless you absolutely need to. Why? Mocks quickly become lies – if they are flexible enough to take made up method names they are likely to continue to take that made up method name even when the real implementation changes. Now your test lies to everyone when it says it passes because what it tests is something that is not used in the real implementation. The only place I personally feel comfortable with mocks is when external network-based services are dependencies and having them reliably be available in development and test environments is not possible.

HOW-TO: Rack::Attack With Dalli and Padrino

| Comments

We use Dalli for memcached-based route caching with Padrino 0.12. I wanted to add rate throttling for all /api route handlers to our app and wanted to use Dalli for that as well.

I found Rack::Attack, a really nice Rack-based gem that allows for connection throttling, blacklisting and whitelisting of clients. Cool stuff, perfect for our needs. Except it expects the caching layer to conform to the ActiveSupport::Cache::Store interface:

Note that Rack::Attack.cache is only used for throttling; not
blacklisting & whitelisting. Your cache store must implement increment
and write like ActiveSupport::Cache::Store.

Darn! Oh, wait, not so bad. But I don’t want to have to do inline creation of the client etc in app/app.rb, especially because I’m likely to have different throttling requirements for different environments.

Modules and blocks to the rescue!

  1. Create a subclass for the Dalli client that conforms to the ActiveSupport API.
  2. Create a helper method that can be used inline in app/app.rb that takes a block with an environment-specific policy.
  3. Wrap the use and cache client creation so it doesn’t have to be repeated in app/app.rb
Our security mixin module with configure_security helper
lib/security.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
module Security

  require 'dalli/client'

  @@store = nil

  # Dalli client does not conform to cache client
  # interface Rack::Attack expects - so add wrappers
  # for methods.

  class MemStore < Dalli::Client
    def decrement( key, step, options )
      decr( key, step, options[ :expires_in ] )
    end
    def increment( key, step, options )
      incr( key, step, options[ :expires_in ], nil )
    end
    def write( key, value, options )
      # Have to use raw => true for write or we get marshall
      # errors as Dalli marshals the Fixnum object instead of
      # sending the raw integer value
      set( key, value, options[ :expires_in ], :raw => true )
    end
  end

  def initialize_store
    if @@store.nil?
      use Rack::Attack
      @@store = Rack::Attack.cache.store = MemStore.new %{localhost:11211}
    end
  end

  # Called from app/app.rb
  def configure_security
    initialize_store
    yield( Rack::Attack )
  end

end
Now use it in app/app.rb
app/app.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
    self.extend Security # lib/security.rb - adds configure_security method

    configure :demo, :development, :api do

      # Rate limit calls to /api URLs to 2 a second in all envs.
      configure_security do |client|
        client.throttle('req/ip', :limit => 2, :period => 1.second) do |req|
          # If we return false nothing is cached ( no rate limiting )
          # - only rate limit calls to /api URLs
          req.path.index( %{/api} ).nil? ? false : req.ip
        end
      end

    end

Hints and Tips for Java Developers New to Ruby

| Comments

Most java developers have a really solid grasp of object-oriented concepts and patterns, which makes the transition to ruby easy really easy from that perspective. Moving from a statically typed to dynamic language is still a big change and some of the more basic coding practices change significantly. Here are some recommendations I’ve come up with based on my experiences doing mentoring with a bunch of java developers transitioning to ruby on our team and some code patterns I’ve heard used by a colleague of mine who is also mentoring some java developers who are transitioning to ruby.

Hints

  • Minimize the use of class variables – ruby’s class variables have some strange inheritence rules, and, with multi-process web containers, they don’t act as singletons across all instances of an app on the same server anyway.
  • Prefer local variables over instance variables when possible. Minimizing the scope of a variable in a dynamic language reduces the possibility of bugs and makes it much easier to see where the variable is being set and used.
  • Don’t pre-initialize data structures – no need. Arrays and hashes are dynamic and in the vast majority of circumstances pre-sizing them does not help performance and just leads to more noise in your code.
  • Snake-case variables .. thing_one and thing_two.
  • Semi-colons are not needed at the ends of statements ; only use them when doing single-line method definitions or rare cases where you want two statements on the same line.
  • Prefer composition over complex inheritence trees.
  • Prefer mixins over complex inheritence trees.

Tips

  • Explore code with irb or Pry. No faster way to get conversant with ruby than to explore using it from a ruby-based shell!

Great Tools for Distributed Teams

| Comments

Recently at my job our teams have grown to include a number of people who are not co-located with us. Here are some of the tools we’ve been using that have helped us develop and design together across locations.

Social coding

  • Gitlab – Github-like UI on top of git. Many of the same features of Github, pretty easy to host internally.

Remote pair programming

  • Screenhero – by far the best remote graphical pair-programming tool I’ve found – includes streaming audio support so we don’t have to have Google Hangouts, Skype, or another audio application open as well.
  • Hastebin – a paste bin tool that runs on node and is easy to set up internally – fast, low memory usage, zero maintenance.

Remote design

  • ASCII Flow – java-based, open source ASCII diagramming tool. Great for cutting and posting diagrams into markdown files. Haven’t tried installing it internally yet.
  • Etherpad – near-real time collaborative, modeless editing tool – like Google docs, highlights each person’s text in a different color. Runs on node as well.

Remote communication

We’ve heard a lot about various team-oriented chat tools, for now we’ve been sticking to the basics and so far so good.

Avoid Class Variables in Ruby for Web Applications

| Comments

When a ruby application runs in a multi-process web container (phusion passenger or puma for example), class variables set in one instance of the application will not be visible in another instance – so if you use them be very aware that the setting will purely apply to the instance of the application in which the variables are set.

If you need to share data across instances of an application, consider using memcache or another host-level data storage mechanism with a library that makes it easy to get and set data ( like Dalli for ruby ).

Jquery Event Handlers - Pitfalls and Tips

| Comments

Always return true or false at the end of the handler; true to allow additional events to fire, false to stop event propogation. If you do not oh boy will you get very strange behavior. For example, in recent Firefox releases you will get an error thrown with HTTP status 0 and message “Error,” yep, that is all you get.

if you have mutiple elementa trigger the same event and the only difference is data ( for example a list of names where clicking posts the name ), write a handler based off of a CSS class selector. Do not create one handler per row or item using unique div IDs as the CSS selector – this eats browser memory quickly!

Save jQuery elements in function scoped variablea and chain events from them – doing $( “selector” ) calls for the same element over and over again is expensive time and memory wise and slows your code down.

Using Pry With Padrino

| Comments

Pry is a really powerful replacement for IRB – I love using it with Rails. I recently started working with Padrino and of course had to have it working there as well.

Pry will read and execute a .pryrc file that exists in the current directory as it boots – here is my Padrino specific .pryrc file – it boots your app just like you’d get in Rails using Pry:

.pryrc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
load %{./config/boot.rb}
load %{./config/database.rb}
load %{./config/apps.rb}

require 'padrino-core/cli/console'
require 'padrino-core/cli/adapter'
require 'padrino-core/cli/base'
require 'padrino-core/cli/rake'
require 'padrino-core/cli/rake_tasks'

def app
  Padrino.application
end

def start( server = :puma )
  puts %{Type Ctrl-C to background server}
  Padrino.run! server: server
rescue Exception => e
  puts %{Problem starting server: #{ e.to_s }}
end

def stop
  puts %{Stopping server}
  threads = Thread.list
  threads.shift
  threads.each { |t| Thread.kill t }
end

def save_to( file, contents )
  File.open( file, %{w} ) { |f| f.puts contents }
end

Using Padrino Before and After Blocks in Rspec Tests

| Comments

We add in code that allows us to send mock parameters to controller actions via Capybara tests for all controllers while testing -so we can simulate session state ( for example – user being logged in ). In Rails you do this by re-opening ApplicationController in spec/spec_helper.rb and adding in a before_filter. In Padrino you can do this by adding custom code to app.rb in a before block – the before block is called for every controller action.

app/app.rb
1
2
3
4
5
6
7
8
9
10
11
configure :test do
  before do
    params.keys.each do |param|
      if param =~ /^mock_/
        mock_param = param.gsub(/mock_/, '')
        session[ mock_param ] = params[ param ]
        logger.debug %{ #{mock_param} set to #{params[ param ]}}
      end
    end
  end
end