width, height, and overlay text arguments — JDK-only, no external dependencies, deterministic within a single JVMbase64-decode-body built-in response transformer that Base64-decodes the rendered response body and serves it as raw bytes, enabling binary responses (PNG, PDF, ZIP, etc.) from JSON mappings when paired with helpers such as {{image}}response.transformerParameters JSON block (used by HmacSigningTransformer and other parameter-driven response transformers) can be authored and edited in the GUI instead of only in the mapping JSON file. The editor auto-formats the JSON on blur (2-space indent) and validates on save (invalid JSON prevents submit with an inline error). Existing mappings round-trip semantically through the form (whitespace is normalised; field order is preserved). See Editing transformer parameters in the GUI for details.queryParameters JSON; loading an existing mapping with a queryParameters block populates the rows on the form. This replaces the previous workarounds of putting the full query string in urlEqualTo or hand-writing a lookahead regex in urlMatching — both of which continue to work for existing mappings.TRAFFICPARROT_LICENSE environment variable (base64-encoded), so it can be injected at runtime from a Kubernetes Secret, Docker secret, or secrets manager instead of being baked into a Docker image. The system property -Dtrafficparrot.license.content takes precedence over the environment variable, which takes precedence over the classpath trafficparrot.license file; if neither is set, the classpath file is read as before (no change for existing installations). A set-but-invalid value fails fast with a clear error rather than silently falling back to the file.bodyFileName file, making it clear that the body is loaded from the __files directory rather than typed inline.SoapMessageSigner entry in the trafficparrot.http.responsetransformers startup property (see Properties) and the per-mapping Response transformers multiselect.hostFilter, methodFilter, statusFilter, and urlFilter parametersswiftField Handlebars helper for extracting SWIFT MT message field values in dynamic response templatescontains, matches (regex), and doesNotMatch matchers in addition to the default equalTo.m3u8 playlists and .ts video segments from a single wildcard mapping, including multi-variant adaptive-bitrate (ABR) playlists with scenario-state-driven variant switching.desc and .protoset files) via the gRPC skeleton import UI, in addition to .proto source filesdata/ directory in the exported ZIP, so dataSource-backed mappings (CSV lookup, Excel lookup, object store) work correctly when imported on another instancetrafficparrot.virtualservice.handlebars.throwErrors, which causes helper errors to throw exceptions (HTTP 500 or messaging failures) instead of embedding inline error strings in responsesscanConsistency parameter to the Couchbase N1QL dataSource helper, allowing you to choose between REQUEST_PLUS (consistent, default) and NOT_BOUNDED (faster) query scan consistency, plus improved error handling that returns error messages instead of exceptionsmanageState Handlebars helper using namespace/variableName syntax, allowing state isolation between different test scenariosPUT /api/state/{namespace}/{name}GET /api/state/{namespace}/{name}GET /api/state/{namespace}DELETE /api/state/{namespace}/api/state/global/{name} routes remain unchanged for backward compatibilityPUT /api/configuration/files/{file} endpoint for creating new configuration files programmatically (returns 201 Created, or 409 Conflict if file already exists)externalValue URLs in named examples, using the fetched response body as the mock response instead of a placeholder messagetransformerParameters.hmacSigning in the mapping JSON, supporting HmacSHA1, HmacSHA256, and HmacSHA512 algorithms for simulating webhook and API gateway authenticationtrafficparrot.virtualservice.openapi.check.mapping.schema.on.startup=truereplyToQueueManagerName, replyToQueueName) in mapping JSON files with Handlebars template support, allowing dynamic control of response message routing headerstrafficparrot.ibmmq.connect.options.accessQueue.input property to configure how IBM® MQ queues are opened for input (consumer) operations, mirroring the existing accessQueue.output property for producersobjectStore Handlebars helper to ensure file access stays within the data directory(binary) placeholder instead of corrupted text$ref schema references in OpenAPI importstrafficparrot.virtualservice.grpc.tls.enabled and trafficparrot.virtualservice.grpc.non.tls.enabled properties to allow independently enabling/disabling each gRPC server portTransformedRequest.like(Request) static factory method in place of the deprecated TransformedRequest public constructor; the deprecated constructor remains available for backwards compatibilitycom.ibm.mq.allclient to com.ibm.mq.jakarta.client. If upgrading, replace com.ibm.mq.allclient.jar with com.ibm.mq.jakarta.client.jar in your lib/external/ folder — see JMS and IBM MQ documentation for details. Existing javax.jms plugins continue to work without source changes; support for javax-based plugins will be removed in a future major release.trafficparrot.virtualservice.httpRequestLoggingDisabled=true trafficparrot.virtualservice.accessLogsEnabled=false trafficparrot.virtualservice.handlebars.maxCacheEntries=10000
trafficparrot.openapi.import.on.startup=true
{{jwt maxAge='12 days'}}
{{jwt exp=(parseDate '2041-02-23T21:22:23Z')}}
{{jwt nbf=(parseDate '2019-02-23T21:22:23Z')}}
{{jwt iss='https://issuer.trafficparrot.com/'}}
{{jwt aud='https://audience.trafficparrot.com/'}}
{{jwt sub='subject'}}
{{jwt alg='RS256'}}
{{jwt
customBoolClaim=true
customIntClaim=23
customStringClaim='example@x.y.z'
customDateClaim=(parseDate '2024-01-02T03:04:05Z')
}}
{{jwks}}{
"settings" : {
"extended" : {
"jwt" : {
"hs256Secret" : "...",
"rs256PublicKeyId" : "...",
"rs256PublicKey" : "-----BEGIN RSA PUBLIC KEY-----\n...\n-----END RSA PUBLIC KEY-----\n",
"rs256PrivateKey" : "-----BEGIN RSA PRIVATE KEY-----\n...\n-----END RSA PRIVATE KEY-----\n"
}
}
}
}
trafficparrot.http.jwt.enabled=true
curl -v http://localhost:8080/thrift/management/sendThriftMessage -d send-mapping-id=fc7ee4ad-e247-49a8-8528-af20845adde9 -d send-to-host-port=localhost:5562
"postServeActions" : [ {
"name" : "send-jms-message",
"parameters" : {
"jmsConnectionId" : "(connection id from jms-connections.json)",
"destination" : {
"name" : "queue-name",
"type" : "QUEUE"
},
"variables" : {
"id" : "{{randomValue length=24 type='ALPHANUMERIC'}}"
},
"properties" : {
"id" : "{{variables.id}}"
},
"jsonBody" : {
"id" : "{{variables.id}}",
"fieldFromRequest" : "{{originalRequest.jsonBody.requestField}}",
"fieldFromResponse" : "{{originalResponse.jsonBody.responseField}}"
},
"delayDistribution" : {
"type" : "fixed",
"milliseconds" : 500
}
}
} ]trafficparrot.http.optionsResponse.enabled=true
trafficparrot.gui.forwardToVirtualService.enabled=true
trafficparrot.okta.enabled=false
trafficparrot.okta.clientId=some_client_id
trafficparrot.okta.clientSecret=some_client_secret
trafficparrot.okta.oktaAuthorizeUri=https://${yourOktaDomain}/oauth2/default/v1/authorize
trafficparrot.okta.oktaTokenUri=https://${yourOktaDomain}/oauth2/default/v1/token
trafficparrot.okta.oktaIssuerUri=https://${yourOktaDomain}/oauth2/default
trafficparrot.okta.oktaAudience=api://default
trafficparrot.okta.oktaRedirectUri=https://some-TP-deployment-uri
trafficparrot.virtualservice.containerThreads=100
{{#if (jsonPath request.body '$.[?(@.field)]') }}field is present{{/if}}
{{#if (not (jsonPath request.body '$.[?(@.field)]') ) }}field is not present{{/unless}}
{{#if (jsonPath request.body '$.[?(!(@.field))]') }}field is not present{{/unless}}
{{#unless (jsonPath request.body '$.[?(@.field)]') }}field is not present{{/unless}}
{
"connectionId": "couchbase.db",
"type": "COUCHBASE_CONNECTION",
"connectionString": "couchbase://localhost:32784",
"username": "Administrator",
"password": "password",
"warmupQuery": "SELECT COUNT(*) FROM bucket_a UNION SELECT COUNT(*) FROM bucket_b",
"enableDnsSrv": true,
"networkResolution": "auto"
}
# OFF will turn off validation # DEFAULT_VALIDATION will turn on validation and provide default responses when not annotated # ONLY_ANNOTATED will turn on validation only for annotated specifications trafficparrot.openapi.request.validation.mode=OFF
paths:
/items:
get:
parameters:
# standard OpenAPI parameters with schema definitions
responses:
'400':
content:
application/json:
schema:
# standard OpenAPI response schema definition
x-traffic-parrot-validation: # array of validations that trigger this response codex-traffic-parrot-validation:
- type: schema
response: ${in} parameter ${name} has invalid value ${value} because ${reason}x-traffic-parrot-validation:
- type: schema
response:
code: INVALID_REQUEST
message: ${in} parameter ${name} has invalid value ${value} because ${reason}x-traffic-parrot-validation:
- type: schema
parameters:
- name: style
in: query
- name: limit
in: query
- name: id
in: path
- name: X-Request-Label
in: header
response:
code: INVALID_REQUEST_PARAMETER
message: ${in} parameter ${name} has invalid value ${value} because ${reason}x-traffic-parrot-validation:
- type: schema
parameters:
- name: *
in: requestBody
response:
code: REQUEST_BODY_INVALID
message: Request body has invalid value ${value} because ${reason}x-traffic-parrot-validation:
- type: schema
parameters:
- name: style
in: query
response:
code: INVALID_QUERY
message: query parameter ${name} has invalid value ${value} because ${reason}
- type: schema
response:
code: INVALID_REQUEST
message: ${in} parameter ${name} has invalid value ${value} because ${reason}
{{ modifyResponse 'headerValue' 'header-name-1' 'header-value-1' }}
{{ modifyResponse 'headerValue' 'header-name-2' 'header-value-2' }}
trafficparrotserver.logging.properties.filename=trafficparrotserver.logback.xml
{{ randomValue length=10 type='ALPHANUMERIC' mixedcase=true }}{{ modifyResponse 'headerValue' 'header-name' 'header-value' }}trafficparrot.openapi.import.mode=SELECT_RESPONSE_STATUS trafficparrot.openapi.skeletons.mode=SELECT_RESPONSE_STATUS
trafficparrot.gui.security.mode=LOGIN_PROPERTIES
admin=password,traffic-parrot-gui-role,traffic-parrot-gui-edit-role readonly=password,traffic-parrot-gui-role
{{ dataSource 'couchbase.db' 'INSERT INTO PERSON(KEY, VALUE) VALUES ("$id", {"id" : $id,"name" : $name})' id=1000 name='some-name' syntax='N1QL' }}
{{ dataSource 'couchbase.db' 'SELECT name FROM PERSON USE KEYS "$id"' id=1000 single=true syntax='N1QL' }}
{{ dataSource 'couchbase.db' 'INSERT INTO PERSON(KEY, VALUE) VALUES ("$id", $object)' id=1000 object=example syntax='N1QL' }}
{{#times 10}}{{@index}}{{#unless @last}},{{/unless}}{{/times}}DELETE http://localhost:8080/api/http/mappings/bulk/UUID1,UUID2,UUID3
DELETE http://localhost:8080/api/grpc/mappings/bulk/UUID1,UUID2,UUID3
com.example.Service/method -> host1:port1 com.example.packageA.* -> host2:port2 com.example.packageB.* -> host3:port3
trafficparrot.virtualservice.handlebars.now.provider=HANDLEBARS
trafficparrot.virtualservice.handlebars.now.provider=WIREMOCK
trafficparrot.virtualservice.handlebars.now.dynamic=true
{{now offset='2 years' format='epoch' provider='WIREMOCK'}}{{now format='short' provider='HANDLEBARS'}}trafficparrot.gui.security.mode=LOGIN_PROPERTIES
admin=password,traffic-parrot-gui-role
2020-10-07 20:09:32,330 INFO Request to 'GET /test123' was received on '2020-10-07T19:09:32.326Z' from '127.0.0.1'. Response was sent on '2020-10-07T19:09:32.397Z' to '127.0.0.1'. Total processing time 71ms
trafficparrot.virtualservice.handlebars.select.indexAndCacheCsvFiles=truethe CSV file loading performance will be significantly improved.
javax.servlet.ServletException: java.lang.IllegalStateException: Insufficient configured threads: required=212 < max=200 for QueuedThreadPool[qtp318353283]@12f9af83{STARTED,8<=168<=200,i=0,r=20,q=0}[ReservedThreadExecutor@71b3bc45{s=0/20,p=0}]
The fix is to increase the number of threads Jetty can spin up. This was done by exposing two properties to configure HTTP Jetty server thread queues:
trafficparrot.gui.http.queuedThreadPool.maxThreads=200 trafficparrot.gui.http.queuedThreadPool.minThreads=8
"sslCipherSuite": "TLS_RSA_WITH_AES_128_CBC_SHA", "sslPeerName": "OU=TP IBM MQ"To provide the server and client certificates you can add the following config to jvm.args:
-Djavax.net.ssl.trustStore=certificates/ca-chain.jks -Djavax.net.ssl.trustStorePassword=trafficparrot -Djavax.net.ssl.keyStore=certificates/mq-client.jks -Djavax.net.ssl.keyStorePassword=trafficparrot -Dcom.ibm.mq.cfg.useIBMCipherMappings=false
For more details see Connect to the queue manager via SSL/TLS channels
trafficparrot.ibmmq.logger.logMessageBodyAsPrintableCharacters=false
test@test-pcs:~/Downloads/trafficparrot-no-jre-5.x.y$ export TP_STARTUP_WAIT_MILLIS=180000 test@test-pcs:~/Downloads/trafficparrot-no-jre-5.x.y$ ./start.sh /optf/programs/jdk1.8.0_181/bin/java Picked up environment startup timeout in milliseconds 180000
trafficparrot.ibmmq.start.queue.replay.on.startup.script=classpath:start-ibmmq-queue-replay-on-startup.txt
trafficparrot.ibmmq.connect.options.accessQueue.output=MQOO_OUTPUT|MQOO_FAIL_IF_QUIESCING
trafficparrot.ibmmq.logger.logMessageBody=true
trafficparrot.virtualservice.mapping.cache.milliseconds=0 trafficparrot.virtualservice.mapping.cache.populate.on.startup=false
"readConnectionsToOpen": 5, "writeConnectionsToOpen": 5
"receiveThreads" : 5, "sendThreads" : 1
"maxMessagesInProgress": 1000000
# # This is a sample comment 1 # RequestQueueManager:'Request QM1' ResponseQueueManager:'Response QM1' RequestQueueNames:'REQ_1_A','REQ_1_B' # # This is a sample comment 2 # RequestQueueManager:'Request QM2' ResponseQueueManager:'Response QM2' RequestQueueNames:'REQ_2_A','REQ_2_B'
# # This is a sample comment # QueueManager:'Local Docker MQ 9' ProxyRequestQueue:'PROXY_PROCESS_PAYMENT' LiveRequestQueue:'PROCESS_PAYMENT' LiveResponseQueue:'PAYMENT_PROCESSESED' ProxyResponseQueue:'PROXY_PAYMENT_PROCESSESED' # # This is a sample comment # QueueManager:'Local Docker MQ 9' ProxyRequestQueue:'PROXY_CREATE_ORDER' LiveRequestQueue:'CREATE_ORDER' LiveResponseQueue:'ORDER_CREATED' ProxyResponseQueue:'PROXY_ORDER_CREATED'
This means that the standard WireMock client libraries can be used when connecting to the API port e.g. when using WireMock.configureFor("localhost", 8080, "/api/http");
Custom HTTP clients or a browser may continue to drop the /__admin section of the path so that API calls such as http://localhost:8080/api/http/mappings can be made
#
# Template used for gRPC mapping file names
#
# Available properties:
# {{ mapping.id }}
# {{ mapping.package }}
# {{ mapping.service }}
# {{ mapping.method }}
# {{ mapping.isSuccess }}
# {{ mapping.status.name }}
# {{ mapping.status.code }}
#
# Available commands:
# {{ countGrpcMappings package=mapping.package service=mapping.service method=mapping.method success=true offset=1 format='%02d' }}
trafficparrot.virtualservice.grpc.saved.mapping.file.name.template={{ mapping.package }}.{{ countGrpcMappings package=mapping.package offset=1 format='%02d' }}.{{ mapping.service }}-{{ mapping.method }}[{{ mapping.status.name }}]
trafficparrot.virtualservice.grpc.saved.mapping.file.name.collision.suffix.template=-{{ mapping.id }}
UNKNOWN: Traffic Parrot Virtual Service: No responses matched the given request. See the Traffic Parrot logs for more details.
Request was not matched
=======================
-----------------------------------------------------------------------------------------------------------------------
| Closest stub | Request |
-----------------------------------------------------------------------------------------------------------------------
|
helloworldgreetersayhello-38d8ac56-38fe-4a57-89b3-5af8368 |
874a5.json |
|
ANY | ANY
helloworld.Greeter/SayHello | helloworld.Greeter/SayHello
|
Protocol: GRPC | Protocol: GRPC
|
{ | { <<<<< Body does not match [equalToJson]
"inputName" : "example" | "inputName" : "not matching"
} | }
|
-----------------------------------------------------------------------------------------------------------------------
Configure how long to cache the proto files during replay using the trafficparrot.virtualservice.grpc.server.replay.proto.cache.milliseconds property.
A value of 0 means do not cache at all.
Configure the number of boss and worker threads of the gRPC server using the trafficparrot.virtualservice.grpc.server.boss.threads and trafficparrot.virtualservice.grpc.server.worker.threads properties.
The special value DOUBLE_NUMBER_OF_PROCESSORS means use double the number of processors.