forked from cockroachdb/cockroach
/
admin_cluster_test.go
142 lines (126 loc) · 4.37 KB
/
admin_cluster_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
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
// Copyright 2016 The Cockroach Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License.
//
// Author: Matt Tracy (matt@cockroachlabs.com)
package server_test
import (
"testing"
"time"
"github.com/pkg/errors"
"github.com/cockroachdb/cockroach/pkg/base"
"github.com/cockroachdb/cockroach/pkg/server/serverpb"
"github.com/cockroachdb/cockroach/pkg/testutils/testcluster"
"github.com/cockroachdb/cockroach/pkg/util"
"github.com/cockroachdb/cockroach/pkg/util/httputil"
"github.com/cockroachdb/cockroach/pkg/util/leaktest"
)
func TestAdminAPITableStats(t *testing.T) {
defer leaktest.AfterTest(t)()
t.Skip("#8890")
const nodeCount = 3
tc := testcluster.StartTestCluster(t, nodeCount, base.TestClusterArgs{
ReplicationMode: base.ReplicationAuto,
ServerArgs: base.TestServerArgs{
ScanInterval: time.Millisecond,
ScanMaxIdleTime: time.Millisecond,
},
})
defer tc.Stopper().Stop()
server0 := tc.Server(0)
// Create clients (SQL, HTTP) connected to server 0.
db := tc.ServerConn(0)
client, err := server0.GetHTTPClient()
if err != nil {
t.Fatal(err)
}
client.Timeout = base.NetworkTimeout * 3
// Make a single table and insert some data. The database and test have
// names which require escaping, in order to verify that database and
// table names are being handled correctly.
if _, err := db.Exec(`CREATE DATABASE "test test"`); err != nil {
t.Fatal(err)
}
if _, err := db.Exec(`
CREATE TABLE "test test"."foo foo" (
id INT PRIMARY KEY,
val STRING
)`,
); err != nil {
t.Fatal(err)
}
for i := 0; i < 10; i++ {
if _, err := db.Exec(`
INSERT INTO "test test"."foo foo" VALUES(
$1, $2
)`, i, "test",
); err != nil {
t.Fatal(err)
}
}
url := server0.AdminURL() + "/_admin/v1/databases/test test/tables/foo foo/stats"
var tsResponse serverpb.TableStatsResponse
// The new SQL table may not yet have split into its own range. Wait for
// this to occur, and for full replication.
util.SucceedsSoon(t, func() error {
if err := httputil.GetJSON(client, url, &tsResponse); err != nil {
return err
}
if tsResponse.RangeCount != 1 {
return errors.Errorf("Table range not yet separated.")
}
if tsResponse.NodeCount != nodeCount {
return errors.Errorf("Table range not yet replicated to %d nodes.", 3)
}
if a, e := tsResponse.ReplicaCount, int64(nodeCount); a != e {
return errors.Errorf("expected %d replicas, found %d", e, a)
}
return nil
})
// These two conditions *must* be true, given that the above
// SucceedsSoon has succeeded.
if a, e := tsResponse.Stats.KeyCount, int64(20); a < e {
t.Fatalf("expected at least 20 total keys, found %d", a)
}
if len(tsResponse.MissingNodes) > 0 {
t.Fatalf("expected no missing nodes, found %v", tsResponse.MissingNodes)
}
// Kill a node, ensure it shows up in MissingNodes and that ReplicaCount is
// lower.
tc.StopServer(1)
if err := httputil.GetJSON(client, url, &tsResponse); err != nil {
t.Fatal(err)
}
if a, e := tsResponse.NodeCount, int64(nodeCount); a != e {
t.Errorf("expected %d nodes, found %d", e, a)
}
if a, e := tsResponse.RangeCount, int64(1); a != e {
t.Errorf("expected %d ranges, found %d", e, a)
}
if a, e := tsResponse.ReplicaCount, int64((nodeCount/2)+1); a != e {
t.Errorf("expected %d replicas, found %d", e, a)
}
if a, e := tsResponse.Stats.KeyCount, int64(10); a < e {
t.Errorf("expected at least 10 total keys, found %d", a)
}
if len(tsResponse.MissingNodes) != 1 {
t.Errorf("expected one missing node, found %v", tsResponse.MissingNodes)
}
// Call TableStats with a very low timeout. This tests that fan-out queries
// do not leak goroutines if the calling context is abandoned.
// Interestingly, the call can actually sometimes succeed, despite the small
// timeout; however, in aggregate (or in stress tests) this will suffice for
// detecting leaks.
client.Timeout = 1 * time.Nanosecond
_ = httputil.GetJSON(client, url, &tsResponse)
}