github.com/matrixorigin/matrixone@v1.2.0/pkg/tests/upgrade/upgrade_init_test.go (about)

     1  // Copyright 2024 Matrix Origin
     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  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package upgrade
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"sync/atomic"
    21  	"testing"
    22  	"time"
    23  
    24  	"github.com/matrixorigin/matrixone/pkg/bootstrap"
    25  	"github.com/matrixorigin/matrixone/pkg/bootstrap/versions"
    26  	"github.com/matrixorigin/matrixone/pkg/bootstrap/versions/v1_2_0"
    27  	"github.com/matrixorigin/matrixone/pkg/catalog"
    28  	"github.com/matrixorigin/matrixone/pkg/cnservice"
    29  	"github.com/matrixorigin/matrixone/pkg/container/vector"
    30  	"github.com/matrixorigin/matrixone/pkg/tests/service"
    31  	"github.com/matrixorigin/matrixone/pkg/util/executor"
    32  	"github.com/stretchr/testify/require"
    33  )
    34  
    35  func TestUpgradeFrameworkInit(t *testing.T) {
    36  	if testing.Short() {
    37  		t.Skip("skipping in short mode.")
    38  		return
    39  	}
    40  
    41  	runUpgradeTest(
    42  		t,
    43  		func(opts service.Options) service.Options {
    44  			return opts.WithCNOptionFunc(func(i int) []cnservice.Option {
    45  				return []cnservice.Option{
    46  					cnservice.WithBootstrapOptions(
    47  						bootstrap.WithCheckUpgradeDuration(time.Millisecond*100),
    48  						bootstrap.WithCheckUpgradeTenantDuration(time.Millisecond*100),
    49  						bootstrap.WithCheckUpgradeTenantWorkers(1),
    50  						bootstrap.WithUpgradeTenantBatch(1),
    51  						bootstrap.WithUpgradeHandles([]bootstrap.VersionHandle{
    52  							v1_2_0.Handler,
    53  						})),
    54  				}
    55  			})
    56  		},
    57  		func(c service.Cluster) {
    58  			waitVersionReady(t, "1.2.0", c)
    59  			checkVersionUpgrades(t, "1.2.0", c, func(upgrades []versions.VersionUpgrade) {
    60  				require.Equal(t, 0, len(upgrades))
    61  			})
    62  		})
    63  }
    64  
    65  func TestUpgradeFrameworkInitWithHighVersion(t *testing.T) {
    66  	if testing.Short() {
    67  		t.Skip("skipping in short mode.")
    68  		return
    69  	}
    70  
    71  	h := newTestVersionHandler("1.3.0", "1.2.0", versions.Yes, versions.No)
    72  
    73  	runUpgradeTest(
    74  		t,
    75  		func(opts service.Options) service.Options {
    76  			return opts.WithCNOptionFunc(func(i int) []cnservice.Option {
    77  				return []cnservice.Option{
    78  					cnservice.WithBootstrapOptions(
    79  						bootstrap.WithCheckUpgradeDuration(time.Millisecond*100),
    80  						bootstrap.WithCheckUpgradeTenantDuration(time.Millisecond*100),
    81  						bootstrap.WithCheckUpgradeTenantWorkers(1),
    82  						bootstrap.WithUpgradeTenantBatch(1),
    83  						bootstrap.WithUpgradeHandles([]bootstrap.VersionHandle{
    84  							v1_2_0.Handler,
    85  							h,
    86  						})),
    87  				}
    88  			})
    89  		},
    90  		func(c service.Cluster) {
    91  			waitVersionReady(t, "1.3.0", c)
    92  			checkVersionUpgrades(t, "1.3.0", c, func(upgrades []versions.VersionUpgrade) {
    93  				require.Equal(t, 0, len(upgrades))
    94  			})
    95  		})
    96  }
    97  
    98  func checkVersionUpgrades(
    99  	t *testing.T,
   100  	version string,
   101  	c service.Cluster,
   102  	ck func([]versions.VersionUpgrade)) {
   103  	svc, err := c.GetCNServiceIndexed(0)
   104  	require.NoError(t, err)
   105  	exec := svc.GetSQLExecutor()
   106  	ctx, cancel := context.WithTimeout(context.Background(), time.Second*60)
   107  	defer cancel()
   108  
   109  	now, _ := c.Clock().Now()
   110  	opts := executor.Options{}.WithDatabase(catalog.MO_CATALOG).WithMinCommittedTS(now)
   111  	err = exec.ExecTxn(
   112  		ctx,
   113  		func(txn executor.TxnExecutor) error {
   114  			upgrades, err := versions.GetUpgradeVersions(version, 0, txn, false, false)
   115  			require.NoError(t, err)
   116  			ck(upgrades)
   117  			return err
   118  		},
   119  		opts)
   120  	require.NoError(t, err)
   121  }
   122  
   123  func waitVersionReady(
   124  	t *testing.T,
   125  	version string,
   126  	c service.Cluster) {
   127  	svc, err := c.GetCNServiceIndexed(0)
   128  	require.NoError(t, err)
   129  	exec := svc.GetSQLExecutor()
   130  	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
   131  	defer cancel()
   132  
   133  	for {
   134  		ready := false
   135  		opts := executor.Options{}.WithDatabase(catalog.MO_CATALOG)
   136  		err := exec.ExecTxn(
   137  			ctx,
   138  			func(txn executor.TxnExecutor) error {
   139  				v, _, err := versions.GetVersionState(version, 0, txn, false)
   140  				if err != nil {
   141  					return err
   142  				}
   143  				ready = v == versions.StateReady
   144  				return nil
   145  			},
   146  			opts)
   147  		require.NoError(t, err)
   148  		if ready {
   149  			return
   150  		}
   151  		time.Sleep(time.Second)
   152  	}
   153  }
   154  
   155  var (
   156  	accountIndex atomic.Uint64
   157  )
   158  
   159  func createTenants(
   160  	t *testing.T,
   161  	c service.Cluster,
   162  	n int,
   163  	version string) []int32 {
   164  	svc, err := c.GetCNServiceIndexed(0)
   165  	require.NoError(t, err)
   166  	exec := svc.GetSQLExecutor()
   167  	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
   168  	defer cancel()
   169  
   170  	var ids []int32
   171  	opts := executor.Options{}.WithWaitCommittedLogApplied().WithDatabase(catalog.MO_CATALOG)
   172  	err = exec.ExecTxn(
   173  		ctx,
   174  		func(txn executor.TxnExecutor) error {
   175  			for i := 0; i < n; i++ {
   176  				sql := fmt.Sprintf(`insert into mo_catalog.mo_account(
   177  					account_name,
   178  					status,
   179  					created_time,
   180  					comments,
   181  					create_version) values ('test_%d','open',current_timestamp(),' ','%s');`,
   182  					accountIndex.Add(1),
   183  					version)
   184  				res, err := txn.Exec(sql, executor.StatementOption{})
   185  				if err != nil {
   186  					return err
   187  				}
   188  				ids = append(ids, int32(res.LastInsertID))
   189  				res.Close()
   190  			}
   191  			return nil
   192  		},
   193  		opts)
   194  	require.NoError(t, err)
   195  	return ids
   196  }
   197  
   198  func checkTenantVersion(
   199  	t *testing.T,
   200  	c service.Cluster,
   201  	version string,
   202  	ids ...int32) {
   203  	svc, err := c.GetCNServiceIndexed(0)
   204  	require.NoError(t, err)
   205  	exec := svc.GetSQLExecutor()
   206  	ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
   207  	defer cancel()
   208  
   209  	opts := executor.Options{}.WithWaitCommittedLogApplied().WithDatabase(catalog.MO_CATALOG)
   210  
   211  	sql := "select account_id, create_version from mo_account"
   212  	if len(ids) > 0 {
   213  		sql += " where account_id in ("
   214  		for _, id := range ids {
   215  			sql += fmt.Sprintf("%d,", id)
   216  		}
   217  		sql = sql[:len(sql)-1] + ")"
   218  	}
   219  
   220  	res, err := exec.Exec(ctx, sql, opts)
   221  	require.NoError(t, err)
   222  	defer res.Close()
   223  
   224  	res.ReadRows(func(rows int, cols []*vector.Vector) bool {
   225  		for i := 0; i < rows; i++ {
   226  			require.Equal(t, version, cols[1].GetStringAt(i))
   227  		}
   228  		return true
   229  	})
   230  }
   231  
   232  func runUpgradeTest(
   233  	t *testing.T,
   234  	adjustOptions func(service.Options) service.Options,
   235  	fn func(c service.Cluster),
   236  ) {
   237  	ctx := context.Background()
   238  	opts := service.DefaultOptions()
   239  	if adjustOptions != nil {
   240  		opts = adjustOptions(opts)
   241  	}
   242  
   243  	c, err := service.NewCluster(
   244  		ctx,
   245  		t,
   246  		opts)
   247  	require.NoError(t, err)
   248  	// close the cluster
   249  	defer func(c service.Cluster) {
   250  		require.NoError(t, c.Close())
   251  	}(c)
   252  	// start the cluster
   253  	require.NoError(t, c.Start())
   254  
   255  	fn(c)
   256  }
   257  
   258  func newTestVersionHandler(
   259  	version, minVersion string,
   260  	upgradeCluster, upgradeTenant int32) *testVersionHandle {
   261  	return &testVersionHandle{
   262  		metadata: versions.Version{
   263  			Version:           version,
   264  			MinUpgradeVersion: minVersion,
   265  			UpgradeCluster:    upgradeCluster,
   266  			UpgradeTenant:     upgradeTenant,
   267  		},
   268  	}
   269  }
   270  
   271  type testVersionHandle struct {
   272  	metadata                 versions.Version
   273  	callHandleClusterUpgrade atomic.Uint64
   274  	callHandleTenantUpgrade  atomic.Uint64
   275  }
   276  
   277  func (h *testVersionHandle) Metadata() versions.Version {
   278  	return h.metadata
   279  }
   280  func (h *testVersionHandle) Prepare(ctx context.Context, txn executor.TxnExecutor, final bool) error {
   281  	return nil
   282  }
   283  func (h *testVersionHandle) HandleClusterUpgrade(ctx context.Context, txn executor.TxnExecutor) error {
   284  	h.callHandleClusterUpgrade.Add(1)
   285  	return nil
   286  }
   287  func (h *testVersionHandle) HandleTenantUpgrade(ctx context.Context, tenantID int32, txn executor.TxnExecutor) error {
   288  	h.callHandleTenantUpgrade.Add(1)
   289  	return nil
   290  }
   291  
   292  func (h *testVersionHandle) HandleCreateFrameworkDeps(txn executor.TxnExecutor) error {
   293  	return nil
   294  }