Tuesday, 10 December 2024

Using Handlebars for Date Comparisons in Response Logic in Traffic Parrot

 We received a question recently from one of our prospects.

"I wanted to know about the advanced usage of dynamic rules. How do I add scripting for my response logic? I need some date comparisons for calculating some fields values, is it possible to with scripting or handlebars?" - Software Developer working for a gaming company.

You can add scripting to your response login with scripts or handlebars. Here is the documentation on how to do that: https://trafficparrot.com/documentation/5.50.x/dynamic.html  

Handbars should be enough for this simple case of comparing dates.

For example, you can add this into your response body like on the screenshot displayed below:

{{#if (gt (date (parseDate request.query.SomeDate format='dd-MM-yyyy')) (date (now)))}}
Response if the defined date is after now
{{else}}
Response if the defined date is not after now
{{/if}}

This code compares SomeDate request query parameter with today's date and returns a different response based on that comparison. 

Here is an example result:

support@support-pcs:/optf/git$ curl http://localhost:8081/hello?SomeDate=01-01-2024
Response if the defined date is not after now
support@support-pcs:/optf/git$ curl http://localhost:8081/hello?SomeDate=01-01-2025
Response if the defined date is after now


Friday, 6 December 2024

How to configure Traffic Parrot log level at runtime in Docker

We got a question from one of our customers about how to configure the log level at runtime when using Traffic Parrot in Docker.
How to pass environment variables to Docker
The Dockerfile CMD command can be modified to accept environment variables as follows:
ENV GUI_HTTP_PORT=8080
ENV VS_HTTP_PORT=8081
CMD exec ./start-foreground.sh \
    trafficparrot.gui.http.port=$GUI_HTTP_PORT \
    trafficparrot.virtualservice.http.port=$VS_HTTP_PORT
How to set the logging level dynamically with Docker environment variables
First the Dockerfile can be configured with an environment variable:
ENV LOG_LEVEL=ERROR
This can be then be configured for use:
  • trafficparrotserver.log4j.properties can be configured with:
    log4j.rootLogger=${LOG_LEVEL},file,stdout
    And the Dockerfile with:
    CMD exec ./start-foreground.sh -DLOG_LEVEL=$LOG_LEVEL
  • trafficparrotserver.log4j2.xml can be configured with:
    <Root level="${env:LOG_LEVEL}">
  • trafficparrotserver.logback.xml can be configured with:
    <root level="${LOG_LEVEL}">

Thursday, 21 November 2024

How to Increment Order Numbers in Dynamic Responses

 We just got a question from one of our customers.

"How do I add +1 here? (jsonPath request.body '$.orderNumber')" - Software Developer working for a Spanish company

You can use the math helper, for example:

{{math (jsonPath request.body '$.orderNumber') '+' 1}}

Wednesday, 20 November 2024

Implementing Controlled Chaos: How to Simulate API Failures with Time-Based and Random Error Responses

We just got a question from one of our prospects:

"How can I implement conditional error responses in my API mocks? Specifically, I want to:

  • Return an error every 100th API call
  • Return an error based on system time (e.g., every 10 minutes)
For a specific endpoint like 'hello':
  • Return a normal JSON response for most requests
  • Return an error response after every 1000 requests
The error responses should work seamlessly with my existing mock responses. What's the best way to implement this kind of controlled failure testing?" - Software Developer 

He is a sample of how you can return an error for a single mock whenever the minute is in the 10s (10, 20, 30,...), and every 100 requests randomly return an error as well.
This is for a single mock. You can also do it for all mocks or selected mocks, depending on your requirements, with a different solution, etc., which we are happy to share.
So please share your business requirement or testing scenario you are looking for with support@trafficparrot.com 

Paste this in the response body (see screenshot attached):
{{#with (now format='mm') as |currentMinute|}}
{{#with (randomInteger 1 101) as |requestId|}}
{{#if (or
    (eq (math currentMinute '%' 10)  "0")
    (eq (math requestId '%' 100) "0")
)}}{{modifyResponse 'statusCode' 503}}
{
    "error": "Service temporarily unavailable",
    "details": "Error triggered by time (10 min interval) or simulated request count",
    "currentMinute": {{currentMinute}},
    "requestId": {{requestId}}
}
{{else}}
{
    "normalResponse": "This is your regular JSON response",
    "timestamp": "{{now format='yyyy-MM-dd\'T\'HH:mm:ss.SSSXXX'}}",
    "requestId": {{requestId}}
}
{{/if}}
{{/with}}
{{/with}}

You can test the randomness by running:
support@support-pcs:~/tmp$ for i in {1..1000}; do echo "Request $i"  && curl -v http://localhost:8081/hello >> test_random.log 2>&1 && echo -e "\n---" >> test_random.log; done
support@support-pcs:~/tmp$ grep  "Service temporarily unavailable" test_random.log | wc -l
10
support@support-pcs:~/tmp$ grep -B 20 "Service temporarily unavailable" test_random.log | head -n 20
> GET /hello HTTP/1.1
> Host: localhost:8081
> User-Agent: curl/7.81.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 503 Service Unavailable
< Matched-Stub-Id: 8c4695d4-f94e-4ba8-9793-ee5dcbfba6b5
< Matched-Stub-Name: hello-8c4695d4-f94e-4ba8-9793-ee5dcbfba6b5.json
< Content-Length: 201
< Server: Jetty(9.4.56.v20240826)
<
{ [201 bytes data]
100   201  100   201    0     0  54046      0 --:--:-- --:--:-- --:--:-- 67000
* Connection #0 to host localhost left intact

You can test the time error response by running:
support@support-pcs:~/tmp$ while true; do current_time=$(date +"%H:%M:%S"); echo "Time: $current_time" && curl -i http://localhost:8081/hello && echo -e "\n-------------------\n" && sleep 10; done



Tuesday, 19 November 2024

Extracting Filename from HTTP Request Body in Traffic Parrot Response Template

We got a question yesterday from one of our prospects.

"Is it possible to get a filename from a HTTP request body byte array? Can you send me an example?" - Software Developer evaluating Traffic Parrot

Yes! The simplest way to do this is using a regexp. For example, create a mapping where the response body is (see attached screenshot for details):

{{ regex request.body 'filename=\"([^\"]+)\"' 'g' }}

You can then test it like this for example:

support@support-pcs:~/Downloads$ curl -X POST http://localhost:8081/hello -H "Content-Type: multipart/form-data" -F "file=@helloworld.pdf" -v

Note: Unnecessary use of -X or --request, POST is already inferred.
*   Trying 127.0.0.1:8081...
* Connected to localhost (127.0.0.1) port 8081 (#0)
> POST /hello HTTP/1.1
> Host: localhost:8081
> User-Agent: curl/7.81.0
> Accept: */*
> Content-Length: 7497
> Content-Type: multipart/form-data; boundary=------------------------1417eab3cd6fdb0a
>

* We are completely uploaded and fine
* Mark bundle as not supporting multiuse

< HTTP/1.1 200 OK
< Matched-Stub-Id: 8c4695d4-f94e-4ba8-9793-ee5dcbfba6b
< Matched-Stub-Name: hello-8c4695d4-f94e-4ba8-9793-ee5dcbfba6b5.json
< Vary: Accept-Encoding, User-Agent
< Content-Length: 41
< Server: Jetty(9.4.56.v20240826)
<
Request contains a file: helloworld.pdf



Thursday, 7 November 2024

Traffic Parrot 5.50.1 released, what's new?

We have just released version 5.50.1. Here is a list of the changes that came with the release:

Features

Fixes

  • Library upgrades to fix OWASP issues

Saturday, 12 October 2024

Traffic Parrot 5.49.0 released, what's new?

We have just released version 5.49.0. Here is a list of the changes that came with the release:

Features

  • Added support for the JWT Extension for WireMock
  • JWT usage examples, typically mocked via an /oauth/token endpoint:
    {{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')
    }}
  • JSON Web Key Set (JWKS) usage example, typically mocked via an /.well-known/jwks.json endpoint:
    {{jwks}}
  • Settings also visible via http://localhost:8080/api/http/__admin/settings as
    {
      "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"
          }
        }
      }
    }
    
  • Enable in trafficparrot.properties by setting:
    trafficparrot.http.jwt.enabled=true

Fixes

  • Library upgrades to fix OWASP issues

Thursday, 27 June 2024

Traffic Parrot 5.48.0 released, what's new?

We have just released version 5.48.0. Here is a list of the changes that came with the release:

Features

  • New Thrift API to send a request by mapping id:
    curl -v http://localhost:8080/thrift/management/sendThriftMessage -d send-mapping-id=fc7ee4ad-e247-49a8-8528-af20845adde9 -d send-to-host-port=localhost:5562
  • Thrift message recordings are now in JSON format
  • New {{ executeProcess '/bin/bash' '-c' 'echo hello' }} helper to execute external processes

Fixes

  • Fixed a Thrift issue when the same method name is defined in super and subclass
  • Fixed a Thrift issue with methods that are prefixes/suffixes of other methods

Changes

  • Thrift compiler binary must be version 0.10.0 for backwards compatibility reasons

Monday, 10 June 2024

The Executive's Guide to Shift-Left Testing: Beyond the Buzzword

What is Shift-Left Testing?

At its core, shift-left testing means moving quality assurance activities earlier in the software development lifecycle. Rather than waiting until development is complete to begin testing, quality becomes integrated from day one. But the actual value goes far beyond just testing earlier.

The Business Case

According to our data, organizations implementing shift-left testing are seeing remarkable results:

  • At least 43% faster software releases
  • At least 38% fewer customer-facing issues
In this example, we calculated the ROI for one of our clients. For their typical release, they would get $800,000 in net return and a 15-day speed-up in release schedules for a modest developer's time investment.

These benefits come from three key areas:

1. Reduced rework and context-switching costs

2. Faster time to market through parallelized development

3. Higher quality through early defect detection

Beyond Testing: A Requirements-First Approach

The most successful implementations treat shift-left testing as more than moving QA earlier. It becomes a requirements-first approach where business needs are captured as automated tests before development begins.

When business stakeholders are asked, "How will you know if this feature works as intended?" Their answers become the acceptance criteria and automated tests. This ensures alignment between business needs and technical implementation from the start.

Implementation Framework

Here's how our clients are successfully implementing shift-left testing:


Phase 1: Pilot Program (1-2 months)

- Select 1-3 teams for initial implementation

- Focus on high-visibility, moderate-risk initiatives

- Provide tools and training for API-first development and test automation

- Measure baseline metrics for comparison


Phase 2: Scale Success (3-6 months) 

- Document learnings and patterns from pilot teams

- Create an internal community of practice

- Roll out to additional teams in waves


Phase 3: Enterprise Transformation (6-24 months)

- Integrate shift-left practices into standard methodologies

- Update governance and funding models

- Implement cross-team metrics and reporting

- Continue optimization based on data


Key Success Factors

  1. Executive Sponsorship: Position quality as a business driver, not just a technical concern
  2. Tool Selection: Provide teams with the right tools for test automation, API mocking, and continuous testing
  3. Skills Development: Invest in upskilling developers and QA professionals in new practices
  4. Metrics Focus: Track both technical and business metrics to demonstrate value:
    • Decrease in production issues
    • Faster time to market
    • Time to recover from a production incident

Conclusion

Shift-left testing, when implemented properly, drives significant business value through faster delivery, higher quality, and lower costs. Success requires executive commitment, the right tools and practices, and a focus on business outcomes rather than just technical metrics.

By starting small, measuring results, and scaling success, organizations can transform their software delivery capabilities while maintaining stability and managing risk.

Thursday, 6 June 2024

Traffic Parrot 5.47.1 released, what's new?

We have just released version 5.47.1. Here is a list of the changes that came with the release:

Features

Fixes

  • Fixed an {{ objectStore }} bug where a deadlock could occur with multiple usages in the same response
  • Fixed an issue with startup logging

Tuesday, 7 May 2024

Troubleshooting Nested Handlebars Each Loops in Traffic Parrot

When working with nested data structures in Traffic Parrot mock responses, you may encounter unexpected behaviour with nested {{#each}} loops, mainly when using the @index variable. Here's how to handle this common issue.

The Problem

Consider a request containing nested arrays, such as a list of customers, each with multiple contact methods:

{
  "customerId": "ABC123XYZ",
  "details": [
    {
      "name": { "first": "John" },
      "contacts": [
        {
          "region": "123",
          "identifier": "5551234567",
          "category": "PRIMARY"
        },
        {
          "region": "123",
          "identifier": "5551234568",
          "category": "SECONDARY"
        }
      ]
    }
  ]
}


When using nested {{#each}} loops without named loop variables, the @index variable may reference the outer loop's index instead of the intended inner loop's index.

The Solution

To correctly handle nested loops, always use named loop variables in your {{#each}} statements:

{{#each (jsonPath request.body '$.details') as |details| }}
{ "customerId": "{{ jsonPath request.body '$.customerId' }}", "status": "SUCCESS", "statusDescription": "Customer record created", "details": [
{{#each details.contacts as |contact| }}
{ "region": "{{ contact.region }}", "identifier": "{{ contact.identifier }}", "category": "{{ contact.category }}" }{{#unless @last}},{{/unless}} {{/each}} ] }{{#unless @last}},{{/unless}} {{/each}}

Best Practices

  1. Always name your loop variables in {{#each}} statements
  2. Use descriptive variable names that reflect the data being iterated
  3. Remember to handle comma separators using {{#unless @last}},{{/unless}}

Tuesday, 30 April 2024

How should data pipeline teams test their products?

Our client is looking to expand the usage of our tooling at their enterprise, and among many teams, we talked to a data pipeline team.

The advice we have given them was to:
1. Write automated tests for their data pipelines
2. Consider shift-left testing of their data pipelines
3. Use an API design-first approach when integrating with other teams

Thoughtworks has two great articles with an introduction to testing data pipelines and ML quality:

We recommended to this team that they use an API design-first approach as described in the article we published a while back https://www.infoq.com/articles/api-mocking-break-dependencies/ 

API-first and API-mocks will allow their consumer teams to start working on their critical features before the data pipeline and ML code are ready, reducing the time to market for the new critical functionality, which will make the product managers and users very happy!

Contact us for a free-of-charge, no-obligation 30-minute call if you would like to discuss how design-first APIs can help accelerate critical deliverables at your organization.

Sunday, 21 April 2024

Traffic Parrot 5.46.7 released, what's new?

We have just released version 5.46.7. Here is a list of the changes that came with the release:

Features

  • Added support for sending one or more JMS text messages after an HTTP or gRPC response, configured via mapping JSON:
    "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
          }
        }
    } ]
  • Added additional Okta JWT access token verification
  • Added gRPC native transport for Apple ARM based processors

Fixes

  • Fixed desktop issue where the start and stop scripts would steal focus on launch
  • Fixed logging issue where HTTP and HTTPS GUI ports would be printed in the logs even if a port is disabled
  • Fixed a DNS resolution failure issue on Mac
  • Improved OpenAPI parser compatibility
  • Improved error message when script runtime is missing

Changes

  • Upgraded bundled JRE from 8u392 to 8u402
  • Upgraded gRPC from 1.60.0 to 1.63.0
  • This release is compatible with the MQ com.ibm.mq.allclient JAR up to version 9.3.4.1
  • When using IBM MQ Advanced for Developers Docker icr.io/ibm-messaging/mq:9.3.4.0-r1 and above, MQ_APP_PASSWORD must be set for the app user, the default lack of password is no longer supported by the container
  • IBM MQ username and password are now interpreted as null if set to "" or "null" in the connection JSON configuration
    • To configure a "" value use "<empty>"
    • To configure a "null" value use "<null>"
  • Improved JMS message logging for null property values
  • Library upgrades to fix OWASP issues

Thursday, 28 March 2024

Large Enterprise Service Virtualization


Large enterprises use a wide variety of software architectures (Monolith running on VMs 
Microservices running in ephemeral containers, Cloud-native serverless).

Tools that fit one paradigm do not fit well with other paradigms. For example, teams use different tech stacks specialized in monolithic architectures or microservice architectures.

Enterprise Archiecture teams must provide solutions to product teams to support all use cases.

Thursday, 14 March 2024

Traffic Parrot 5.45.0 released, what's new?

We have just released version 5.45.0. Here is a list of the changes that came with the release:

Features

  • Added support for default HTTP OPTIONS response based on the current HTTP mappings, enabled by:
    trafficparrot.http.optionsResponse.enabled=true
  • Added support for accessing HTTP VS using the UI port, enabled by:
    trafficparrot.gui.forwardToVirtualService.enabled=true
  • Added support for Okta SSO integration, enabled by:
    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

Friday, 12 January 2024

Traffic Parrot 5.44.0 released, what's new?

We have just released version 5.44.0. Here is a list of the changes that came with the release:

Features

  • Added support for zero response messages in server streaming record/replay gRPC

Fixes

  • Library upgrades to fix OWASP issues
  • Exposed properties to allow changing maximum HTTP header size:
    trafficparrot.virtualservice.jettyHeaderRequestSize=8192
    trafficparrot.virtualservice.jettyHeaderResponseSize=8192

Changes

  • Reduced default HTTP container threads from 500 to 100:
    trafficparrot.virtualservice.containerThreads=100