SkillAgentSearch skills...

TesTcl

when you don't have the balls to test your F5 BIG-IP iRules directly in production

Install / Use

/learn @landro/TesTcl
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Introduction

TesTcl is a Tcl library for unit testing iRules which are used when configuring F5 BIG-IP devices.

News

  • 4th May 2020 - Version 1.0.14 released
  • 10th November 2018 - Version 1.0.13 released
  • 26th September 2018 - Version 1.0.12 released
  • 24th May 2018 - Version 1.0.11 released
  • 23rd March 2017 - Version 1.0.10 released
  • 29th April 2016 - Version 1.0.9 released

Getting started

If you're familiar with unit testing and mocking in particular, using TesTcl should't be to hard. Check out the examples below:

Simple example

Let's say you want to test the following simple iRule found in simple_irule.tcl:

rule simple {

  when HTTP_REQUEST {
    if { [HTTP::uri] starts_with "/foo" } {
      pool foo
    } else {
      pool bar
    }
  }

  when HTTP_RESPONSE {
    HTTP::header remove "Vary"
    HTTP::header insert Vary "Accept-Encoding"
  }

}

Now, create a file called test_simple_irule.tcl containing the following lines:

package require -exact testcl 1.0.14
namespace import ::testcl::*

# Comment in to enable logging
#log::lvSuppressLE info 0

it "should handle request using pool bar" {
  event HTTP_REQUEST
  on HTTP::uri return "/bar"
  endstate pool bar
  run simple_irule.tcl simple
}

it "should handle request using pool foo" {
  event HTTP_REQUEST
  on HTTP::uri return "/foo/admin"
  endstate pool foo
  run simple_irule.tcl simple
}

it "should replace existing Vary http response headers with Accept-Encoding value" {
  event HTTP_RESPONSE
  verify "there should be only one Vary header" 1 == {HTTP::header count vary}
  verify "there should be Accept-Encoding value in Vary header" "Accept-Encoding" eq {HTTP::header Vary}
  HTTP::header insert Vary "dummy value"
  HTTP::header insert Vary "another dummy value"
  run simple_irule.tcl simple
}

Installing JTcl including jtcl-irule extensions

Install JTcl

Download JTcl, unzip it and add it to your path.

Add jtcl-irule to your JTcl installation

Add the jtcl-irule extension to JTcl. If you don't have the time to build it yourself, you can download the jar artifact from the release v 0.9 page or you can use the direct link. Next, copy the jar file into the directory where you installed JTcl. Add jtcl-irule to the classpath in jtcl or jtcl.bat. IMPORTANT! Make sure you place the jtcl-irule-0.9.jar on the classpath before the standard jtcl-<version>.jar

MacOS X and Linux

On MacOs X and Linux, this can be achieved by putting the following line just above the last line in the jtcl shell script

export CLASSPATH=$dir/jtcl-irule-0.9.jar:$CLASSPATH
Windows

On Windows, modify the following line in jtcl.bat from

set cp="%dir%\jtcl-%jtclver%.jar;%CLASSPATH%"

to

set cp="%dir%\jtcl-irule-0.9.jar;%dir%\jtcl-%jtclver%.jar;%CLASSPATH%"
Verify installation

Create a script file named test_jtcl_irule.tcl containing the following lines

if {"aa" starts_with "a"} {
  puts "The jtcl-irule extension has successfully been installed"
}

and execute it using

jtcl test_jtcl_irule.tcl

You should get a success message. If you get a message saying syntax error in expression ""aa" starts_with "a"": variable references require preceding $, jtcl-irule is not on the classpath before the standard jtcl-<version>.jar. Please review instructions above.

Add the testcl library to your library path

Download latest TesTcl distribution from github containing all the files (including examples) found in the project. Unzip, and add unzipped directory to the TCLLIBPATH environment variable:

On MacOS X and Linux:

export TCLLIBPATH=whereever/TesTcl-1.0.14

On Windows, create a System Variable named TCLLIBPATH and make sure that the path uses forward slashes '/'

In order to run this example, type in the following at the command-line:

>jtcl test_simple_irule.tcl

This should give you the following output:

**************************************************************************
* it should handle request using pool bar
**************************************************************************
-> Test ok

**************************************************************************
* it should handle request using pool foo
**************************************************************************
-> Test ok

**************************************************************************
* it should replace existing Vary http response headers with Accept-Encoding value
**************************************************************************
verification of 'there should be only one Vary header' done.
verification of 'there should be Accept-Encoding value in Vary header' done.
-> Test ok

Explanations

  • Require the testcl package and import the commands and variables found in the testcl namespace to use it.
  • Enable or disable logging
  • Add the specification tests
    • Describe every it statement as precisely as possible. It serves as documentation.
    • Add an event . This is mandatory.
    • Add one or several on statements to setup expectations/mocks. If you don't care about the return value, return "".
    • Add an endstate. This could be a pool, HTTP::respond, HTTP::redirect or any other function call (see link).
    • Add a verify. The verifications will be run immediately after the iRule execution. Describe every verification as precisely as possible, add as many verifications as needed in your particular test scenario.
    • Add an HTTP::header initialization if you are testing modification of HTTP headers (stubs/mocks are provided for all commands in HTTP namespace).
    • Add a run statement in order to actually run the Tcl script file containing your iRule. This is mandatory.
A word on the TesTcl commands
  • it statement takes two arguments, description and code block to execute as test case.
  • event statement takes a single argument - event type. Supported values are all standard HTTP, TCP and IP events .
  • on statement has the following syntax: on ... (return|error) result
  • endstate statement accepts 2 to 5 arguments which are matched with command to stop processing iRule with success in test case evaluation.
  • verify statement takes four arguments. Syntax: verify "DESCRIPTION" value CONDITION {verification code}
    • description is displayed during verification execution
    • value is expected result of verification code
    • condition is operator used during comparison of value with code result (ex. ==, !=, eq).
    • verification_code is code to evaluate after iRule execution
  • run statement takes two arguments, file name of iRule source and name of iRule to execute
A word on stubs or mockups (you choose what to call 'em)#####
HTTP namespace

Most of the other commands in the HTTP namespace have been implemented. We've done our best, but might have missed some details. Look at the sourcecode if you wonder what is going on in the mocks. In particular, the HTTP::header mockup implementation should work as expected. However insert_modssl_fields subcommand is not supported in current version.

URI namespace

Everything should be supported, with the exception of:

which is only partially supported.

GLOBAL namespace

Support for

Avoiding code duplication using the before command

In order to avoid code duplication, one can use the before command. The argument passed to the before command will be executed before the following it specifications.

NB! Be carefull with using on commands in before. If there will be another definition of the same expectation in it statement, only first one will be in use (this one set in before).

Using the before command, test_simple_irule.tcl can be rewritten as:

package require -exact testcl 1.0.14
namespace import ::testcl::*

# Comment in to enable logging
#log::lvSuppressLE info 0

before {
  event HTTP_REQUEST
}

it "should handle request using pool bar" {
  on HTTP::uri return "/bar"
  endstate pool bar
  run simple_irule.tcl simple
}

it "should handle request using pool foo" {
  on HTTP::uri return "/foo/admin"
  endstate pool foo
  run simple_irule.tcl simple
}

it "should replace existing Vary http response headers with Accept-Encoding value" {
  # NB! override event type set in before
  event HTTP_RESPONSE

  verify "there should be only one Vary header" 1 == {HTTP::header count vary}
  verify "there should be Accept-Encoding value in Vary header" "Accept-Encoding" eq {HTTP::header Vary}
  HTTP::header insert Vary "dummy value"
  HTTP::header insert Vary "

Related Skills

View on GitHub
GitHub Stars104
CategoryDevelopment
Updated3mo ago
Forks30

Languages

Tcl

Security Score

97/100

Audited on Dec 13, 2025

No findings