The TNB CLI tool allows you to deploy and interact with System-X services directly from your terminal without writing test cases. It’s powered by JBang and provides an interactive Groovy shell.
Installation
Install JBang
First, ensure you have JBang installed. Visit jbang.dev for installation instructions. # macOS
brew install jbangdev/tap/jbang
# Linux
curl -Ls https://sh.jbang.dev | bash -s - app setup
# Windows
choco install jbang
Build TNB locally
Clone and build the TNB project: git clone https://github.com/tnb-software/TNB.git
cd TNB
mvn clean install -DskipTests
Install tnb command
Register the tnb command globally: jbang app install jbang/tnb.java
This creates a global tnb command in your PATH.
Verify installation
Test the installation: You should see the Groovy shell prompt.
The CLI uses a Groovy shell, so all Groovy language features are available for scripting and automation.
Basic usage
Deploying services
Deploy System-X services using the deploy command:
Local deployment
OpenShift deployment
// Deploy services locally using TestContainers (default)
tnb > deploy Kafka
tnb > deploy MongoDB
tnb > deploy PostgreSQL
Services are deployed as Docker containers on your local machine. // Deploy to OpenShift with --openshift flag
tnb > deploy Kafka -- openshift
tnb > deploy MongoDB -- openshift
Or set OpenShift mode persistently: tnb > setOpenshift
tnb > deploy Kafka // Now deploys to OpenShift
Switch back to local: tnb > setLocal
tnb > deploy Kafka // Now deploys locally
Using deployed services
After deployment, you’ll get a variable name to interact with the service:
tnb > deploy Kafka
Deploying Kafka .. .
Service deployed successfully !
Use 'kafka' to interact with the service.
tnb > kafka . validation() . createTopic( "my-topic" )
tnb > kafka . validation() . produce( "my-topic" , "Hello from CLI!" )
tnb > def records = kafka . validation() . consume( "my-topic" )
tnb > records . each { println it . value() }
Hello from CLI !
Press TAB after typing a service name to see available methods: tnb > kafka . validation() . [ TAB ]
This shows all validation methods you can use.
Undeploying services
Manual undeploy
Automatic undeploy
// Undeploy a specific service
tnb > undeploy kafka
// Undeploy all services
tnb > undeploy
Services are automatically undeployed when you exit the CLI: Or press Ctrl+D to exit.
Configuration
The CLI uses the ~/.tnb directory for configuration and state.
Directory structure
~/.tnb/
├── init.groovy # Startup script (executed on launch)
├── credentials/ # Stored credentials
│ ├── aws.properties
│ ├── jira.properties
│ └── ...
└── history # Command history
Initialization script
Create ~/.tnb/init.groovy to set up properties and configurations on startup:
// Set credentials file
System . setProperty( 'test.credentials.file' , System . getProperty( 'user.home' ) + '/credentials.yaml' )
// OpenShift configuration
System . setProperty( 'openshift.kubeconfig' , System . getProperty( 'user.home' ) + '/.kube/config' )
// Enable log streaming
System . setProperty( 'stream.logs' , 'true' )
// Custom service images
System . setProperty( 'tnb.mongodb.image' , 'mongo:7.0' )
System . setProperty( 'tnb.kafka.image' , 'confluentinc/cp-kafka:7.5.0' )
// Helper function
def deployAll ( services ) {
services . each { deploy it }
}
println "Custom TNB environment loaded!"
Credential handling
The CLI has special credential management:
Interactive prompt
When deploying a service requiring credentials, you’ll be prompted if they’re not found: tnb> deploy AWS
Credentials for 'aws' not found.
Enter access_key: AKIAIOSFODNN7EXAMPLE
Enter secret_key: ********
Enter region: us-east-1
Automatic storage
Entered credentials are saved to ~/.tnb/credentials/<id>.properties: ~/.tnb/credentials/aws.properties
access_key =AKIAIOSFODNN7EXAMPLE
secret_key =wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
region =us-east-1
Reuse
Stored credentials are automatically loaded for future sessions.
Credentials stored in ~/.tnb/credentials/ are in plain text. Ensure proper file permissions: chmod 600 ~/.tnb/credentials/ *
Advanced usage
Multiple services
Deploy and orchestrate multiple services:
// Deploy multiple services
tnb > deploy Kafka
tnb > deploy MongoDB
tnb > deploy PostgreSQL
// Use them together
tnb > kafka . validation() . produce( "events" , '{"userId": 123}' )
tnb > def event = kafka . validation() . consume( "events" )[ 0 ] . value()
tnb > import groovy.json.JsonSlurper
tnb > def json = new JsonSlurper () . parseText(event)
tnb > mongodb . validation() . insertDocument( "users" , json)
Scripting
Create Groovy scripts to automate tasks:
// Load the script in tnb
tnb > load 'test-scenario.groovy'
// Or run it directly
jbang jbang / tnb . java test - scenario . groovy
Example script:
// Deploy services
deploy Kafka
deploy MongoDB
// Wait for readiness
Thread . sleep( 5000 )
// Create test data
kafka . validation() . createTopic( "orders" )
// Produce messages
100. times { i ->
kafka . validation() . produce( "orders" , "Order # ${ i } " )
}
// Consume and verify
def records = kafka . validation() . consume( "orders" , 100 )
assert records . size() == 100
println "Test completed successfully!"
// Cleanup
undeploy
Custom service configuration
Configure services before deployment:
tnb > import software.tnb.common.service.ServiceFactory
tnb > import software.tnb.splunk.service.Splunk
tnb > import software.tnb.splunk.service.configuration.SplunkConfiguration.SplunkProtocol
// Create service with configuration
tnb > def splunk = ServiceFactory . create( Splunk . class, config ->
config . protocol( SplunkProtocol . HTTP ))
tnb > splunk . validation() . sendEvent( "test" , "my event" )
Working with external services
Connect to external service instances:
// Set external host property
tnb > System . setProperty( 'tnb.kafka.host' , 'kafka.example.com:9092' )
// Deploy will now connect to external instance instead of creating new one
tnb > deploy Kafka
tnb > kafka . validation() . listTopics()
Integration with OpenShift
Prerequisites
Ensure you’re logged into OpenShift:
oc login https://api.cluster.example.com:6443
oc project my-namespace
Deploying to OpenShift
tnb > setOpenshift
tnb > deploy Kafka
// Check deployment status
tnb > ! oc get pods
// View logs
tnb > ! oc logs - f kafka - entity - operator -.. .
Use ! prefix to execute shell commands from within the TNB CLI: tnb > ! oc get routes
tnb > ! kubectl get svc
Configuration in init.groovy
// OpenShift configuration
System . setProperty( 'test.use.openshift' , 'true' )
System . setProperty( 'openshift.kubeconfig' , System . getProperty( 'user.home' ) + '/.kube/config' )
System . setProperty( 'openshift.namespace' , 'tnb-testing' )
System . setProperty( 'openshift.namespace.delete' , 'false' )
println "OpenShift mode enabled by default"
Examples
Kafka workflow
MongoDB workflow
Multi-service
// Start Kafka
tnb > deploy Kafka
// Create topic
tnb > kafka . validation() . createTopic( "my-topic" , 3 , 1 )
// Produce messages
tnb > 10. times { i ->
kafka . validation() . produce( "my-topic" , "key- ${ i } " , "Message ${ i } " )
}
// Consume messages
tnb > def records = kafka . validation() . consume( "my-topic" , 10 )
tnb > records . each { println " ${ it.key() } : ${ it.value() } " }
// List topics
tnb > kafka . validation() . listTopics() . each { println it }
// Cleanup
tnb > kafka . validation() . deleteTopic( "my-topic" )
tnb > undeploy kafka
// Deploy MongoDB
tnb > deploy MongoDB
// Insert documents
tnb > mongodb . validation() . insertDocument( "testdb" , "users" ,
[ name : "John" , age : 30 ])
tnb > mongodb . validation() . insertDocument( "testdb" , "users" ,
[ name : "Jane" , age : 25 ])
// Query documents
tnb > def users = mongodb . validation() . findDocuments( "testdb" , "users" )
tnb > users . each { println it }
// Count documents
tnb > def count = mongodb . validation() . countDocuments( "testdb" , "users" )
tnb > println "Total users: ${ count } "
// Cleanup
tnb > mongodb . validation() . dropDatabase( "testdb" )
tnb > undeploy mongodb
// Deploy services
tnb > deploy Kafka
tnb > deploy MongoDB
// Create integration flow
tnb > kafka . validation() . createTopic( "events" )
// Produce events to Kafka
tnb > import groovy.json.JsonBuilder
tnb > def event = new JsonBuilder ()
tnb > event {
userId 123
action "login"
timestamp System . currentTimeMillis()
}
tnb > kafka . validation() . produce( "events" , event . toString())
// Consume from Kafka and store in MongoDB
tnb > import groovy.json.JsonSlurper
tnb > def slurper = new JsonSlurper ()
tnb > kafka . validation() . consume( "events" ) . each { record ->
def data = slurper . parseText(record . value())
mongodb . validation() . insertDocument( "analytics" , "events" , data)
}
// Query MongoDB
tnb > def events = mongodb . validation() . findDocuments( "analytics" , "events" )
tnb > println "Stored ${ events.size() } events in MongoDB"
// Cleanup
tnb > undeploy
Tips and tricks
Tab completion Use TAB to autocomplete service methods and explore available APIs interactively.
Command history Press ↑/↓ to navigate command history. History is persisted in ~/.tnb/history.
Shell commands Execute shell commands with ! prefix: !ls, !oc get pods, !docker ps
Import libraries Import any Java/Groovy library: import org.apache.commons.lang3.StringUtils
Multi-line commands Press Enter without completing a statement to continue on the next line.
Save session Save your commands to a script file for reuse: save 'my-session.groovy'
Troubleshooting
The tnb command requires TNB to be built locally: cd TNB
mvn clean install -DskipTests
jbang app install jbang/tnb.java
Check Docker is running for local deployments: For OpenShift deployments, verify you’re logged in:
Ensure credentials are configured in ~/.tnb/init.groovy or available in ~/.tnb/credentials/. You can also set them manually: System . setProperty( 'test.credentials.file' , '/path/to/credentials.yaml' )
If a service is already running, undeploy it first: tnb > undeploy kafka
tnb > deploy Kafka
Demo
Watch the TNB CLI in action:
The demo shows:
Installing the CLI
Deploying services
Interactive usage
Validation methods
Cleanup