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.