Quarkus Tip: Testing a Google Cloud function

Quarkus Tip: Testing a Google Cloud function

I recently contributed a PR to Quarkus that contains a testing framework for Google Cloud functions.

Quarkus supports creating Google Cloud functions three different ways:

  • Using the Google Cloud API.
  • Using a Quarkus HTTP extension: RESTEasy, Reactive routes, Servlet, Spring Web.
  • Using Funqy, the cloud provider agnostic Quarkus function API.

But until now, to test these functions, you had to package them and launch them locally via the function invoker provided by the Google SDK. The function invoker is a JAR you can download that can then be used to launch a function. Not very practical to use, and especially, does not allow to be used for automated unit tests.

Functions using an HTTP extension of Quarkus could implement a unit test in a traditional way, but in this cas they would not use a function environment. So the test would not reproduce a function execution close to reality.

With Quarkus 2.15, a framework for testing Google Cloud functions exists that allows to test a function via HTTP calls. This framework will use the function invoker and start it automatically when the test is launched. You can then use REST-assured to test your function as you would for a standard Quarkus application.

To use this test framework, you need to add the following Maven dependency:

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-test-google-cloud-functions</artifactId>
    <scope>test</scope>
</dependency>

Testing a function that uses the Google Cloud Function API

The following function uses the Google Cloud Function API to implement an HTTP function that responds “Hello World”.

@ApplicationScoped // Needed for Quarkus to locate the function
public class HttpFunctionTest implements HttpFunction { 
    @Inject GreetingService greetingService; 

    @Override
    public void service(HttpRequest httpRequest, HttpResponse httpResponse) throws Exception { 
        Writer writer = httpResponse.getWriter();
        writer.write(greetingService.hello());
    }
}

The corresponding test will be a standard Quarkus test, annotated via @QuarkusTest, but will use the @WithFunction annotation that allows the function to be launched using the Google Cloud functions invoker. The @WithFunction annotation takes as an attribute the type of the function to be launched, in this case FunctionType.HTTP because it is an HTTP function.

@QuarkusTest 
@WithFunction(FunctionType.HTTP) 
class HttpFunctionTestCase {
    @Test
    public void test() {
        when()
                .get()
                .then()
                .statusCode(200)
                .body(is("Hello World!")); 
    }
}

The test uses REST-assured to send an HTTP request with the GET method, and assert that the response has a status code 200 and contains the string “Hello World”.

We can write the same type of test for a background function.

Let’s take as an example a background function triggered from a Cloud Storage event:

@ApplicationScoped  // Needed for Quarkus to locate the function
public class BackgroundFunctionStorageTest implements BackgroundFunction<BackgroundFunctionStorageTest.StorageEvent> { 
    @Override
    public void accept(StorageEvent event, Context context) throws Exception { 
        System.out.println("Receive event: " + event);
    }

    // The Cloud Storage event will be deserialized with this class
    public static class StorageEvent { 
        public String name;
    }
}

It can be tested with the following code:

@QuarkusTest
@WithFunction(FunctionType.BACKGROUND) 
class BackgroundFunctionStorageTestCase {
    @Test
    public void test() {
        given()
                .body("{\"data\":{\"name\":\"hello.txt\"}}") 
                .when()
                .post()
                .then()
                .statusCode(200);
    }
}

Here, the test is of type FunctionType.BACKGROUND, and we send the event to the function via a POST request whose body is a JSON whose data attribute contains the event triggering the function.

Cloud Events functions are also supported.

More information in the guide Quarkus Google Cloud Functions.

Testing a function that uses Quarkus Funqy

It is possible to write a Google Cloud function reacting to a Cloud Storage event via the Funqy framework. Funqy provides a cloud provider agnostic API. To use Funqy, you need to write a Java method annotated with @Funq, which takes the function’s trigger event as a parameter.

public class GreetingFunctions {
    @Funq 
    public void helloGCSWorld(StorageEvent storageEvent) {
        String message = service.hello("world");
        System.out.println(storageEvent.name + " - " + message);
    }
}

To test this function, we’ll use the same code as for a function using the Google Cloud API, but we’ll configure the test framework for a function of type FunctionType.FUNQY_BACKGROUND.

@QuarkusTest 
@WithFunction(FunctionType.FUNQY_BACKGROUND) 
class GreetingFunctionsStorageTest {
    @Test
    public void test() {
        given()
                .body("{\"data\":{\"name\":\"hello.txt\"}}") 
                .when()
                .post()
                .then()
                .statusCode(200);
    }
}

Here again, Cloud Events are also supported.

More information in the guide Quarkus Funqy Google Cloud Functions.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.