Let’s say you usually code in Ruby, and your company and its build systems are built around Rakefiles and the like. Today you’ve written some C code, and you want to add unit tests. In this blog post, I present a method of writing those C unit tests in Ruby using FFI and RSpec.
/**
* This is a very silly function that clearly requires some unit tests.
*/
int foo_count_letters(const char *source, size_t *count)
{
if (!source || !count) return 0;
for (*count = 0; *source; (*count)++, source++)
;
return 1;
}
First, compile your C code as position independent and symbols exported. This allows you to dlopen() the executable:
$ gcc -pie -rdynamic -o foo foo.c
Next, add the FFI gem to your Gemset, in Gemfile
:
source :rubygems
gem 'ffi'
Then write your rspec tests spec/foo_spec.rb
:
#!/usr/bin/env ruby
require 'ffi'
# This module is your bridge from Ruby to C and back
module FOO
extend FFI::Library
# Use an absolute path to the executable under test, otherwise ffi will search LD_LIBRARY_PATH.
ffi_lib File.absolute_path(File.join(File.dirname(__FILE__), "..", "foo"))
# Function signatures for each function to be tested
attach_function :foo_count_letters, [:string, :pointer], :int
end
describe "unit tests for foo.c" do
before(:each) do
end
it "should really foo" do
# This function takes a pointer-to-uint32 out-param
out = FFI::MemoryPointer.new :uint32
res = FOO.foo_count_letters("Hello", out)
# Read back the pointers to Ruby data types, then use rspec's verification functions
out.get_uint32(0).should == 5
res.should == 1
end
end
I’m excited about this approach because the tests run under rspec
along with the rest of your spec tests.
Today I moved my blog from my own server to GitHub. I exported my blog from Movable Type to Jekyll source files, checked it a GitHub repo, and pointed my domain’s DNS at GitHub Pages.
Varnish makes your websites go faster. Memcached, makes your websites go faster. Blog posts abound on using Varnish’s excellent embedded C functionality to link libmemcached into your VCLs, and Poul himself has written about his surprise in learning that many VCLs were actually thin wrappers around a C library where all of the business logic of a VCL would live.
Starting in Varnish 3, the balance can now shift back towards the VCL itself as the driver of business logic, with first-class “vmod” modules providing new VCL functions. (If you’ve been around a while, you might recognize the same progression that PHP took in the late 90’s and early 2000’s, back when PHP looked like a promising future.)
Without further ado, I present libvmod-memcached, a Varnish Memcached Module. Here’s a quick example script that flushed the cache for a page every 20 hits.
import memcached;
sub vcl_init {
memcached.servers("localhost");
}
sub vcl_hit {
if( memcached.incr(req.url, 1) == 0 ) {
memcached.set(req.url, 0, 86400, 0);
}
if( memcached.get(req.url) == "20" {
purge_url(req.url);
}
}
Note that VCL does not allow arbitrary variables, so I’m doing two memcached queries here. Fixing that will be another blog post!
The Dilburn campers jotted some useful notes on a little whiteboard at our camp. Eventually I wanted to erase the whiteboard, so here’s what it said!
My gal has a laptop that she really likes, an HP dv2000 - dv2225nr to be exact - even though it’s slooow. I’d gotten pretty near to talking her into replacing it when the new job provided a spiffy ThinkPad that she can bring home now and then. Needing only a personal machine to sync her iPhone and surf the web, I said, “What if we just put in a hundred bucks to make it less slow and do a Windows Vista detox?”
Ok, $185 bucks later, and I have some recommendations to make to the lazywebs about this laptop model.
Things I learned:
The AMD Turion 64 x2 with GeForce Go 6150 chipset in this system will happily accept sticks of 4GB DDR2 RAM, probably for a maximum capacity of 8GB. But I stopped at mixing a 4GB stick with an existing 1GB stick, for a total of 5GB.
Check in the BIOS how much RAM is set aside for that GeForce Go 6150. The default is probably 64MB from the factory (with the default 1GB memory configuration, this makes sense I suppose), but you can go to 128MB. Now that 128MB is basically a rounding error on the total memory size, use it.
I tried to clone the original hard drive, but taking it out of the machine caused it to lose its magic smoke. That meant my Windows 7 Upgrade edition was no longer valid for a clean install on a new 7200RPM drive. Follow these directions to get around that:
Windows 7 64-bit runs great, uses all of the RAM and all that jazz. [Insert pointless argument about pointer sizes and 64-bit bloat and how I’d be better off with 3.5GB usable RAM at 32-bits. I don’t care; everything else I touch these days is 64-bit. Consistency FTW.]
Finally, the 1.6GHz Turion TL-50 CPU sits in an S1G1 socket, so $20 got me a 2GHz TL-60 with double the L1 cache and a 31W TDP, down from 35W. Runs faster, cooler, and I pretend that the battery lasts a little more. That’s what I told my girlfriend, anyhow! Winning!