github.com/lfch/etcd-io/tests/v3@v3.0.0-20221004140520-eac99acd3e9d/integration/corrupt_test.go (about) 1 // Copyright 2022 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 15 package integration 16 17 import ( 18 "context" 19 "fmt" 20 "testing" 21 "time" 22 23 "github.com/lfch/etcd-io/api/v3/etcdserverpb" 24 clientv3 "github.com/lfch/etcd-io/client/v3" 25 "github.com/lfch/etcd-io/server/v3/storage/mvcc/testutil" 26 "github.com/lfch/etcd-io/tests/v3/framework/integration" 27 "github.com/stretchr/testify/assert" 28 "github.com/stretchr/testify/require" 29 ) 30 31 func TestPeriodicCheck(t *testing.T) { 32 integration.BeforeTest(t) 33 34 clus := integration.NewCluster(t, &integration.ClusterConfig{Size: 3}) 35 defer clus.Terminate(t) 36 37 cc, err := clus.ClusterClient(t) 38 require.NoError(t, err) 39 40 ctx := context.Background() 41 42 var totalRevisions int64 = 1210 43 var rev int64 44 for ; rev < totalRevisions; rev += testutil.CompactionCycle { 45 testPeriodicCheck(ctx, t, cc, clus, rev, rev+testutil.CompactionCycle) 46 } 47 testPeriodicCheck(ctx, t, cc, clus, rev, rev+totalRevisions) 48 alarmResponse, err := cc.AlarmList(ctx) 49 assert.NoError(t, err, "error on alarm list") 50 assert.Equal(t, []*etcdserverpb.AlarmMember(nil), alarmResponse.Alarms) 51 } 52 53 func testPeriodicCheck(ctx context.Context, t *testing.T, cc *clientv3.Client, clus *integration.Cluster, start, stop int64) { 54 for i := start; i <= stop; i++ { 55 if i%67 == 0 { 56 _, err := cc.Delete(ctx, testutil.PickKey(i+83)) 57 assert.NoError(t, err, "error on delete") 58 } else { 59 _, err := cc.Put(ctx, testutil.PickKey(i), fmt.Sprint(i)) 60 assert.NoError(t, err, "error on put") 61 } 62 } 63 err := clus.Members[0].Server.CorruptionChecker().PeriodicCheck() 64 assert.NoError(t, err, "error on periodic check (rev %v)", stop) 65 } 66 67 func TestPeriodicCheckDetectsCorruption(t *testing.T) { 68 integration.BeforeTest(t) 69 70 clus := integration.NewCluster(t, &integration.ClusterConfig{Size: 3}) 71 defer clus.Terminate(t) 72 73 cc, err := clus.ClusterClient(t) 74 require.NoError(t, err) 75 76 ctx := context.Background() 77 78 for i := 0; i < 10; i++ { 79 _, err := cc.Put(ctx, testutil.PickKey(int64(i)), fmt.Sprint(i)) 80 assert.NoError(t, err, "error on put") 81 } 82 83 err = clus.Members[0].Server.CorruptionChecker().PeriodicCheck() 84 assert.NoError(t, err, "error on periodic check") 85 clus.Members[0].Stop(t) 86 clus.WaitLeader(t) 87 88 err = testutil.CorruptBBolt(clus.Members[0].BackendPath()) 89 assert.NoError(t, err) 90 91 err = clus.Members[0].Restart(t) 92 assert.NoError(t, err) 93 time.Sleep(50 * time.Millisecond) 94 leader := clus.WaitLeader(t) 95 err = clus.Members[leader].Server.CorruptionChecker().PeriodicCheck() 96 assert.NoError(t, err, "error on periodic check") 97 time.Sleep(50 * time.Millisecond) 98 alarmResponse, err := cc.AlarmList(ctx) 99 assert.NoError(t, err, "error on alarm list") 100 assert.Equal(t, []*etcdserverpb.AlarmMember{{Alarm: etcdserverpb.AlarmType_CORRUPT, MemberID: uint64(clus.Members[0].ID())}}, alarmResponse.Alarms) 101 } 102 103 func TestCompactHashCheck(t *testing.T) { 104 integration.BeforeTest(t) 105 106 clus := integration.NewCluster(t, &integration.ClusterConfig{Size: 3}) 107 defer clus.Terminate(t) 108 109 cc, err := clus.ClusterClient(t) 110 require.NoError(t, err) 111 112 ctx := context.Background() 113 114 var totalRevisions int64 = 1210 115 var rev int64 116 for ; rev < totalRevisions; rev += testutil.CompactionCycle { 117 testCompactionHash(ctx, t, cc, clus, rev, rev+testutil.CompactionCycle) 118 } 119 testCompactionHash(ctx, t, cc, clus, rev, rev+totalRevisions) 120 } 121 122 func testCompactionHash(ctx context.Context, t *testing.T, cc *clientv3.Client, clus *integration.Cluster, start, stop int64) { 123 for i := start; i <= stop; i++ { 124 if i%67 == 0 { 125 _, err := cc.Delete(ctx, testutil.PickKey(i+83)) 126 assert.NoError(t, err, "error on delete") 127 } else { 128 _, err := cc.Put(ctx, testutil.PickKey(i), fmt.Sprint(i)) 129 assert.NoError(t, err, "error on put") 130 } 131 } 132 _, err := cc.Compact(ctx, stop) 133 assert.NoError(t, err, "error on compact (rev %v)", stop) 134 // Wait for compaction to be compacted 135 time.Sleep(50 * time.Millisecond) 136 137 clus.Members[0].Server.CorruptionChecker().CompactHashCheck() 138 } 139 140 func TestCompactHashCheckDetectCorruption(t *testing.T) { 141 integration.BeforeTest(t) 142 143 clus := integration.NewCluster(t, &integration.ClusterConfig{Size: 3}) 144 defer clus.Terminate(t) 145 146 cc, err := clus.ClusterClient(t) 147 require.NoError(t, err) 148 149 ctx := context.Background() 150 151 for i := 0; i < 10; i++ { 152 _, err := cc.Put(ctx, testutil.PickKey(int64(i)), fmt.Sprint(i)) 153 assert.NoError(t, err, "error on put") 154 } 155 156 clus.Members[0].Server.CorruptionChecker().CompactHashCheck() 157 clus.Members[0].Stop(t) 158 clus.WaitLeader(t) 159 160 err = testutil.CorruptBBolt(clus.Members[0].BackendPath()) 161 assert.NoError(t, err) 162 163 err = clus.Members[0].Restart(t) 164 assert.NoError(t, err) 165 _, err = cc.Compact(ctx, 5) 166 assert.NoError(t, err) 167 time.Sleep(50 * time.Millisecond) 168 leader := clus.WaitLeader(t) 169 clus.Members[leader].Server.CorruptionChecker().CompactHashCheck() 170 time.Sleep(50 * time.Millisecond) 171 alarmResponse, err := cc.AlarmList(ctx) 172 assert.NoError(t, err, "error on alarm list") 173 assert.Equal(t, []*etcdserverpb.AlarmMember{{Alarm: etcdserverpb.AlarmType_CORRUPT, MemberID: uint64(clus.Members[0].ID())}}, alarmResponse.Alarms) 174 }