1// Copyright 2016 The etcd Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package e2e
16
17import (
18	"os"
19	"strings"
20	"testing"
21	"time"
22
23	"github.com/coreos/etcd/clientv3"
24	"golang.org/x/net/context"
25)
26
27func TestCtlV3Alarm(t *testing.T) {
28	// The boltdb minimum working set is six pages.
29	testCtl(t, alarmTest, withQuota(int64(13*os.Getpagesize())))
30}
31
32func alarmTest(cx ctlCtx) {
33	// test small put still works
34	smallbuf := strings.Repeat("a", 64)
35	if err := ctlV3Put(cx, "1st_test", smallbuf, ""); err != nil {
36		cx.t.Fatal(err)
37	}
38
39	// write some chunks to fill up the database
40	buf := strings.Repeat("b", int(os.Getpagesize()))
41	for {
42		if err := ctlV3Put(cx, "2nd_test", buf, ""); err != nil {
43			if !strings.Contains(err.Error(), "etcdserver: mvcc: database space exceeded") {
44				cx.t.Fatal(err)
45			}
46			break
47		}
48	}
49
50	// quota alarm should now be on
51	if err := ctlV3Alarm(cx, "list", "alarm:NOSPACE"); err != nil {
52		cx.t.Fatal(err)
53	}
54
55	// check that Put is rejected when alarm is on
56	if err := ctlV3Put(cx, "3rd_test", smallbuf, ""); err != nil {
57		if !strings.Contains(err.Error(), "etcdserver: mvcc: database space exceeded") {
58			cx.t.Fatal(err)
59		}
60	}
61
62	eps := cx.epc.grpcEndpoints()
63
64	// get latest revision to compact
65	cli, err := clientv3.New(clientv3.Config{
66		Endpoints:   eps,
67		DialTimeout: 3 * time.Second,
68	})
69	if err != nil {
70		cx.t.Fatal(err)
71	}
72	defer cli.Close()
73	sresp, err := cli.Status(context.TODO(), eps[0])
74	if err != nil {
75		cx.t.Fatal(err)
76	}
77
78	// make some space
79	if err := ctlV3Compact(cx, sresp.Header.Revision, true); err != nil {
80		cx.t.Fatal(err)
81	}
82	if err := ctlV3Defrag(cx); err != nil {
83		cx.t.Fatal(err)
84	}
85
86	// turn off alarm
87	if err := ctlV3Alarm(cx, "disarm", "alarm:NOSPACE"); err != nil {
88		cx.t.Fatal(err)
89	}
90
91	// put one more key below quota
92	if err := ctlV3Put(cx, "4th_test", smallbuf, ""); err != nil {
93		cx.t.Fatal(err)
94	}
95}
96
97func ctlV3Alarm(cx ctlCtx, cmd string, as ...string) error {
98	cmdArgs := append(cx.PrefixArgs(), "alarm", cmd)
99	return spawnWithExpects(cmdArgs, as...)
100}
101