Giter Club home page Giter Club logo

cloud-bigtable-clients-test's Introduction

Test Framework for Cloud Bigtable Client Libraries

This repository contains the test framework to validate the correctness of Cloud Bigtable client libraries. Specifically, all of the client libraries should exhibit correct and consistent behaviors when interacting with the server (e.g. retry on transient error) However, writing test cases in every language would present maintainability and scalability challenges.

This framework allows test logic to be written once and run for any client implementation. The tests can be run on different operating systems, but the examples in this document assume you are using Linux.

The Framework

The test framework consists of three components: test cases, test proxy, and mock server. With the client library involved, we use the diagram below to illustrate the life of a test case.

The test case first starts a mock server, then sends a test request through the test proxy, and tears down the mock server after finish.

The test proxy exposes the client API via an RPC service: it translates the request from the test case into an API call to the client library, and the return values of the client library are assembled by the test proxy into a response to the test case. As the proxy runs in a separate process and communicates with the test program via gRPC, different languages of the client library are supported.

This doc describes how to implement a test proxy. Please use the doc if you want to onboard a Cloud Bigtable client library.

Test Execution

Basic usage

Assuming you have built the proxy binary already, then you can do the following:

  1. Install Golang (Instructions)

  2. Set environment variable if you don't have gcc installed

    $ export CGO_ENABLED="0"
  3. Download the test code

    $ git clone https://github.com/googleapis/cloud-bigtable-clients-test.git
  4. Bring up the test proxy with an unused port. Java example:

    $ java -jar target/google-cloud-bigtable-test-proxy-0.0.1-SNAPSHOT.jar
  5. Change directory to the folder tests, and do

    $ go test -v -proxy_addr=:9999

    To run tests that use a local Bigtable emulator, the command is

    $ go test -v --tags=emulator -proxy_addr=:9999

Advanced usage

You may want to run/skip a subset of test cases. As of Go 1.20, we can achieve the goal with a well-designed naming convention.

The command is

$ go test -v -run <test name regex> -proxy_addr=:9999

or

$ go test -v -skip <test name regex> -proxy_addr=:9999

In the above command, <test name regex> will try to match a substring of each test name. For more information, please refer to the online doc. Here are some simple examples:

  • TestReadRows_ selects all the test cases exercising “ReadRows”.
  • TestReadRows_Retry_ selects all the test cases exercising the “Retry” behaviors of “ReadRows”.
  • _Retry_ selects all the test cases that contain “_Retry_” in the names.
  • _NoRetry_\|_Generic_ selects all the test cases that contain “_NoRetry_” or “_Generic_” in the names.
  • A full name can be used to only run the specific test case (good for troubleshooting).

Troubleshooting Tips

If you experience a test failure, the printout of the error may already provide hints for failure resolving. In addition, you can use logging to uncover less obvious problems. The subsections below provide some recommendations.

Logging in the test case

You can use t.Logf() to print out the variables you care about. For example, to check the response of test proxy, you can do

t.Logf("Response of test proxy: %+v", res)

Logging in the mock server

We have added flag-guarded logging to print out the requests from the client library. To enable it, please use

$ go test -v -run <test name> -proxy_addr=:9999 -print_client_req

Logging in the test proxy

To check if the test proxy receives the expected request from the test case, you can print it out at the proxy method’s entry point. Java example:

logger.info("Request from test:\n" + request.toString());

To check if the test proxy receives the expected return value from the client library, you can print it out right after the client method call. Java example:

row = client.dataClient().readRow(...);
logger.info("readRow() returns:\n" + row.toString());

Logging in the client library

You may add logging to the client library to check if it receives the expected parameters from the proxy or responses from the server.

Additional tips

  • At the end of a test case, the client object will be deleted. So please make sure the proxy method RemoveClient() is implemented correctly.
  • If you terminate the running test via “Ctrl+C”, you will leave behind the client objects, which will lead to collision of client IDs in the resumed execution. In this case, you need to restart the test proxy server to have a clean state.
  • If you have additional questions or issues, please file issues.

cloud-bigtable-clients-test's People

Contributors

bhshkh avatar brandtnewton avatar dbolduc avatar dependabot[bot] avatar google-cloud-policy-bot[bot] avatar igorbernstein2 avatar liujiongxin avatar meagar avatar mutianf avatar renovate-bot avatar telpirion avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cloud-bigtable-clients-test's Issues

Assertion inside loop in BulkMutateRows tests

While implementing the python test_proxy, I noticed a bunch of the tests make assertions only inside a for loop. Example:

	for _, entry := range res.GetEntries() {
		outputIndices = append(outputIndices, int(entry.GetIndex()))
		assert.Equal(t, int32(codes.PermissionDenied), entry.GetStatus().GetCode())
	}

The intention seems to be to make sure the client reports all entries failed with the same exception, but my code can pass the tests by returning a full success response, where the list of failures is empty. We should probably add a check that res.GetEntries() returns the number of entries that we expect

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Detected dependencies

gomod
go.mod
  • go 1.19
  • cloud.google.com/go/bigtable v1.22.0
  • github.com/golang/protobuf v1.5.4
  • github.com/google/go-cmp v0.6.0
  • github.com/stretchr/testify v1.9.0
  • google.golang.org/api v0.172.0
  • google.golang.org/genproto v0.0.0-20240412170617-26222e5d3d56@26222e5d3d56
  • google.golang.org/genproto/googleapis/api v0.0.0-20240401170217-c3f982113cda@c3f982113cda
  • google.golang.org/genproto/googleapis/rpc v0.0.0-20240412170617-26222e5d3d56@26222e5d3d56
  • google.golang.org/grpc v1.63.2
  • google.golang.org/protobuf v1.33.0

  • Check this box to trigger a request for Renovate to run again on this repository

Backoff timing verification can flake

googleapis/google-cloud-cpp#12913

=== RUN   TestMutateRows_Retry_ExponentialBackoff
    mutaterows_test.go:347: The three retry delays are: 111ms, 106ms, 353ms
    mutaterows_test.go:350: 
        	Error Trace:	/var/tmp/downloads/cloud-bigtable-clients-test/tests/mutaterows_test.go:350
        	Error:      	"111" is not less than "106"
        	Test:       	TestMutateRows_Retry_ExponentialBackoff
--- FAIL: TestMutateRows_Retry_ExponentialBackoff (0.63s)

C++ has unit tests in our code that verify that the retry policy always increases. There is jitter (randomness) involved.

I think it is very likely that the computer running the build had a hiccup during the first attempt to add an extra few ms of slowness. And the backoff duration on the second attempt happened to be very close to the backoff duration of the first attempt. Thus the proxy detects a failure.

To bandaid, we can add a few ms of tolerance to the backoff expectations. But ultimately we are at the mercy of a time based test.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.