acceptance_test.go 4.18 KB
Newer Older
Erin Krengel's avatar
Erin Krengel committed
1
2
// +build acceptance

Erin Krengel's avatar
Erin Krengel committed
3
4
5
package acceptance_test

import (
Sean Holung's avatar
Sean Holung committed
6
	"bytes"
Erin Krengel's avatar
Erin Krengel committed
7
	"context"
Sean Holung's avatar
Sean Holung committed
8
	"encoding/json"
Erin Krengel's avatar
Erin Krengel committed
9
	"fmt"
10
	"io/ioutil"
Erin Krengel's avatar
Erin Krengel committed
11
12
13
14
15
16
17
	"log"
	"net/http"
	"os"
	"testing"
	"time"

	"cloud.google.com/go/pubsub"
18
	"cloud.google.com/go/storage"
Erin Krengel's avatar
Erin Krengel committed
19
	"github.com/stretchr/testify/assert"
Erin Krengel's avatar
Erin Krengel committed
20
21
)

22
23
type config struct {
	project          string
Sean Holung's avatar
Sean Holung committed
24
	serviceName      string
25
26
	bucketName       string
	subscriptionName string
27
28
}

29
var testConfig config
Erin Krengel's avatar
Erin Krengel committed
30

31
func TestMain(m *testing.M) {
Erin Krengel's avatar
Erin Krengel committed
32
33
34
	// Set up our acceptance test configuration. These values are
	// required, so we will use a helper function that exits if the
	// environment variable is not set.
35
36
	testConfig = config{
		project:          getConfigurationValue("PROJECT"),
Erin Krengel's avatar
Erin Krengel committed
37
		serviceName:      getConfigurationValue("SERVICE_NAME"),
38
39
40
41
42
		bucketName:       getConfigurationValue("BUCKET"),
		subscriptionName: getConfigurationValue("SUBSCRIPTION"),
	}
	os.Exit(m.Run())
}
Sean Holung's avatar
Sean Holung committed
43

44
func TestSimpleHappyPath(t *testing.T) {
Erin Krengel's avatar
Erin Krengel committed
45
46
47
48
49
50
51
52
53
	t.Logf("CONFIGURATION: %+v\n", testConfig)

	// ARRANGE
	// Setup clients to talk to GCP resources.
	ctx := context.Background()
	client, err := storage.NewClient(ctx)
	bkt := client.Bucket(testConfig.bucketName)
	pubsubCtx, cancelCtx := context.WithTimeout(ctx, 2*time.Minute)
	subscription := setupSubscription(t, pubsubCtx)
Erin Krengel's avatar
Erin Krengel committed
54

Erin Krengel's avatar
Erin Krengel committed
55
	// Create a test message.
Sean Holung's avatar
Sean Holung committed
56
	testMsg := map[string]string{"message": "Ruby is awesome!!!"}
Erin Krengel's avatar
Erin Krengel committed
57
58
59
60
61
62
63
64
65
66
67
68
69
70

	// ACT
	// Post test message.
	resp := postTestMessage(t, testMsg)

	// ASSERT
	// Validate the response status code.
	assert.Equal(t, http.StatusAccepted, resp.StatusCode)

	// Read and validate the response body.
	defer resp.Body.Close()
	rawBody, err := ioutil.ReadAll(resp.Body)
	assert.NoError(t, err)
	objectName := getObjectNameFromBytes(t, rawBody)
71
72

	t.Run("message is sent to PubSub topic", func(t *testing.T) {
Erin Krengel's avatar
Erin Krengel committed
73
74
75
76
		// Receive message from the subscription.
		var receivedBytes []byte
		err := subscription.Receive(pubsubCtx, func(ctx context.Context, m *pubsub.Message) {
			receivedBytes = m.Data
77
78
79
			m.Ack()
			cancelCtx()
		})
Erin Krengel's avatar
Erin Krengel committed
80
		assert.NoError(t, err)
81

Erin Krengel's avatar
Erin Krengel committed
82
83
84
85
		// Validate received message and the the object name matches
		// the object name previously return from the service.
		receivedObjectName := getObjectNameFromBytes(t, receivedBytes)
		assert.Equal(t, objectName, receivedObjectName)
86
	})
Sean Holung's avatar
Sean Holung committed
87

88
	t.Run("message is stored in bucket", func(t *testing.T) {
Erin Krengel's avatar
Erin Krengel committed
89
90
91
		// Check the stored message is the one we sent.
		storedMsg := readStoredObject(ctx, t, bkt, objectName)
		assert.EqualValues(t, testMsg, storedMsg)
Erin Krengel's avatar
Erin Krengel committed
92
	})
Erin Krengel's avatar
Erin Krengel committed
93
94
95
	// Clean up after our test. Delete the object so we can delete the bucket.
	err = bkt.Object(objectName).Delete(ctx)
	assert.NoError(t, err)
96
}
Sean Holung's avatar
Sean Holung committed
97

Erin Krengel's avatar
Erin Krengel committed
98
func TestSimpleSadPath(t *testing.T) {
Erin Krengel's avatar
Erin Krengel committed
99
	t.Run("posting a incorrectly formatted message returns 400", func(t *testing.T) {
Erin Krengel's avatar
Erin Krengel committed
100
101
		resp := postTestMessage(t, "this wont unmarshal")
		assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
Erin Krengel's avatar
Erin Krengel committed
102
103
104
	})
}

105
106
107
108
func getConfigurationValue(envVar string) string {
	value := os.Getenv(envVar)
	if value == "" {
		log.Fatalf("%s not set", envVar)
Sean Holung's avatar
Sean Holung committed
109
	}
110
	return value
Erin Krengel's avatar
Erin Krengel committed
111
}
Erin Krengel's avatar
Erin Krengel committed
112
113

func getObjectNameFromBytes(t *testing.T, bytes []byte) string {
Sean Holung's avatar
Sean Holung committed
114
	assert.NotNil(t, bytes, "nil bytes")
Erin Krengel's avatar
Erin Krengel committed
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
	body := make(map[string]string)
	err := json.Unmarshal(bytes, &body)
	assert.NoError(t, err)

	objectName := body["name"]
	assert.NotZero(t, objectName)
	return objectName
}

func setupSubscription(t *testing.T, ctx context.Context) *pubsub.Subscription {
	pubsubClient, err := pubsub.NewClient(ctx, testConfig.project)
	assert.NoError(t, err)
	sub := pubsubClient.Subscription(testConfig.subscriptionName)
	return sub
}

func postTestMessage(t *testing.T, msg interface{}) *http.Response {
	url := fmt.Sprintf("http://%s/message", testConfig.serviceName)
	bodyBytes, err := json.Marshal(msg)
	assert.NoError(t, err)

	resp, err := http.Post(url, "application/json", bytes.NewBuffer(bodyBytes))
	assert.NoError(t, err)
	return resp
}

func readStoredObject(ctx context.Context, t *testing.T, bkt *storage.BucketHandle, objectName string) map[string]string {
	reader, err := bkt.Object(objectName).NewReader(ctx)
	assert.NoError(t, err)

	defer reader.Close()
	bytes, err := ioutil.ReadAll(reader)
	assert.NoError(t, err)

	storedMsg := make(map[string]string)
	err = json.Unmarshal(bytes, &storedMsg)
	assert.NoError(t, err)
	t.Logf("Stored message: %+v", storedMsg)
	return storedMsg
}