github.com/pingcap/ticdc@v0.0.0-20220526033649-485a10ef2652/pkg/version/check_test.go (about)

     1  // Copyright 2020 PingCAP, 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 version
    15  
    16  import (
    17  	"context"
    18  	"fmt"
    19  	"net/http"
    20  	"net/url"
    21  	"testing"
    22  	"time"
    23  
    24  	"github.com/coreos/go-semver/semver"
    25  	"github.com/pingcap/check"
    26  	"github.com/pingcap/kvproto/pkg/metapb"
    27  	"github.com/pingcap/ticdc/cdc/model"
    28  	"github.com/pingcap/ticdc/pkg/util/testleak"
    29  	pd "github.com/tikv/pd/client"
    30  	"github.com/tikv/pd/pkg/tempurl"
    31  )
    32  
    33  func Test(t *testing.T) {
    34  	check.TestingT(t)
    35  }
    36  
    37  type checkSuite struct{}
    38  
    39  var _ = check.Suite(&checkSuite{})
    40  
    41  type mockPDClient struct {
    42  	pd.Client
    43  	getAllStores  func() []*metapb.Store
    44  	getVersion    func() string
    45  	getStatusCode func() int
    46  }
    47  
    48  func (m *mockPDClient) GetAllStores(ctx context.Context, opts ...pd.GetStoreOption) ([]*metapb.Store, error) {
    49  	if m.getAllStores != nil {
    50  		return m.getAllStores(), nil
    51  	}
    52  	return []*metapb.Store{}, nil
    53  }
    54  
    55  func (m *mockPDClient) ServeHTTP(resp http.ResponseWriter, _ *http.Request) {
    56  	// set status code at first, else will not work
    57  	if m.getStatusCode != nil {
    58  		resp.WriteHeader(m.getStatusCode())
    59  	}
    60  
    61  	if m.getVersion != nil {
    62  		_, _ = resp.Write([]byte(fmt.Sprintf(`{"version":"%s"}`, m.getVersion())))
    63  	}
    64  }
    65  
    66  func (s *checkSuite) TestCheckClusterVersion(c *check.C) {
    67  	defer testleak.AfterTest(c)()
    68  	mock := mockPDClient{
    69  		Client: nil,
    70  	}
    71  	pdURL, _ := url.Parse(tempurl.Alloc())
    72  	pdHTTP := fmt.Sprintf("http://%s", pdURL.Host)
    73  	srv := http.Server{Addr: pdURL.Host, Handler: &mock}
    74  	go func() {
    75  		//nolint:errcheck
    76  		srv.ListenAndServe()
    77  	}()
    78  	defer srv.Close()
    79  	for i := 0; i < 20; i++ {
    80  		time.Sleep(100 * time.Millisecond)
    81  		_, err := http.Get(pdHTTP)
    82  		if err == nil {
    83  			break
    84  		}
    85  		c.Error(err)
    86  		if i == 19 {
    87  			c.Fatal("http server timeout", err)
    88  		}
    89  	}
    90  
    91  	{
    92  		mock.getVersion = func() string {
    93  			return minPDVersion.String()
    94  		}
    95  		mock.getAllStores = func() []*metapb.Store {
    96  			return []*metapb.Store{{Version: MinTiKVVersion.String()}}
    97  		}
    98  		err := CheckClusterVersion(context.Background(), &mock, pdHTTP, nil, true)
    99  		c.Assert(err, check.IsNil)
   100  	}
   101  
   102  	{
   103  		mock.getVersion = func() string {
   104  			return `v1.0.0-alpha-271-g824ae7fd`
   105  		}
   106  		mock.getAllStores = func() []*metapb.Store {
   107  			return []*metapb.Store{{Version: MinTiKVVersion.String()}}
   108  		}
   109  		err := CheckClusterVersion(context.Background(), &mock, pdHTTP, nil, true)
   110  		c.Assert(err, check.ErrorMatches,
   111  			".*PD .* is not supported.*")
   112  	}
   113  
   114  	{
   115  		mock.getVersion = func() string {
   116  			return minPDVersion.String()
   117  		}
   118  		mock.getAllStores = func() []*metapb.Store {
   119  			// TiKV does not include 'v'.
   120  			return []*metapb.Store{{Version: `1.0.0-alpha-271-g824ae7fd`}}
   121  		}
   122  		err := CheckClusterVersion(context.Background(), &mock, pdHTTP, nil, true)
   123  		c.Assert(err, check.ErrorMatches,
   124  			".*TiKV .* is not supported.*")
   125  		err = CheckClusterVersion(context.Background(), &mock, pdHTTP, nil, false)
   126  		c.Assert(err, check.IsNil)
   127  	}
   128  
   129  	{
   130  		mock.getStatusCode = func() int {
   131  			return http.StatusBadRequest
   132  		}
   133  
   134  		err := CheckClusterVersion(context.Background(), &mock, pdHTTP, nil, false)
   135  		c.Assert(err, check.ErrorMatches, ".*response status: .*")
   136  	}
   137  }
   138  
   139  func (s *checkSuite) TestCompareVersion(c *check.C) {
   140  	defer testleak.AfterTest(c)()
   141  	c.Assert(semver.New("4.0.0-rc").Compare(*semver.New("4.0.0-rc.2")), check.Equals, -1)
   142  	c.Assert(semver.New("4.0.0-rc.1").Compare(*semver.New("4.0.0-rc.2")), check.Equals, -1)
   143  	c.Assert(semver.New(removeVAndHash("4.0.0-rc-35-g31dae220")).Compare(*semver.New("4.0.0-rc.2")), check.Equals, -1)
   144  	c.Assert(semver.New(removeVAndHash("4.0.0-9-g30f0b014")).Compare(*semver.New("4.0.0-rc.1")), check.Equals, 1)
   145  
   146  	c.Assert(semver.New(removeVAndHash("4.0.0-rc-35-g31dae220")).Compare(*semver.New("4.0.0-rc.2")), check.Equals, -1)
   147  	c.Assert(semver.New(removeVAndHash("4.0.0-9-g30f0b014")).Compare(*semver.New("4.0.0-rc.1")), check.Equals, 1)
   148  	c.Assert(semver.New(removeVAndHash("v3.0.0-beta-211-g09beefbe0-dirty")).
   149  		Compare(*semver.New("3.0.0-beta")), check.Equals, 0)
   150  	c.Assert(semver.New(removeVAndHash("v3.0.5-dirty")).
   151  		Compare(*semver.New("3.0.5")), check.Equals, 0)
   152  	c.Assert(semver.New(removeVAndHash("v3.0.5-beta.12-dirty")).
   153  		Compare(*semver.New("3.0.5-beta.12")), check.Equals, 0)
   154  	c.Assert(semver.New(removeVAndHash("v2.1.0-rc.1-7-g38c939f-dirty")).
   155  		Compare(*semver.New("2.1.0-rc.1")), check.Equals, 0)
   156  }
   157  
   158  func (s *checkSuite) TestReleaseSemver(c *check.C) {
   159  	defer testleak.AfterTest(c)()
   160  	cases := []struct{ releaseVersion, releaseSemver string }{
   161  		{"None", ""},
   162  		{"HEAD", ""},
   163  		{"v4.0.5", "4.0.5"},
   164  		{"v4.0.2-152-g62d7075-dev", "4.0.2"},
   165  	}
   166  
   167  	for _, cs := range cases {
   168  		ReleaseVersion = cs.releaseVersion
   169  		c.Assert(ReleaseSemver(), check.Equals, cs.releaseSemver, check.Commentf("%v", cs))
   170  	}
   171  }
   172  
   173  func (s *checkSuite) TestGetTiCDCClusterVersion(c *check.C) {
   174  	defer testleak.AfterTest(c)()
   175  	testCases := []struct {
   176  		captureInfos []*model.CaptureInfo
   177  		expected     TiCDCClusterVersion
   178  	}{
   179  		{
   180  			captureInfos: []*model.CaptureInfo{},
   181  			expected:     TiCDCClusterVersionUnknown,
   182  		},
   183  		{
   184  			captureInfos: []*model.CaptureInfo{
   185  				{ID: "capture1", Version: ""},
   186  				{ID: "capture2", Version: ""},
   187  				{ID: "capture3", Version: ""},
   188  			},
   189  			expected: TiCDCClusterVersion{MinTiCDCVersion, false},
   190  		},
   191  		{
   192  			captureInfos: []*model.CaptureInfo{
   193  				{ID: "capture1", Version: "5.0.1"},
   194  				{ID: "capture2", Version: "4.0.7"},
   195  				{ID: "capture3", Version: "5.0.0-rc"},
   196  			},
   197  			expected: TiCDCClusterVersion{semver.New("4.0.7"), false},
   198  		},
   199  		{
   200  			captureInfos: []*model.CaptureInfo{
   201  				{ID: "capture1", Version: "5.0.0-rc"},
   202  			},
   203  			expected: TiCDCClusterVersion{semver.New("5.0.0-rc"), false},
   204  		},
   205  		{
   206  			captureInfos: []*model.CaptureInfo{
   207  				{ID: "capture1", Version: "5.0.0"},
   208  			},
   209  			expected: TiCDCClusterVersion{semver.New("5.0.0"), false},
   210  		},
   211  		{
   212  			captureInfos: []*model.CaptureInfo{
   213  				{ID: "capture1", Version: "4.1.0"},
   214  			},
   215  			expected: TiCDCClusterVersion{semver.New("4.1.0"), false},
   216  		},
   217  		{
   218  			captureInfos: []*model.CaptureInfo{
   219  				{ID: "capture1", Version: "4.0.10"},
   220  			},
   221  			expected: TiCDCClusterVersion{semver.New("4.0.10"), false},
   222  		},
   223  	}
   224  	for _, tc := range testCases {
   225  		ver, err := GetTiCDCClusterVersion(tc.captureInfos)
   226  		c.Assert(err, check.IsNil)
   227  		c.Assert(ver, check.DeepEquals, tc.expected)
   228  	}
   229  }
   230  
   231  func (s *checkSuite) TestTiCDCClusterVersionFeaturesCompatible(c *check.C) {
   232  	defer testleak.AfterTest(c)()
   233  
   234  	ver := TiCDCClusterVersion{semver.New("4.0.10"), false}
   235  	c.Assert(ver.ShouldEnableUnifiedSorterByDefault(), check.Equals, false)
   236  	c.Assert(ver.ShouldEnableOldValueByDefault(), check.Equals, false)
   237  
   238  	ver = TiCDCClusterVersion{semver.New("4.0.12"), false}
   239  	c.Assert(ver.ShouldEnableUnifiedSorterByDefault(), check.Equals, false)
   240  	c.Assert(ver.ShouldEnableOldValueByDefault(), check.Equals, false)
   241  
   242  	ver = TiCDCClusterVersion{semver.New("4.0.13"), false}
   243  	c.Assert(ver.ShouldEnableUnifiedSorterByDefault(), check.Equals, true)
   244  	c.Assert(ver.ShouldEnableOldValueByDefault(), check.Equals, false)
   245  
   246  	ver = TiCDCClusterVersion{semver.New("4.0.13-hotfix"), false}
   247  	c.Assert(ver.ShouldEnableUnifiedSorterByDefault(), check.Equals, true)
   248  	c.Assert(ver.ShouldEnableOldValueByDefault(), check.Equals, false)
   249  
   250  	ver = TiCDCClusterVersion{semver.New("4.0.14"), false}
   251  	c.Assert(ver.ShouldEnableUnifiedSorterByDefault(), check.Equals, true)
   252  	c.Assert(ver.ShouldEnableOldValueByDefault(), check.Equals, false)
   253  
   254  	ver = TiCDCClusterVersion{semver.New("5.0.0-rc"), false}
   255  	c.Assert(ver.ShouldEnableUnifiedSorterByDefault(), check.Equals, false)
   256  	c.Assert(ver.ShouldEnableOldValueByDefault(), check.Equals, true)
   257  
   258  	ver = TiCDCClusterVersion{semver.New("5.0.0"), false}
   259  	c.Assert(ver.ShouldEnableUnifiedSorterByDefault(), check.Equals, true)
   260  	c.Assert(ver.ShouldEnableOldValueByDefault(), check.Equals, true)
   261  
   262  	ver = TiCDCClusterVersion{semver.New("5.1.0"), false}
   263  	c.Assert(ver.ShouldEnableUnifiedSorterByDefault(), check.Equals, true)
   264  	c.Assert(ver.ShouldEnableOldValueByDefault(), check.Equals, true)
   265  
   266  	ver = TiCDCClusterVersion{semver.New("5.2.0-alpha"), false}
   267  	c.Assert(ver.ShouldEnableUnifiedSorterByDefault(), check.Equals, true)
   268  	c.Assert(ver.ShouldEnableOldValueByDefault(), check.Equals, true)
   269  
   270  	c.Assert(TiCDCClusterVersionUnknown.ShouldEnableUnifiedSorterByDefault(), check.Equals, true)
   271  	c.Assert(TiCDCClusterVersionUnknown.ShouldEnableOldValueByDefault(), check.Equals, true)
   272  }