Sunday, January 29, 2012

Puppet: Multiple Classes & Inheritance

I learned about a very cool thing yesterday: Defined Types in Puppet. Previously, I was trying to use parameterized classes for code reusability, but the problem there is that you can only declare one class resource per node. So puppet would yell if you tried to use the same parameterized class more than once on the same node. That's where defined types come in, they let you essentially declare a constructor like you would for a class, but as a method signature. Then, you can declare as many as you want and give them names.

The tie in to how to use this with classes and inheritance is to run the Defined Type declaration within each of your individual classes.

Defined types are not auto-loaded in the same fashion as the rest of the modules, so it's necessary to define them in a file named "init.pp" Otherwise they won't load and you'll see lots of errors like, "err: Could not retrieve catalog from remote server: Error 400 on SERVER: Puppet::Parser::AST::Resource failed with error ArgumentError: Invalid resource my_defined_resource at .../modules/module_name/manifests/my_manifest.pp:8 on node node.f.q.d.n"

Friday, January 13, 2012

Specs2 Mockito - Invoke Injected Callback

Mockito and Specs2 work great together and make testing my code a lot of fun. I ran into a problem yesterday in which I needed to get access to a callback function that was passed into an object that I was mocking. For some concreteness, I was mocking a zookeeper client and needed to invoke the callback function I passed to "zookeeper.watchNode(path, callbackFunction)".

Up until this point, I've only needed to verify arguments from my test. I haven't needed to actually do something with the argument itself. My original approach was to use a custom matcher to capture the parameter using function matchers. But that involved a var and was rather messy.

It turns out there is a MUCH better way to do this. Called "argument capture." In my case, my code looked like this:

      // The signature of the zookeeper watch function
      val listener = capture[(Option[Array[Byte]]) => Unit]

      // create system under test, which will call watchNode internally
      new SUT(zkMock)

      // Use the arg capturers to capture the params SUT passed in
      there was one(zkMock).watchNode(path, listener)

      // Now, call the callback method
      listener.value(Some("some updated value from zookeeper"))

      SUT.someValue must_== "some updated value"

Thursday, January 12, 2012

Specs2: IndexOutOfBoundsException: 30

I was consistently seeing a java.lang.IndexOutOfBoundsException: 30 exception today while working on some code. I had written a spec with a single use case, which was marked as pending because I couldn't test my trait until I flushed out another piece of code upon which it depended.

I'd seen the error in the past, but couldn't remember how (of it) it went away. Since I was working on a pretty much skeleton spec, I figured now would be a good time to get to the bottom of it.

Well, it was pretty simple! In connecting my use case text description to the actual test, I was using a "^" instead of an "!", which also explains the other oddity I was seeing (that I had thought related to pending tests) "No source file found at src/test/scala/...", since the "^" was expecting a String as the result of my test method being run, not a Specs result. Go DSLs!

def is =
"My trait should" ^
"do what I want" ^ SpecsStub().assert() // WRONG, ^ should be !

case class SpecsStub() {
  def assert() = {
    pending
  }
}