🚀 Exciting news for Python developers! 🐍🎉

🚀 Exciting news for Python developers! 🐍🎉

Oct 3, 2023

Skyramp Feature Highlight: Using Dynamic Python for Tests and Mocks

#python #testing #kubernetes #microservices

Python developers, rejoice! Skyramp now supports Python code for dynamically testing and mocking your distributed applications. Previously, Skyramp supported only JavaScript for dynamic requests and responses within test and mock description files. In this blog post, we'll walk you through Skyramp's new capability of employing dynamic Python code in requests and responses for testing and mocking microservices, right from a running Kubernetes cluster.

Unpacking Skyramp Tests

Before diving into the step-by-step example, let's first lay the foundation by understanding what constitutes a Skyramp test. At the heart of every Skyramp test is a test description file. This file can either be auto-generated using skyramp tester generate or created manually as a .yaml file.

What's Inside a Test Description?

Within a Skyramp test description file, you define the essential components of your test. This includes the scenarios for testing, the services to be tested, the requests you'll make to them, the expected responses in the form of asserts, and any custom logic or handlers to process these interactions. Let's dissect the important elements.

Here's a simple scenario in a test description:

  - name: scenario1
    - request: request1
    - asserts: requests.request1.res.message == "abc"

The scenario above simply tests if the message returned from a service is equal to "abc". Below is an example request to support the scenario above. We can assume this hypothetical service takes an id and returns a message. Both of these YAML sections are contained within a Skyramp test description file.

  - name: request1
    endpoint: our-service
    method: GetMessage
      blob: |
            "id": "123"

Notice the block under requestValue. It is configured as a static blob in this example, but it can also be configured as dynamic code that the Skyramp Worker will execute during a test. The language used in a dynamic handler had been limited to JavaScript, but now you can use Python! Let's look at how.

A Hands-on Example: Testing with Python Code

To illustrate how Python can now be harnessed in Skyramp tests, let's embark on a simple journey you can follow yourself. We'll clone a sample project from a Skyramp-provided repo on GitHub, which conveniently contains microservices that can be swiftly deployed to a Kubernetes cluster, all primed and ready for testing.

Paving the Way with the Skyramp CLI

First, make sure you have the Skyramp CLI installed. The Skyramp CLI enables the Deployer, Mocker, and Tester tools. You can follow these easy steps from the Skyramp Docs for installation.

Cloning the Project

Start with cloning Skyramp's letsramp/sample-microservices repo, which is a sample e-commerce system that includes a number of microservices. See the GitHub repo Readme for additional information. The Skyramp repo is based on Google Cloud's Online Boutique, adding test demos and support for REST and Thrift APIs.

From a terminal, you can execute this command:

git clone https://github.com/letsramp/sample-microservices.git

Start your Cluster

Now that the project is in place, you can navigate to the grpc-demo directory in your terminal and bring up a local cluster for testing by executing these three commands:

cd sample-microservices/skyramp/grpc-demo
skyramp cluster create --local
skyramp deployer up checkout-system

Putting Python to the Test

With the system-under-test up and running, let's edit one of the tests to show where we can insert Python code that will be run dynamically during testing. The tests/checkout-test.yaml test description file contains a requests section with a static blob. Edit the section under requestValue for request1 as follows:

  - name: request1
    endpoint: cart-service
    method: AddItem
      python: |
        def handler():
          uid = "abcde"
          qty = 5 * 5
          pid = "OLJCE"
          pid += "SPC7Z"
          request_value = {
            "userId": uid,
            "item": {
                "productId": pid,
                "quantity": qty
          return SkyrampValue(value=request_value)

You can see we replaced the blob attribute with python and are now creating the request values in code. To learn more about the specific details of how you can use Python in test descriptions, visit the Skyramp Docs that cover Python Dynamic Requests.

You will notice that the tests/checkout-test.yaml test description file has two requests. The first request, shown above as request1, adds an item to the cart. The second request, request2, places an order. We will leave the requestValue in request2 as a static blob.

For our test scenario under scenarios, we first make a request to request1 and then make a request to request2. The existing assert checks that the productId matches the first item returned in the response from request2. Let's also add an asserts line in the same file to check the quantity value returned. This should match the quantity we set in request1. Notice the type is a number and not a string.

  - name: scenario1
      - request: request1
      - request: request2
      - asserts: requests.request2.res.order.items[0].item.productId == "OLJCESPC7Z"
      - asserts: requests.request2.res.order.items[0].item.quantity == 25

We are almost ready to run our new test scenario with Python, but we are missing one final piece. We know our checkout depends on the payment service, but it is not running in our system-under-test. Luckily, we have a mock for that.

Yes, Mocks Too!

Not only is Python available for dynamic requests in the test description, but Python is also available for dynamic responses in the mock description.

Open mocks/payment-service-k8s.yaml for editing, which is also under the skyramp/grpc-demo folder in the letsramp/sample-microservices repo.

Change the section under responseValues to include the python attribute and the code shown below:

    - name: ChargeResponse
      python: |
        def handler(req):
          key = "transaction_id"
          value = "default-string"
          return SkyrampValue(value={key: value})

Here, we now return values from Python-generated variables instead of a static blob as before. To learn more about the specific details of how you can use Python in mock descriptions, visit the Skyramp Docs that cover
Python Dynamic Responses

Mocking and Testing with Skyramp

With our new test description and mock description updated to include dynamic Python, we can proceed with our test session. Skyramp makes running tests a breeze.

First, apply the mock that was updated with Python code:

skyramp mocker apply -n test-grpc-demo

You should see this output in the terminal:

Applying mock config     [##############################################################] 100 %
Successfully applied mock configurations

Next, run the test that was updated with Python code:

skyramp tester start checkout-test -n test-grpc-demo

The test results should produce the following output:

- pattern0.scenario1.2.assert
    [Status: finished] [Started at: N/A]
    Assert: requests.request2.res.order.items[0].item.productId == "OLJCESPC7Z"
    Passed: true
  - pattern0.scenario1.3.assert
    [Status: finished] [Started at: N/A]
    Assert: requests.request2.res.order.items[0].item.quantity == 25
    Passed: true

Nice job, you did it! This was just a simple taste to show how to use Python for tests and mocks, but there is much more to explore. Additional capabilities include:

Wrapping Up

That concludes our exploration of using Python code in Skyramp tests and mocks. Now Python developers can leverage their skills to create comprehensive and robust testing scenarios. We hope you've enjoyed this glimpse into using Python for dynamic requests and responses in testing distributed applications with Skyramp.

Stay tuned for more updates and enhancements as Skyramp continues to evolve, enabling developers to optimize their testing processes like never before. Happy testing!

© 2024 Skyramp, Inc. All rights reserved.

© 2024 Skyramp, Inc. All rights reserved.

© 2024 Skyramp, Inc. All rights reserved.