github.com/dolthub/dolt/go@v0.40.5-0.20240520175717-68db7794bea6/libraries/doltcore/doltdb/feature_version_test.go (about)

     1  // Copyright 2020 Dolthub, 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  // 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 doltdb_test
    16  
    17  import (
    18  	"context"
    19  	"testing"
    20  
    21  	"github.com/stretchr/testify/assert"
    22  	"github.com/stretchr/testify/require"
    23  
    24  	"github.com/dolthub/dolt/go/cmd/dolt/cli"
    25  	"github.com/dolthub/dolt/go/cmd/dolt/commands"
    26  	"github.com/dolthub/dolt/go/libraries/doltcore/doltdb"
    27  	"github.com/dolthub/dolt/go/libraries/doltcore/dtestutils"
    28  	"github.com/dolthub/dolt/go/libraries/doltcore/env"
    29  )
    30  
    31  const (
    32  	newVersion doltdb.FeatureVersion = 1 << 19
    33  	oldVersion doltdb.FeatureVersion = 1 << 13
    34  )
    35  
    36  // |doltdb.FeatureVersion| is manipulated during these integration tests.
    37  // Save a copy here to assert that it was correctly restored.
    38  var DoltFeatureVersionCopy = doltdb.DoltFeatureVersion
    39  
    40  type fvTest struct {
    41  	name   string
    42  	setup  []fvCommand
    43  	expVer doltdb.FeatureVersion
    44  
    45  	// for error path testing
    46  	errCmds []fvCommand
    47  }
    48  
    49  type args []string
    50  
    51  type fvCommand struct {
    52  	user fvUser
    53  	cmd  cli.Command
    54  	args args
    55  }
    56  
    57  func (cmd fvCommand) exec(ctx context.Context, dEnv *env.DoltEnv) int {
    58  	// execute the command using |cmd.user|'s Feature Version
    59  	doltdb.DoltFeatureVersion = cmd.user.vers
    60  	defer func() { doltdb.DoltFeatureVersion = DoltFeatureVersionCopy }()
    61  
    62  	cliCtx, _ := commands.NewArgFreeCliContext(ctx, dEnv)
    63  
    64  	return cmd.cmd.Exec(ctx, cmd.cmd.Name(), cmd.args, dEnv, cliCtx)
    65  }
    66  
    67  type fvUser struct {
    68  	vers doltdb.FeatureVersion
    69  }
    70  
    71  var NewClient = fvUser{vers: newVersion}
    72  var OldClient = fvUser{vers: oldVersion}
    73  
    74  func TestFeatureVersion(t *testing.T) {
    75  
    76  	tests := []fvTest{
    77  		{
    78  			name: "smoke test",
    79  			setup: []fvCommand{
    80  				{OldClient, commands.SqlCmd{}, args{"-q", "CREATE TABLE test (pk int PRIMARY KEY);"}},
    81  			},
    82  			expVer: oldVersion,
    83  		},
    84  		{
    85  			name: "CREATE TABLE statements write feature version",
    86  			setup: []fvCommand{
    87  				{OldClient, commands.SqlCmd{}, args{"-q", "CREATE TABLE test (pk int PRIMARY KEY);"}},
    88  				{NewClient, commands.SqlCmd{}, args{"-q", "CREATE TABLE quiz (pk int PRIMARY KEY);"}},
    89  			},
    90  			expVer: newVersion,
    91  		},
    92  		{
    93  			name: "DROP TABLE statements write feature version",
    94  			setup: []fvCommand{
    95  				{OldClient, commands.SqlCmd{}, args{"-q", "CREATE TABLE test (pk int PRIMARY KEY);"}},
    96  				{NewClient, commands.SqlCmd{}, args{"-q", "DROP TABLE test;"}},
    97  			},
    98  			expVer: newVersion,
    99  		},
   100  		{
   101  			name: "schema changes write feature version",
   102  			setup: []fvCommand{
   103  				{OldClient, commands.SqlCmd{}, args{"-q", "CREATE TABLE test (pk int PRIMARY KEY);"}},
   104  				{NewClient, commands.SqlCmd{}, args{"-q", "ALTER TABLE test ADD COLUMN c0 int;"}},
   105  			},
   106  			expVer: newVersion,
   107  		},
   108  		{
   109  			name: "INSERT statements write feature version",
   110  			setup: []fvCommand{
   111  				{OldClient, commands.SqlCmd{}, args{"-q", "CREATE TABLE test (pk int PRIMARY KEY);"}},
   112  				{NewClient, commands.SqlCmd{}, args{"-q", "INSERT INTO test VALUES (0);"}},
   113  			},
   114  			expVer: newVersion,
   115  		},
   116  		{
   117  			name: "UPDATE statements write feature version",
   118  			setup: []fvCommand{
   119  				{OldClient, commands.SqlCmd{}, args{"-q", "CREATE TABLE test (pk int PRIMARY KEY);"}},
   120  				{OldClient, commands.SqlCmd{}, args{"-q", "INSERT INTO test VALUES (0);"}},
   121  				{NewClient, commands.SqlCmd{}, args{"-q", "UPDATE test SET pk = 1;"}},
   122  			},
   123  			expVer: newVersion,
   124  		},
   125  		{
   126  			name: "DELETE statements write feature version",
   127  			setup: []fvCommand{
   128  				{OldClient, commands.SqlCmd{}, args{"-q", "CREATE TABLE test (pk int PRIMARY KEY);"}},
   129  				{OldClient, commands.SqlCmd{}, args{"-q", "INSERT INTO test VALUES (0);"}},
   130  				{NewClient, commands.SqlCmd{}, args{"-q", "DELETE FROM test WHERE pk = 0;"}},
   131  			},
   132  			expVer: newVersion,
   133  		},
   134  		{
   135  			name: "new client writes to table, locking out old client",
   136  			setup: []fvCommand{
   137  				{OldClient, commands.SqlCmd{}, args{"-q", "CREATE TABLE test (pk int PRIMARY KEY);"}},
   138  				{OldClient, commands.SqlCmd{}, args{"-q", "INSERT INTO test VALUES (0);"}},
   139  				{NewClient, commands.SqlCmd{}, args{"-q", "INSERT INTO test VALUES (1);"}},
   140  			},
   141  			errCmds: []fvCommand{
   142  				// old client can't write
   143  				{OldClient, commands.SqlCmd{}, args{"-q", "INSERT INTO test VALUES (2);"}},
   144  				// old client can't read
   145  				{OldClient, commands.SqlCmd{}, args{"-q", "SELECT * FROM test;"}},
   146  			},
   147  			expVer: newVersion,
   148  		},
   149  	}
   150  
   151  	ctx := context.Background()
   152  	for _, test := range tests {
   153  		t.Run(test.name, func(t *testing.T) {
   154  
   155  			doltdb.DoltFeatureVersion = oldVersion
   156  			dEnv := dtestutils.CreateTestEnv()
   157  			defer dEnv.DoltDB.Close()
   158  			doltdb.DoltFeatureVersion = DoltFeatureVersionCopy
   159  
   160  			for _, cmd := range test.setup {
   161  				code := cmd.exec(ctx, dEnv)
   162  				require.Equal(t, 0, code)
   163  			}
   164  			for _, cmd := range test.errCmds {
   165  				code := cmd.exec(ctx, dEnv)
   166  				require.NotEqual(t, 0, code)
   167  			}
   168  
   169  			// execute assertions with newVersion to avoid OutOfDate errors
   170  			doltdb.DoltFeatureVersion = newVersion
   171  			defer func() { doltdb.DoltFeatureVersion = DoltFeatureVersionCopy }()
   172  
   173  			assertFeatureVersion := func(r doltdb.RootValue) {
   174  				act, ok, err := r.GetFeatureVersion(ctx)
   175  				require.NoError(t, err)
   176  				require.True(t, ok)
   177  				assert.Equal(t, test.expVer, act)
   178  			}
   179  
   180  			working, err := dEnv.WorkingRoot(ctx)
   181  			require.NoError(t, err)
   182  			assertFeatureVersion(working)
   183  		})
   184  
   185  		// ensure |doltdb.DoltFeatureVersion| was restored
   186  		assert.Equal(t, DoltFeatureVersionCopy, doltdb.DoltFeatureVersion)
   187  	}
   188  }