github.com/pingcap/br@v5.3.0-alpha.0.20220125034240-ec59c7b6ce30+incompatible/pkg/version/version_test.go (about)

     1  // Copyright 2020 PingCAP, Inc. Licensed under Apache-2.0.
     2  
     3  package version
     4  
     5  import (
     6  	"context"
     7  	"fmt"
     8  	"testing"
     9  
    10  	"github.com/coreos/go-semver/semver"
    11  	. "github.com/pingcap/check"
    12  	"github.com/pingcap/kvproto/pkg/metapb"
    13  	pd "github.com/tikv/pd/client"
    14  
    15  	"github.com/pingcap/br/pkg/version/build"
    16  )
    17  
    18  type checkSuite struct{}
    19  
    20  var _ = Suite(&checkSuite{})
    21  
    22  func TestT(t *testing.T) {
    23  	TestingT(t)
    24  }
    25  
    26  type mockPDClient struct {
    27  	pd.Client
    28  	getAllStores func() []*metapb.Store
    29  }
    30  
    31  func (m *mockPDClient) GetAllStores(ctx context.Context, opts ...pd.GetStoreOption) ([]*metapb.Store, error) {
    32  	if m.getAllStores != nil {
    33  		return m.getAllStores(), nil
    34  	}
    35  	return []*metapb.Store{}, nil
    36  }
    37  
    38  func tiflash(version string) []*metapb.Store {
    39  	return []*metapb.Store{
    40  		{Version: version, Labels: []*metapb.StoreLabel{{Key: "engine", Value: "tiflash"}}},
    41  	}
    42  }
    43  
    44  func (s *checkSuite) TestCheckClusterVersion(c *C) {
    45  	mock := mockPDClient{
    46  		Client: nil,
    47  	}
    48  
    49  	{
    50  		build.ReleaseVersion = "v4.0.5"
    51  		mock.getAllStores = func() []*metapb.Store {
    52  			return tiflash("v4.0.0-rc.1")
    53  		}
    54  		err := CheckClusterVersion(context.Background(), &mock, CheckVersionForBR)
    55  		c.Assert(err, ErrorMatches, `incompatible.*version v4.0.0-rc.1, try update it to 4.0.0.*`)
    56  	}
    57  
    58  	{
    59  		build.ReleaseVersion = "v3.0.14"
    60  		mock.getAllStores = func() []*metapb.Store {
    61  			return tiflash("v3.1.0-beta.1")
    62  		}
    63  		err := CheckClusterVersion(context.Background(), &mock, CheckVersionForBR)
    64  		c.Assert(err, ErrorMatches, `incompatible.*version v3.1.0-beta.1, try update it to 3.1.0.*`)
    65  	}
    66  
    67  	{
    68  		build.ReleaseVersion = "v3.1.1"
    69  		mock.getAllStores = func() []*metapb.Store {
    70  			return tiflash("v3.0.15")
    71  		}
    72  		err := CheckClusterVersion(context.Background(), &mock, CheckVersionForBR)
    73  		c.Assert(err, ErrorMatches, `incompatible.*version v3.0.15, try update it to 3.1.0.*`)
    74  	}
    75  
    76  	{
    77  		build.ReleaseVersion = "v3.1.0-beta.2"
    78  		mock.getAllStores = func() []*metapb.Store {
    79  			return []*metapb.Store{{Version: minTiKVVersion.String()}}
    80  		}
    81  		err := CheckClusterVersion(context.Background(), &mock, CheckVersionForBR)
    82  		c.Assert(err, IsNil)
    83  	}
    84  
    85  	{
    86  		build.ReleaseVersion = "v3.1.0-beta.2"
    87  		mock.getAllStores = func() []*metapb.Store {
    88  			// TiKV is too lower to support BR
    89  			return []*metapb.Store{{Version: `v2.1.0`}}
    90  		}
    91  		err := CheckClusterVersion(context.Background(), &mock, CheckVersionForBR)
    92  		c.Assert(err, ErrorMatches, ".*TiKV .* don't support BR, please upgrade cluster .*")
    93  	}
    94  
    95  	{
    96  		build.ReleaseVersion = "v3.1.0"
    97  		mock.getAllStores = func() []*metapb.Store {
    98  			// TiKV v3.1.0-beta.2 is incompatible with BR v3.1.0
    99  			return []*metapb.Store{{Version: minTiKVVersion.String()}}
   100  		}
   101  		err := CheckClusterVersion(context.Background(), &mock, CheckVersionForBR)
   102  		c.Assert(err, ErrorMatches, "TiKV .* mismatch, please .*")
   103  	}
   104  
   105  	{
   106  		build.ReleaseVersion = "v3.1.0"
   107  		mock.getAllStores = func() []*metapb.Store {
   108  			// TiKV v4.0.0-rc major version mismatch with BR v3.1.0
   109  			return []*metapb.Store{{Version: "v4.0.0-rc"}}
   110  		}
   111  		err := CheckClusterVersion(context.Background(), &mock, CheckVersionForBR)
   112  		c.Assert(err, ErrorMatches, "TiKV .* major version mismatch, please .*")
   113  	}
   114  
   115  	{
   116  		build.ReleaseVersion = "v4.0.0-rc.2"
   117  		mock.getAllStores = func() []*metapb.Store {
   118  			// TiKV v4.0.0-rc.2 is incompatible with BR v4.0.0-beta.1
   119  			return []*metapb.Store{{Version: "v4.0.0-beta.1"}}
   120  		}
   121  		err := CheckClusterVersion(context.Background(), &mock, CheckVersionForBR)
   122  		c.Assert(err, ErrorMatches, "TiKV .* mismatch, please .*")
   123  	}
   124  
   125  	{
   126  		build.ReleaseVersion = "v4.0.0-rc.2"
   127  		mock.getAllStores = func() []*metapb.Store {
   128  			// TiKV v4.0.0-rc.1 with BR v4.0.0-rc.2 is ok
   129  			return []*metapb.Store{{Version: "v4.0.0-rc.1"}}
   130  		}
   131  		err := CheckClusterVersion(context.Background(), &mock, CheckVersionForBR)
   132  		c.Assert(err, IsNil)
   133  	}
   134  
   135  	{
   136  		// Even across many patch versions, backup should be usable.
   137  		mock.getAllStores = func() []*metapb.Store {
   138  			return []*metapb.Store{{Version: "v4.0.0-rc.1"}}
   139  		}
   140  		err := CheckClusterVersion(context.Background(), &mock, CheckVersionForBackup(semver.New("4.0.12")))
   141  		c.Assert(err, IsNil)
   142  	}
   143  
   144  	{
   145  		// Restore across major version isn't allowed.
   146  		mock.getAllStores = func() []*metapb.Store {
   147  			return []*metapb.Store{{Version: "v4.0.0-rc.1"}}
   148  		}
   149  		err := CheckClusterVersion(context.Background(), &mock, CheckVersionForBackup(semver.New("5.0.0-rc")))
   150  		c.Assert(err, Not(IsNil))
   151  	}
   152  
   153  	{
   154  		build.ReleaseVersion = "v4.0.0-rc.1"
   155  		mock.getAllStores = func() []*metapb.Store {
   156  			// TiKV v4.0.0-rc.2 with BR v4.0.0-rc.1 is ok
   157  			return []*metapb.Store{{Version: "v4.0.0-rc.2"}}
   158  		}
   159  		err := CheckClusterVersion(context.Background(), &mock, CheckVersionForBR)
   160  		c.Assert(err, IsNil)
   161  	}
   162  }
   163  
   164  func (s *checkSuite) TestCompareVersion(c *C) {
   165  	c.Assert(semver.New("4.0.0-rc").Compare(*semver.New("4.0.0-rc.2")), Equals, -1)
   166  	c.Assert(semver.New("4.0.0-beta.3").Compare(*semver.New("4.0.0-rc.2")), Equals, -1)
   167  	c.Assert(semver.New("4.0.0-rc.1").Compare(*semver.New("4.0.0")), Equals, -1)
   168  	c.Assert(semver.New("4.0.0-beta.1").Compare(*semver.New("4.0.0")), Equals, -1)
   169  	c.Assert(semver.New(removeVAndHash("4.0.0-rc-35-g31dae220")).Compare(*semver.New("4.0.0-rc.2")), Equals, -1)
   170  	c.Assert(semver.New(removeVAndHash("4.0.0-9-g30f0b014")).Compare(*semver.New("4.0.0-rc.1")), Equals, 1)
   171  	c.Assert(semver.New(removeVAndHash("v3.0.0-beta-211-g09beefbe0-dirty")).
   172  		Compare(*semver.New("3.0.0-beta")), Equals, 0)
   173  	c.Assert(semver.New(removeVAndHash("v3.0.5-dirty")).
   174  		Compare(*semver.New("3.0.5")), Equals, 0)
   175  	c.Assert(semver.New(removeVAndHash("v3.0.5-beta.12-dirty")).
   176  		Compare(*semver.New("3.0.5-beta.12")), Equals, 0)
   177  	c.Assert(semver.New(removeVAndHash("v2.1.0-rc.1-7-g38c939f-dirty")).
   178  		Compare(*semver.New("2.1.0-rc.1")), Equals, 0)
   179  }
   180  
   181  func (s *checkSuite) TestNextMajorVersion(c *C) {
   182  	build.ReleaseVersion = "v4.0.0-rc.1"
   183  	c.Assert(NextMajorVersion().String(), Equals, "5.0.0")
   184  	build.ReleaseVersion = "4.0.0-rc-35-g31dae220"
   185  	c.Assert(NextMajorVersion().String(), Equals, "5.0.0")
   186  	build.ReleaseVersion = "4.0.0-9-g30f0b014"
   187  	c.Assert(NextMajorVersion().String(), Equals, "5.0.0")
   188  
   189  	build.ReleaseVersion = "v5.0.0-rc.2"
   190  	c.Assert(NextMajorVersion().String(), Equals, "6.0.0")
   191  	build.ReleaseVersion = "v5.0.0-master"
   192  	c.Assert(NextMajorVersion().String(), Equals, "6.0.0")
   193  }
   194  
   195  func (s *checkSuite) TestExtractTiDBVersion(c *C) {
   196  	vers, err := ExtractTiDBVersion("5.7.10-TiDB-v2.1.0-rc.1-7-g38c939f")
   197  	c.Assert(err, IsNil)
   198  	c.Assert(*vers, Equals, *semver.New("2.1.0-rc.1"))
   199  
   200  	vers, err = ExtractTiDBVersion("5.7.10-TiDB-v2.0.4-1-g06a0bf5")
   201  	c.Assert(err, IsNil)
   202  	c.Assert(*vers, Equals, *semver.New("2.0.4"))
   203  
   204  	vers, err = ExtractTiDBVersion("5.7.10-TiDB-v2.0.7")
   205  	c.Assert(err, IsNil)
   206  	c.Assert(*vers, Equals, *semver.New("2.0.7"))
   207  
   208  	vers, err = ExtractTiDBVersion("8.0.12-TiDB-v3.0.5-beta.12")
   209  	c.Assert(err, IsNil)
   210  	c.Assert(*vers, Equals, *semver.New("3.0.5-beta.12"))
   211  
   212  	vers, err = ExtractTiDBVersion("5.7.25-TiDB-v3.0.0-beta-211-g09beefbe0-dirty")
   213  	c.Assert(err, IsNil)
   214  	c.Assert(*vers, Equals, *semver.New("3.0.0-beta"))
   215  
   216  	vers, err = ExtractTiDBVersion("8.0.12-TiDB-v3.0.5-dirty")
   217  	c.Assert(err, IsNil)
   218  	c.Assert(*vers, Equals, *semver.New("3.0.5"))
   219  
   220  	vers, err = ExtractTiDBVersion("8.0.12-TiDB-v3.0.5-beta.12-dirty")
   221  	c.Assert(err, IsNil)
   222  	c.Assert(*vers, Equals, *semver.New("3.0.5-beta.12"))
   223  
   224  	vers, err = ExtractTiDBVersion("5.7.10-TiDB-v2.1.0-rc.1-7-g38c939f-dirty")
   225  	c.Assert(err, IsNil)
   226  	c.Assert(*vers, Equals, *semver.New("2.1.0-rc.1"))
   227  
   228  	_, err = ExtractTiDBVersion("")
   229  	c.Assert(err, ErrorMatches, "not a valid TiDB version.*")
   230  
   231  	_, err = ExtractTiDBVersion("8.0.12")
   232  	c.Assert(err, ErrorMatches, "not a valid TiDB version.*")
   233  
   234  	_, err = ExtractTiDBVersion("not-a-valid-version")
   235  	c.Assert(err, NotNil)
   236  }
   237  
   238  func (s *checkSuite) TestCheckVersion(c *C) {
   239  	err := CheckVersion("TiNB", *semver.New("2.3.5"), *semver.New("2.1.0"), *semver.New("3.0.0"))
   240  	c.Assert(err, IsNil)
   241  
   242  	err = CheckVersion("TiNB", *semver.New("2.1.0"), *semver.New("2.3.5"), *semver.New("3.0.0"))
   243  	c.Assert(err, ErrorMatches, "TiNB version too old.*")
   244  
   245  	err = CheckVersion("TiNB", *semver.New("3.1.0"), *semver.New("2.3.5"), *semver.New("3.0.0"))
   246  	c.Assert(err, ErrorMatches, "TiNB version too new.*")
   247  
   248  	err = CheckVersion("TiNB", *semver.New("3.0.0-beta"), *semver.New("2.3.5"), *semver.New("3.0.0"))
   249  	c.Assert(err, ErrorMatches, "TiNB version too new.*")
   250  }
   251  
   252  type versionEqualsC struct{}
   253  
   254  func (v versionEqualsC) Info() *CheckerInfo {
   255  	return &CheckerInfo{
   256  		Name:   "VersionEquals",
   257  		Params: []string{"source", "target"},
   258  	}
   259  }
   260  
   261  func (v versionEqualsC) Check(params []interface{}, names []string) (result bool, error string) {
   262  	source := params[0].(*semver.Version)
   263  	target := params[1].(*semver.Version)
   264  
   265  	if source == nil || target == nil {
   266  		if target == source {
   267  			return true, ""
   268  		}
   269  		return false, fmt.Sprintf("one of version is nil but another is not (%s and %s)", params[0], params[1])
   270  	}
   271  
   272  	if source.Equal(*target) {
   273  		return true, ""
   274  	}
   275  	return false, fmt.Sprintf("version not equal (%s vs %s)", source, target)
   276  }
   277  
   278  var versionEquals versionEqualsC
   279  
   280  func (s *checkSuite) TestNormalizeBackupVersion(c *C) {
   281  	cases := []struct {
   282  		target string
   283  		source string
   284  	}{
   285  		{"4.0.0", `"4.0.0\n"`},
   286  		{"5.0.0-rc.x", `"5.0.0-rc.x\n"`},
   287  		{"5.0.0-rc.x", `5.0.0-rc.x`},
   288  		{"4.0.12", `"4.0.12"` + "\n"},
   289  		{"<error-version>", ""},
   290  	}
   291  
   292  	for _, testCase := range cases {
   293  		target, _ := semver.NewVersion(testCase.target)
   294  		source := NormalizeBackupVersion(testCase.source)
   295  		c.Assert(source, versionEquals, target)
   296  	}
   297  }