github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/causetstore/petri/acyclic/tenant/manager_test.go (about)

     1  // Copyright 2020 WHTCORPS INC, Inc.
     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  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package tenant_test
    15  
    16  import (
    17  	"context"
    18  	"fmt"
    19  	"runtime"
    20  	"testing"
    21  	"time"
    22  
    23  	"github.com/whtcorpsinc/BerolinaSQL/terror"
    24  	. "github.com/whtcorpsinc/check"
    25  	"github.com/whtcorpsinc/errors"
    26  	"github.com/whtcorpsinc/milevadb/causetstore/mockstore"
    27  	. "github.com/whtcorpsinc/milevadb/dbs"
    28  	"github.com/whtcorpsinc/milevadb/soliton/logutil"
    29  	"github.com/whtcorpsinc/milevadb/tenant"
    30  	"go.etcd.io/etcd/clientv3"
    31  	"go.etcd.io/etcd/clientv3/concurrency"
    32  	"go.etcd.io/etcd/integration"
    33  	goctx "golang.org/x/net/context"
    34  )
    35  
    36  const testLease = 5 * time.Millisecond
    37  
    38  func TestT(t *testing.T) {
    39  	TestingT(t)
    40  }
    41  
    42  func checkTenant(d DBS, fbVal bool) (isTenant bool) {
    43  	manager := d.TenantManager()
    44  	// The longest to wait for 30 seconds to
    45  	// make sure that campaigning tenants is completed.
    46  	for i := 0; i < 6000; i++ {
    47  		time.Sleep(5 * time.Millisecond)
    48  		isTenant = manager.IsTenant()
    49  		if isTenant == fbVal {
    50  			break
    51  		}
    52  	}
    53  	return
    54  }
    55  
    56  func TestSingle(t *testing.T) {
    57  	if runtime.GOOS == "windows" {
    58  		t.Skip("integration.NewClusterV3 will create file contains a colon which is not allowed on Windows")
    59  	}
    60  	causetstore, err := mockstore.NewMockStore()
    61  	if err != nil {
    62  		t.Fatal(err)
    63  	}
    64  	defer causetstore.Close()
    65  
    66  	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1})
    67  	defer clus.Terminate(t)
    68  	cli := clus.RandClient()
    69  	ctx := goctx.Background()
    70  	d := NewDBS(
    71  		ctx,
    72  		WithEtcdClient(cli),
    73  		WithStore(causetstore),
    74  		WithLease(testLease),
    75  	)
    76  	err = d.Start(nil)
    77  	if err != nil {
    78  		t.Fatalf("DBS start failed %v", err)
    79  	}
    80  	defer d.Stop()
    81  
    82  	isTenant := checkTenant(d, true)
    83  	if !isTenant {
    84  		t.Fatalf("expect true, got isTenant:%v", isTenant)
    85  	}
    86  
    87  	// test for newStochastik failed
    88  	ctx, cancel := goctx.WithCancel(ctx)
    89  	manager := tenant.NewTenantManager(ctx, cli, "dbs", "dbs_id", DBSTenantKey)
    90  	cancel()
    91  	err = manager.CampaignTenant()
    92  	if !terror.ErrorEqual(err, goctx.Canceled) &&
    93  		!terror.ErrorEqual(err, goctx.DeadlineExceeded) {
    94  		t.Fatalf("campaigned result don't match, err %v", err)
    95  	}
    96  	isTenant = checkTenant(d, true)
    97  	if !isTenant {
    98  		t.Fatalf("expect true, got isTenant:%v", isTenant)
    99  	}
   100  	// The test is used to exit campaign loop.
   101  	d.TenantManager().Cancel()
   102  	isTenant = checkTenant(d, false)
   103  	if isTenant {
   104  		t.Fatalf("expect false, got isTenant:%v", isTenant)
   105  	}
   106  	time.Sleep(200 * time.Millisecond)
   107  	tenantID, _ := manager.GetTenantID(goctx.Background())
   108  	// The error is ok to be not nil since we canceled the manager.
   109  	if tenantID != "" {
   110  		t.Fatalf("tenant %s is not empty", tenantID)
   111  	}
   112  }
   113  
   114  func TestCluster(t *testing.T) {
   115  	if runtime.GOOS == "windows" {
   116  		t.Skip("integration.NewClusterV3 will create file contains a colon which is not allowed on Windows")
   117  	}
   118  	tmpTTL := 3
   119  	orignalTTL := tenant.ManagerStochastikTTL
   120  	tenant.ManagerStochastikTTL = tmpTTL
   121  	defer func() {
   122  		tenant.ManagerStochastikTTL = orignalTTL
   123  	}()
   124  	causetstore, err := mockstore.NewMockStore()
   125  	if err != nil {
   126  		t.Fatal(err)
   127  	}
   128  	defer causetstore.Close()
   129  	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 4})
   130  	defer clus.Terminate(t)
   131  
   132  	cli := clus.Client(0)
   133  	d := NewDBS(
   134  		goctx.Background(),
   135  		WithEtcdClient(cli),
   136  		WithStore(causetstore),
   137  		WithLease(testLease),
   138  	)
   139  	err = d.Start(nil)
   140  	if err != nil {
   141  		t.Fatalf("DBS start failed %v", err)
   142  	}
   143  	isTenant := checkTenant(d, true)
   144  	if !isTenant {
   145  		t.Fatalf("expect true, got isTenant:%v", isTenant)
   146  	}
   147  	cli1 := clus.Client(1)
   148  	d1 := NewDBS(
   149  		goctx.Background(),
   150  		WithEtcdClient(cli1),
   151  		WithStore(causetstore),
   152  		WithLease(testLease),
   153  	)
   154  	err = d1.Start(nil)
   155  	if err != nil {
   156  		t.Fatalf("DBS start failed %v", err)
   157  	}
   158  	isTenant = checkTenant(d1, false)
   159  	if isTenant {
   160  		t.Fatalf("expect false, got isTenant:%v", isTenant)
   161  	}
   162  
   163  	// Delete the leader key, the d1 become the tenant.
   164  	cliRW := clus.Client(2)
   165  	err = deleteLeader(cliRW, DBSTenantKey)
   166  	if err != nil {
   167  		t.Fatal(err)
   168  	}
   169  	isTenant = checkTenant(d, false)
   170  	if isTenant {
   171  		t.Fatalf("expect false, got isTenant:%v", isTenant)
   172  	}
   173  	d.Stop()
   174  
   175  	// d3 (not tenant) stop
   176  	cli3 := clus.Client(3)
   177  	d3 := NewDBS(
   178  		goctx.Background(),
   179  		WithEtcdClient(cli3),
   180  		WithStore(causetstore),
   181  		WithLease(testLease),
   182  	)
   183  	err = d3.Start(nil)
   184  	if err != nil {
   185  		t.Fatalf("DBS start failed %v", err)
   186  	}
   187  	defer d3.Stop()
   188  	isTenant = checkTenant(d3, false)
   189  	if isTenant {
   190  		t.Fatalf("expect false, got isTenant:%v", isTenant)
   191  	}
   192  	d3.Stop()
   193  
   194  	// Cancel the tenant context, there is no tenant.
   195  	d1.Stop()
   196  	time.Sleep(time.Duration(tmpTTL+1) * time.Second)
   197  	stochastik, err := concurrency.NewStochastik(cliRW)
   198  	if err != nil {
   199  		t.Fatalf("new stochastik failed %v", err)
   200  	}
   201  	elec := concurrency.NewElection(stochastik, DBSTenantKey)
   202  	logPrefix := fmt.Sprintf("[dbs] %s tenantManager %s", DBSTenantKey, "useless id")
   203  	logCtx := logutil.WithKeyValue(context.Background(), "tenant info", logPrefix)
   204  	_, err = tenant.GetTenantInfo(goctx.Background(), logCtx, elec, "useless id")
   205  	if !terror.ErrorEqual(err, concurrency.ErrElectionNoLeader) {
   206  		t.Fatalf("get tenant info result don't match, err %v", err)
   207  	}
   208  }
   209  
   210  func deleteLeader(cli *clientv3.Client, prefixKey string) error {
   211  	stochastik, err := concurrency.NewStochastik(cli)
   212  	if err != nil {
   213  		return errors.Trace(err)
   214  	}
   215  	defer stochastik.Close()
   216  	elec := concurrency.NewElection(stochastik, prefixKey)
   217  	resp, err := elec.Leader(goctx.Background())
   218  	if err != nil {
   219  		return errors.Trace(err)
   220  	}
   221  	_, err = cli.Delete(goctx.Background(), string(resp.Ekvs[0].Key))
   222  	return errors.Trace(err)
   223  }