Repository: etcd-io/etcd
File: tests/e2e/etcd_release_upgrade_test.go (Go)

Code before:
	require.NoErrorf(t, err, "failed to get version from binary")

	lastClusterVersion, err := e2e.GetVersionFromBinary(e2e.BinPath.EtcdLastRelease)
	require.NoErrorf(t, err, "failed to get version from last release binary")

	clusterSize := 3

	epc := createNewClusterByPromotingMembers(t, lastClusterVersion, clusterSize)
	defer func() {
		require.NoError(t, epc.Close())
	}()

	err = e2e.DowngradeUpgradeMembers(t, nil, epc, 3, false, lastClusterVersion, currentVersion)
	require.NoError(t, err)

	t.Logf("Checking all members' status after upgrading")
	ensureAllMembersAreVotingMembers(t, epc)

	t.Logf("Checking all members are ready to serve client requests")
	for i := 0; i < clusterSize; i++ {
		err = epc.Procs[i].Etcdctl().Put(context.Background(), "foo", "bar", config.PutOptions{})
		require.NoError(t, err)
	}
}

func createNewClusterByPromotingMembers(t *testing.T, clusterVersion *semver.Version, clusterSize int) *e2e.EtcdProcessCluster {
	require.GreaterOrEqualf(t, clusterSize, 1, "clusterSize >= 1")

	cv := e2e.CurrentVersion
	if clusterVersion.LessThan(*semver.New(version.Version)) {
		cv = e2e.LastVersion
	}
	ctx := context.Background()

	t.Logf("Creating new etcd cluster - version: %s, clusterSize: %v", clusterVersion.String(), clusterSize)

	t.Log("Creating first node")
	epc, err := e2e.NewEtcdProcessCluster(ctx, t,
		e2e.WithVersion(cv),
		e2e.WithClusterSize(1),
		e2e.WithSnapshotCount(10),
	)
	require.NoErrorf(t, err, "failed to start first etcd process")
	defer func() {
		if t.Failed() {
			epc.Close()
		}
	}()

	for i := 1; i < clusterSize; i++ {
		var nodeID uint64

Review comment (refactor):
I think we can minor refactor this function as what I did in https://github.com/etcd-io/etcd/pull/19636.

We can create a separate PR to get it reviewed & merged separately

Code after:
	require.NoErrorf(t, err, "failed to get version from binary")

	lastClusterVersion, err := e2e.GetVersionFromBinary(e2e.BinPath.EtcdLastRelease)
	require.NoErrorf(t, err, "failed to get version from last release binary")

	clusterSize := 3

	for _, tc := range []struct {
		name     string
		snapshot int
	}{
		{
			name:     "create snapshot after promoted",
			snapshot: 10,
		},
		{
			name: "no snapshot after promoted",
		},
	} {
		t.Run(tc.name, func(t *testing.T) {
			ctx := context.Background()

			epc, _ := mustCreateNewClusterByPromotingMembers(t, e2e.LastVersion, clusterSize,
				e2e.WithSnapshotCount(uint64(tc.snapshot)))
			defer func() {
				require.NoError(t, epc.Close())
			}()

			for i := 0; i < tc.snapshot; i++ {
				err = epc.Etcdctl().Put(ctx, "foo", "bar", config.PutOptions{})
				require.NoError(t, err)
			}

			err = e2e.DowngradeUpgradeMembers(t, nil, epc, clusterSize, false, lastClusterVersion, currentVersion)
			require.NoError(t, err)

			t.Logf("Checking all members' status after upgrading")
			ensureAllMembersAreVotingMembers(t, epc)

			t.Logf("Checking all members are ready to serve client requests")
			for i := 0; i < clusterSize; i++ {
				err = epc.Procs[i].Etcdctl().Put(context.Background(), "foo", "bar", config.PutOptions{})
				require.NoError(t, err)
			}
		})
	}
}

func mustCreateNewClusterByPromotingMembers(t *testing.T, clusterVersion e2e.ClusterVersion, clusterSize int, opts ...e2e.EPClusterOption) (*e2e.EtcdProcessCluster, []*etcdserverpb.Member) {
	require.GreaterOrEqualf(t, clusterSize, 1, "clusterSize must be at least 1")