Add test for join existing cluster

Signed-off-by: Brad Davidson <brad.davidson@rancher.com>
pull/11537/head
Brad Davidson 2024-12-18 19:47:39 +00:00 committed by Brad Davidson
parent 365372441b
commit f8271d8506
2 changed files with 67 additions and 8 deletions

View File

@ -2,8 +2,10 @@ package etcd
import ( import (
"context" "context"
"encoding/json"
"net" "net"
"net/http" "net/http"
"net/http/httptest"
"os" "os"
"path/filepath" "path/filepath"
"sync" "sync"
@ -27,6 +29,7 @@ import (
"google.golang.org/grpc/reflection" "google.golang.org/grpc/reflection"
"google.golang.org/grpc/status" "google.golang.org/grpc/status"
utilnet "k8s.io/apimachinery/pkg/util/net" utilnet "k8s.io/apimachinery/pkg/util/net"
"k8s.io/apimachinery/pkg/util/wait"
) )
func init() { func init() {
@ -234,6 +237,22 @@ func Test_UnitETCD_Register(t *testing.T) {
} }
func Test_UnitETCD_Start(t *testing.T) { func Test_UnitETCD_Start(t *testing.T) {
// dummy supervisor API for testing
var memberAddr string
server := httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
if req.URL.Path == "/db/info" {
members := []*etcdserverpb.Member{{
ClientURLs: []string{"https://" + net.JoinHostPort(memberAddr, "2379")},
PeerURLs: []string{"https://" + net.JoinHostPort(memberAddr, "2380")},
}}
resp.Header().Set("Content-Type", "application/json")
json.NewEncoder(resp).Encode(&Members{
Members: members,
})
}
}))
defer server.Close()
type contextInfo struct { type contextInfo struct {
ctx context.Context ctx context.Context
cancel context.CancelFunc cancel context.CancelFunc
@ -265,9 +284,6 @@ func Test_UnitETCD_Start(t *testing.T) {
address: mustGetAddress(), address: mustGetAddress(),
name: "default", name: "default",
}, },
args: args{
clientAccessInfo: nil,
},
setup: func(e *ETCD, ctxInfo *contextInfo) error { setup: func(e *ETCD, ctxInfo *contextInfo) error {
ctxInfo.ctx, ctxInfo.cancel = context.WithCancel(context.Background()) ctxInfo.ctx, ctxInfo.cancel = context.WithCancel(context.Background())
e.config.EtcdDisableSnapshots = true e.config.EtcdDisableSnapshots = true
@ -294,8 +310,37 @@ func Test_UnitETCD_Start(t *testing.T) {
name: "default", name: "default",
cron: cron.New(), cron: cron.New(),
}, },
setup: func(e *ETCD, ctxInfo *contextInfo) error {
ctxInfo.ctx, ctxInfo.cancel = context.WithCancel(context.Background())
testutil.GenerateRuntime(e.config)
return nil
},
teardown: func(e *ETCD, ctxInfo *contextInfo) error {
// RemoveSelf will fail with a specific error, but it still does cleanup for testing purposes
err := e.RemoveSelf(ctxInfo.ctx)
ctxInfo.cancel()
time.Sleep(5 * time.Second)
testutil.CleanupDataDir(e.config)
if err != nil && err.Error() != etcdserver.ErrNotEnoughStartedMembers.Error() {
return err
}
return nil
},
},
{
name: "valid clientAccessInfo",
fields: fields{
config: generateTestConfig(),
address: mustGetAddress(),
name: "default",
cron: cron.New(),
},
args: args{ args: args{
clientAccessInfo: nil, clientAccessInfo: &clientaccess.Info{
BaseURL: "http://" + server.Listener.Addr().String(),
Username: "server",
Password: "token",
},
}, },
setup: func(e *ETCD, ctxInfo *contextInfo) error { setup: func(e *ETCD, ctxInfo *contextInfo) error {
ctxInfo.ctx, ctxInfo.cancel = context.WithCancel(context.Background()) ctxInfo.ctx, ctxInfo.cancel = context.WithCancel(context.Background())
@ -322,9 +367,6 @@ func Test_UnitETCD_Start(t *testing.T) {
name: "default", name: "default",
cron: cron.New(), cron: cron.New(),
}, },
args: args{
clientAccessInfo: nil,
},
setup: func(e *ETCD, ctxInfo *contextInfo) error { setup: func(e *ETCD, ctxInfo *contextInfo) error {
ctxInfo.ctx, ctxInfo.cancel = context.WithCancel(context.Background()) ctxInfo.ctx, ctxInfo.cancel = context.WithCancel(context.Background())
if err := testutil.GenerateRuntime(e.config); err != nil { if err := testutil.GenerateRuntime(e.config); err != nil {
@ -364,6 +406,18 @@ func Test_UnitETCD_Start(t *testing.T) {
if err := e.Start(tt.fields.context.ctx, tt.args.clientAccessInfo); (err != nil) != tt.wantErr { if err := e.Start(tt.fields.context.ctx, tt.args.clientAccessInfo); (err != nil) != tt.wantErr {
t.Errorf("ETCD.Start() error = %v, wantErr %v", err, tt.wantErr) t.Errorf("ETCD.Start() error = %v, wantErr %v", err, tt.wantErr)
} }
if !tt.wantErr {
memberAddr = e.address
if err := wait.PollUntilContextTimeout(tt.fields.context.ctx, time.Second, time.Minute, true, func(ctx context.Context) (bool, error) {
if _, err := e.getETCDStatus(tt.fields.context.ctx, ""); err != nil {
t.Logf("Waiting to get etcd status: %v", err)
return false, nil
}
return true, nil
}); err != nil {
t.Errorf("Failed to get etcd status: %v", err)
}
}
if err := tt.teardown(e, &tt.fields.context); err != nil { if err := tt.teardown(e, &tt.fields.context); err != nil {
t.Errorf("Teardown for ETCD.Start() failed = %v", err) t.Errorf("Teardown for ETCD.Start() failed = %v", err)
} }

View File

@ -43,7 +43,12 @@ func CleanupDataDir(cnf *config.Control) {
// GenerateRuntime creates a temporary data dir and configures // GenerateRuntime creates a temporary data dir and configures
// config.ControlRuntime with all the appropriate certificate keys. // config.ControlRuntime with all the appropriate certificate keys.
func GenerateRuntime(cnf *config.Control) error { func GenerateRuntime(cnf *config.Control) error {
cnf.Runtime = config.NewRuntime(nil) // reuse ready channel from existing runtime if set
var readyCh <-chan struct{}
if cnf.Runtime != nil {
readyCh = cnf.Runtime.ContainerRuntimeReady
}
cnf.Runtime = config.NewRuntime(readyCh)
if err := GenerateDataDir(cnf); err != nil { if err := GenerateDataDir(cnf); err != nil {
return err return err
} }