README.md
1# Server Integration Tests
2
3This directory contains integration tests for the database.
4
5To run them using an in-process local server:
6
7```sh
8go test ./tests
9```
10
11They can also be run against a remote server running in a separate process
12or machine
13
14```sh
15URL=http://127.0.0.1:8086 go test -parallel 1 ./tests
16```
17
18When running tests against a remote server, `-parallel 1` is currently needed
19as many of the tests use the same DB and RP names which causes tests to fail
20when run concurrently.
21
22When adding tests, try to add tests that will always work for remote server usage.
23
24## Structure
25
26Currently, the file `server_test.go` has integration tests for single node scenarios.
27At some point we'll need to add cluster tests, and may add them in a different file, or
28rename `server_test.go` to `server_single_node_test.go` or something like that.
29
30## What is in a test?
31
32Each test is broken apart effectively into the following areas:
33
34- Write sample data
35- Use cases for table driven test, that include a command (typically a query) and an expected result.
36
37When each test runs it does the following:
38
39- init: determines if there are any writes and if so, writes them to the in-memory database
40- queries: iterate through each query, executing the command, and comparing the results to the expected result.
41
42## Idempotent - Allows for parallel tests
43
44Each test should be `idempotent`, meaning that its data will not be affected by other tests, or use cases within the table tests themselves.
45This allows for parallel testing, keeping the test suite total execution time very low.
46
47### Basic sample test
48
49```go
50// Ensure the server can have a database with multiple measurements.
51func TestServer_Query_Multiple_Measurements(t *testing.T) {
52 t.Parallel()
53 s := OpenServer(NewConfig(), "")
54 defer s.Close()
55
56 if err := s.CreateDatabaseAndRetentionPolicy("db0", newRetentionPolicyInfo("rp0", 1, 1*time.Hour)); err != nil {
57 t.Fatal(err)
58 }
59
60 // Make sure we do writes for measurements that will span across shards
61 writes := []string{
62 fmt.Sprintf("cpu,host=server01 value=100,core=4 %d", mustParseTime(time.RFC3339Nano, "2000-01-01T00:00:00Z").UnixNano()),
63 fmt.Sprintf("cpu1,host=server02 value=50,core=2 %d", mustParseTime(time.RFC3339Nano, "2015-01-01T00:00:00Z").UnixNano()),
64 }
65 test := NewTest("db0", "rp0")
66 test.write = strings.Join(writes, "\n")
67
68 test.addQueries([]*Query{
69 &Query{
70 name: "measurement in one shard but not another shouldn't panic server",
71 command: `SELECT host,value FROM db0.rp0.cpu`,
72 exp: `{"results":[{"series":[{"name":"cpu","tags":{"host":"server01"},"columns":["time","value"],"values":[["2000-01-01T00:00:00Z",100]]}]}]}`,
73 },
74 }...)
75
76 if err := test.init(s); err != nil {
77 t.Fatalf("test init failed: %s", err)
78 }
79
80 for _, query := range test.queries {
81 if query.skip {
82 t.Logf("SKIP:: %s", query.name)
83 continue
84 }
85 if err := query.Execute(s); err != nil {
86 t.Error(query.Error(err))
87 } else if !query.success() {
88 t.Error(query.failureMessage())
89 }
90 }
91}
92```
93
94Let's break this down:
95
96In this test, we first tell it to run in parallel with the `t.Parallel()` call.
97
98We then open a new server with:
99
100```go
101s := OpenServer(NewConfig(), "")
102defer s.Close()
103```
104
105If needed, we create a database and default retention policy. This is usually needed
106when inserting and querying data. This is not needed if you are testing commands like `CREATE DATABASE`, `SHOW DIAGNOSTICS`, etc.
107
108```go
109if err := s.CreateDatabaseAndRetentionPolicy("db0", newRetentionPolicyInfo("rp0", 1, 1*time.Hour)); err != nil {
110 t.Fatal(err)
111}
112```
113
114Next, set up the write data you need:
115
116```go
117writes := []string{
118 fmt.Sprintf("cpu,host=server01 value=100,core=4 %d", mustParseTime(time.RFC3339Nano, "2000-01-01T00:00:00Z").UnixNano()),
119 fmt.Sprintf("cpu1,host=server02 value=50,core=2 %d", mustParseTime(time.RFC3339Nano, "2015-01-01T00:00:00Z").UnixNano()),
120}
121```
122Create a new test with the database and retention policy:
123
124```go
125test := NewTest("db0", "rp0")
126```
127
128Send in the writes:
129```go
130test.write = strings.Join(writes, "\n")
131```
132
133Add some queries (the second one is mocked out to show how to add more than one):
134
135```go
136test.addQueries([]*Query{
137 &Query{
138 name: "measurement in one shard but not another shouldn't panic server",
139 command: `SELECT host,value FROM db0.rp0.cpu`,
140 exp: `{"results":[{"series":[{"name":"cpu","tags":{"host":"server01"},"columns":["time","value"],"values":[["2000-01-01T00:00:00Z",100]]}]}]}`,
141 },
142 &Query{
143 name: "another test here...",
144 command: `Some query command`,
145 exp: `the expected results`,
146 },
147}...)
148```
149
150The rest of the code is boilerplate execution code. It is purposefully not refactored out to a helper
151to make sure the test failure reports the proper lines for debugging purposes.
152
153#### Running the tests
154
155To run the tests:
156
157```sh
158go test ./cmd/influxd/run -parallel 500 -timeout 10s
159```
160
161#### Running a specific test
162
163```sh
164go test ./cmd/influxd/run -parallel 500 -timeout 10s -run TestServer_Query_Fill
165```
166
167#### Verbose feedback
168
169By default, all logs are silenced when testing. If you pass in the `-v` flag, the test suite becomes verbose, and enables all logging in the system
170
171```sh
172go test ./cmd/influxd/run -parallel 500 -timeout 10s -run TestServer_Query_Fill -v
173```
174
175