Skip to content

Commit e21756b

Browse files
e2e test: add schema version verification in mix_version_test.
Signed-off-by: Siyuan Zhang <[email protected]>
1 parent c2a3ca6 commit e21756b

File tree

3 files changed

+45
-0
lines changed

3 files changed

+45
-0
lines changed

tests/e2e/cluster_downgrade_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,9 @@ func newCluster(t *testing.T, clusterSize int, snapshotCount uint64) *e2e.EtcdPr
202202
if errC := epc.Close(); errC != nil {
203203
t.Fatalf("error closing etcd processes (%v)", errC)
204204
}
205+
for _, proc := range epc.Procs {
206+
require.NoError(t, proc.VerifySchemaVersion(epc.Cfg.Logger))
207+
}
205208
})
206209
return epc
207210
}

tests/e2e/etcd_mix_versions_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,11 +92,15 @@ func mixVersionsSnapshotTestByAddingMember(t *testing.T, cfg *e2e.EtcdProcessClu
9292
epc, err := e2e.NewEtcdProcessCluster(context.TODO(), t,
9393
e2e.WithConfig(cfg),
9494
e2e.WithSnapshotCount(10),
95+
e2e.WithKeepDataDir(true),
9596
)
9697
require.NoError(t, err, "failed to start etcd cluster: %v", err)
9798
defer func() {
9899
derr := epc.Close()
99100
require.NoError(t, derr, "failed to close etcd cluster: %v", derr)
101+
for _, proc := range epc.Procs {
102+
require.NoError(t, proc.VerifySchemaVersion(epc.Cfg.Logger))
103+
}
100104
}()
101105

102106
t.Log("Writing 20 keys to the cluster (more than SnapshotCount entries to trigger at least a snapshot)")
@@ -135,11 +139,15 @@ func mixVersionsSnapshotTestByMockPartition(t *testing.T, cfg *e2e.EtcdProcessCl
135139
e2e.WithConfig(cfg),
136140
e2e.WithSnapshotCount(10),
137141
e2e.WithSnapshotCatchUpEntries(10),
142+
e2e.WithKeepDataDir(true),
138143
)
139144
require.NoError(t, err, "failed to start etcd cluster: %v", err)
140145
defer func() {
141146
derr := epc.Close()
142147
require.NoError(t, derr, "failed to close etcd cluster: %v", derr)
148+
for _, proc := range epc.Procs {
149+
require.NoError(t, proc.VerifySchemaVersion(epc.Cfg.Logger))
150+
}
143151
}()
144152
toPartitionedMember := epc.Procs[mockPartitionNodeIndex]
145153

tests/framework/e2e/etcd_process.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,13 @@ import (
3131
"github.com/coreos/go-semver/semver"
3232
"go.uber.org/zap"
3333

34+
"go.etcd.io/etcd/api/v3/version"
3435
"go.etcd.io/etcd/client/pkg/v3/fileutil"
3536
"go.etcd.io/etcd/pkg/v3/expect"
3637
"go.etcd.io/etcd/pkg/v3/proxy"
38+
"go.etcd.io/etcd/server/v3/storage/backend"
39+
"go.etcd.io/etcd/server/v3/storage/datadir"
40+
"go.etcd.io/etcd/server/v3/storage/schema"
3741
"go.etcd.io/etcd/tests/v3/framework/config"
3842
)
3943

@@ -60,6 +64,8 @@ type EtcdProcess interface {
6064
LazyFS() *LazyFS
6165
Logs() LogsExpect
6266
Kill() error
67+
// VerifySchemaVersion verifies the db file schema version is compatible with the binary after the process is closed.
68+
VerifySchemaVersion(lg *zap.Logger) error
6369
}
6470

6571
type LogsExpect interface {
@@ -253,6 +259,34 @@ func (ep *EtcdServerProcess) Close() error {
253259
return nil
254260
}
255261

262+
func (ep *EtcdServerProcess) VerifySchemaVersion(lg *zap.Logger) error {
263+
dbPath := datadir.ToBackendFileName(ep.cfg.DataDirPath)
264+
be := backend.NewDefaultBackend(lg, dbPath)
265+
defer be.Close()
266+
ver, err := schema.UnsafeDetectSchemaVersion(lg, be.BatchTx())
267+
if err != nil {
268+
return err
269+
}
270+
maxStorageVersion := version.V3_6
271+
if ep.cfg.ExecPath == BinPath.EtcdLastRelease {
272+
maxStorageVersion = version.V3_5
273+
}
274+
// in a mix version cluster, the storage version would be set to the cluster version,
275+
// which could be lower than the server version by 1 minor version.
276+
if !ver.LessThan(maxStorageVersion) && !ver.Equal(maxStorageVersion) {
277+
return fmt.Errorf("expect backend schema version to be <= %s, but got %s", maxStorageVersion.String(), ver.String())
278+
}
279+
// check new fields introduced in V3_6 do not exist in V3_5 data file.
280+
// V3_6 contains all the fields in V3_5, so no need to check for V3_6 servers.
281+
if maxStorageVersion == version.V3_5 {
282+
_, vs := be.BatchTx().UnsafeRange(schema.Meta, schema.MetaStorageVersionName, nil, 1)
283+
if len(vs) != 0 {
284+
return fmt.Errorf("expect storageVersion not exist in the meta bucket, but got %s", string(vs[0]))
285+
}
286+
}
287+
return nil
288+
}
289+
256290
func (ep *EtcdServerProcess) waitReady(ctx context.Context) error {
257291
defer close(ep.donec)
258292
return WaitReadyExpectProc(ctx, ep.proc, EtcdServerReadyLines)

0 commit comments

Comments
 (0)