Fuzzy about Scala

I’ve recently started working on a new project (SwiftKey), and my immediate priority is to get our testing sorted out. To that end, I’m constructing a fuzz test suite. Partly because I think that it’s the right tool for the job, and partly because it’s a good opportunity for me to learn more about the language, I’m writing it in Scala.

A fuzz test interacts with the System Under Test in a random, yet structured manner. The object of the exercise is to construct sequences of API calls (or network traffic, or whatever) that flush out the kind of bugs that are less likely to be discovered by unit tests tests and the like. Fuzz tests are particularly good at finding things like security problems, buffer overruns, memory leaks etc.

Clearly randomness is a large part of a fuzz test, so I’m creating some utilities that make it easier to randomly choose between several different actions. I thought that I’d publish them just in case anyone else finds them useful, and also to solicit feedback to help me improve my use of Scala (bear in mind that I’m still finding my feet, so be gentle!).

So, here’s my first attempt:

val random = new Random

def oneAtRandom(actions: () => Unit*)() =
  () => actions(random.nextInt(actions.length))()

oneAtRandom takes a set of functions and returns another function which, each time it’s called, executes one of them at random. For example:

val randomAction = oneAtRandom(
  () => print('a'), () => print('b'), () => print('c'))

for(_ <- 1 to 10)
  randomAction()

Which gives the following output:

aabaacbbcc

So far, so good. But what if we want different functions to be executed with different frequencies? We might have some actions that we want to only happen occasionally? Here’s another version of oneAtRandom that takes a weighted set of functions and calls them in proportion to their relative weights:

def oneAtRandom(actions: (Int, () => Unit)*)() = {
  val totalWeight = actions.foldLeft(0) {_ + _._1}
  () => {
    val r = random.nextInt(totalWeight)
    var w = 0
    val (_, action) = actions.find {
        case(weight, _) => w += weight; w > r
      }.get
    action()
  }
}

Here’s how it’s used:

val randomAction = oneAtRandom(
    (1, () => println("rare")),
    (10, () => println("occasional")),
    (50, () => println("frequent"))
  )

for(_ <- 1 to 100)
  randomAction()

And to prove that it’s doing what it claims:

$ scala random2.scala | sort | uniq -c
  88 frequent
  11 occasional
   1 rare

$ scala random2.scala | sort | uniq -c
  82 frequent
  12 occasional
   6 rare

So I’ve got it working, which I’m happy about. But I’m sure that it could be improved. I’m sure, for example, that there must be a “nice” functional way to implement the loop inside the weighted version (instead of using var w as an accumulator), but each of my attempts to do so have ended up being considerably more complex than the current version.

I’d also love to use the -> notation to pass the arguments, for example:

val randomAction = oneAtRandom(
    1 -> () => println("rare"),
    10 -> () => println("occasional"),
    50 -> () => println("frequent")
  )

But doing so results in a parse error—the only way I’ve found to avoid it is to add additional parentheses:

val randomAction = oneAtRandom(
    1 -> (() => println("rare")),
    10 -> (() => println("occasional")),
    50 -> (() => println("frequent"))
  )

which is starting to feel a bit too much like Lisp for my taste 🙂

Finally, I’m really missing some of the handy little utilities provided by Ruby. In Ruby, for example, I could write the loops that call randomAction like this:

10.times { randomAction }

I know that it’s trivial to create this kind of utility, but one of the nice things about Ruby is that they all come as standard out of the box.

In any case, I’d be very grateful for any and all feedback on the above. Thanks in advance!

0 Responses to “Fuzzy about Scala”



  1. Leave a Comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s





%d bloggers like this: