So you’ve been developing an application using the Go programming language with a team of developers for your organization. Best practice would say that you need to create proper tests and develop a continuous integration and deployment strategy.

If you’ve been keeping up with my tutorials, you’ll remember that I wrote about creating a continuous deployment pipeline with Node.js and Jenkins. This time around we’re going to change things up with the development technology and CI / CD service.

We’re going to see how to continuously deploy a Golang application that interacts with Couchbase with the popular Travis CI service.

The goal of this tutorial is to help you create a Golang application that communicates with Couchbase. This application will have proper unit tests that will be used when Travis CI is triggered. If the tests are successful in Travis CI, the application will be automatically deployed to some remote server with SSH.

As a prerequisite, you will need to have at least one Couchbase Server instance available to you. This Couchbase Server instance will be used during deployment.

Developing an Application with Go and Couchbase NoSQL

We’ll be creating a fresh Golang project for this example. Somewhere in your $GOPATH create a file called main.go and include the following:

The above code is simple, but will change significantly as we progress in this tutorial. For now, let’s figure out what it does.

Because we’re using Couchbase, we need to have obtained the Go SDK. This can be installed by executing the following:

With the Go SDK installed, we can add it to our project imports.

The project will have two very simple functions. There will be a function for retrieving a document and a function for creating a document. Each document will have the Person model as defined in the struct.

When the application starts, it will connect to a Couchbase cluster as specified by environment variables. Likewise an RBAC account will be authenticated and a bucket will be opened.

After the database is good to go, we first get a document based on an id:

Assuming the document exists, it will be returned. After the document is retrieved, we insert a new document into the database.

Now you might be wondering, why we are creating functions for this at all. I mean we aren’t doing anything special beyond using the actual SDK.

Use your imagination on these functions. Assume they are something complex because we’ll be writing test cases for them. They are simple in this example to remain easy to understand.

Designing Unit Tests with Mock Data

We have a foundation to our project, so we can start thinking about writing test cases for our application. Before we start writing tests, let’s make a few changes to the main.go file that we had just created.

Open the main.go file and include the following:

Notice that there are some slight changes to the above code.

When writing tests for functions that interact with your database, it probably isn’t a good idea to test against your actual database. Instead we’re going to want to use mock data. However, we’re going to want to write tests without jumping through too many hoops.

To test easily, we can create an interface that represents our Couchbase bucket. In our main code, we’ll use an actual bucket and in our test code we’ll use a mock bucket.

In our example, the interface for our bucket only includes two of the many possible SDK functions. This interface matches what we’d see in the actual SDK.

The two functions that we had created are now part of the Database class.

Create a main_test.go file in your project and make sure it contains the following code:

The above code is really where the magic comes in for our project. It uses a mixture of code from the parent file and custom test code.

Take the following for example:

When testing, we aren’t going to be working with an actual Couchbase bucket, so we have to create our own dummy struct. We will be using the Database data structure from the parent file and it uses the BucketInterface.

When the tests start, we can create our dummy bucket:

Now, since our mock bucket doesn’t have any functions like the real bucket, we have to create the functions as defined in our interface. In other words, we have to create an Insert and a Get function.

Starting with the Insert function:

Our test is going to be simple. We’re going to try to insert any document except one with a key of nraboy. The test will either succeed or fail based on the key.

The Get function works in a similar fashion.

When trying to get a document, we are expecting a key of nraboy. If the correct key was provided, return some data marshalled by our convert function, otherwise return an error.

Again, these are mock versions of what we’d find in the Go SDK for bucket operations. With the interface functions created, we can write our two test functions.

The TestGetPersonDocument will use our testdatabase variable which uses the mock bucket. However, it uses the GetPersonDocument from the main.go file. Remember, our parent function could be way more complex, but the database stuff is now mock.

The result of our function will be decoded into the Person data structure using the mapstructure package. More information on using the mapstructure package can be read about here.

The TestCreatePersonDocument function follows the same strategy. We are using the mock bucket, but the very real CreatePersonDocument function. The Insert will use what we had created in our test.

There isn’t too much to testing a Golang application that includes database interaction. Your best bet is to create an interface and use your own custom mock versions of the functions and data.

Creating a YAML Configuration for Travis CI

So we have our Go application with a few unit tests. Now we need to be able to use Travis CI to automatically test our application and deploy it if successful.

Travis CI functions off a YAML configuration file. Take the following configuration for example:

The above configuration says that we are using Go 1.8. Before we start executing scripts, we need to download a necessary package. We need sshpass which allows us to SSH with plaintext passwords. In the end you’ll probably want to use keys, but for this example it is fine.

After sshpass has downloaded, we need to run our tests. This is done in the scripts section. After the first script finishes, we can build our project.

Assuming both scripts have completed successfully, we want to focus on the deployment.

Two different commands are executed for deployment. The first command will copy the binary to a remote server and the second command will run that file on the remote server.

Both deployment commands reference environment variables in the CI / CD process that are later passed to the server.

Now, you’ll notice that we haven’t set any environment variables. These variables are sensitive and shouldn’t be plain text within our Git repository. Instead we can use secrets with Travis CI.

Download the travis CLI tool by following the Travis CI documentation. With the tool installed, execute the following:

Instead of adding all your information as plain text in the YAML file, it is encrypted and can be understood by Travis CI. The YAML configuration it adds will look something like this:

This is something you can keep in your Git repository and feel safe. An even safer approach would be to use public and private keys for SSH, but this is fine for this example.

When you push your project, assuming you’ve linked it in your Travis CI account, the application will test and deploy automatically.

The Significance of NoSQL with Continuous Deployment

We saw how to create tests that use mock data as a database. However, what is really convenient is that we don’t need to create upgrade scripts when our data changes. In a relational database you’d have to create alter scripts for your table. With Couchbase, if your data model needs to change, just change to struct for Person in the code.

Conclusion

You just saw how to use Travis CI to continuously deploy your Golang project that uses a Couchbase NoSQL database. During the continuous integration phase, the application is tested using mock data. When the tests pass and the project is built, it is pushed to a remote server and ran.

The example used in this tutorial can be found on GitHub. Just note that the remote server that the project is pushed to has been removed.

If you’re interested in learning more about Go with Couchbase, check out the Couchbase Developer Portal.

Posted by Nic Raboy, Developer Advocate, Couchbase

Nic Raboy is an advocate of modern web and mobile development technologies. He has experience in Java, JavaScript, Golang and a variety of frameworks such as Angular, NativeScript, and Apache Cordova. Nic writes about his development experiences related to making web and mobile development easier to understand.

Leave a reply