github.com/hasnat/dolt/go@v0.0.0-20210628190320-9eb5d843fbb7/libraries/doltcore/envtestutils/super_schema_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 envtestutils
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"testing"
    21  
    22  	"github.com/stretchr/testify/assert"
    23  	"github.com/stretchr/testify/require"
    24  
    25  	"github.com/dolthub/dolt/go/libraries/doltcore/dtestutils"
    26  	tc "github.com/dolthub/dolt/go/libraries/doltcore/dtestutils/testcommands"
    27  	"github.com/dolthub/dolt/go/libraries/doltcore/schema"
    28  	"github.com/dolthub/dolt/go/libraries/doltcore/schema/typeinfo"
    29  )
    30  
    31  const (
    32  	pkTag  = 16191
    33  	c0Tag  = 8734
    34  	c1Tag  = 15903
    35  	c11Tag = 15001
    36  )
    37  
    38  type SuperSchemaTest struct {
    39  	// The name of this test. Names should be unique and descriptive.
    40  	Name string
    41  	// Name of the table to be verified
    42  	TableName string
    43  	// The modifying queries to run
    44  	Commands []tc.Command
    45  	// Expected branch
    46  	ExpectedBranch string
    47  	// The schema of the result of the query, nil if an error is expected
    48  	ExpectedSchema schema.Schema
    49  	// The rows the select query should return, nil if an error is expected
    50  	ExpectedSuperSchema *schema.SuperSchema
    51  	// An expected error string
    52  	ExpectedErrStr string
    53  }
    54  
    55  var testableDef = fmt.Sprintf("create table testable (pk int not null primary key);")
    56  
    57  var SuperSchemaTests = []SuperSchemaTest{
    58  	{
    59  		Name:      "can create super schema",
    60  		TableName: "testable",
    61  		Commands: []tc.Command{
    62  			tc.Query{Query: testableDef},
    63  			tc.CommitAll{Message: "created table testable"},
    64  		},
    65  		ExpectedBranch: "master",
    66  		ExpectedSchema: schema.MustSchemaFromCols(columnCollection(
    67  			newColTypeInfo("pk", pkTag, typeinfo.Int32Type, true, schema.NotNullConstraint{}),
    68  		)),
    69  		ExpectedSuperSchema: superSchemaFromCols(columnCollection(
    70  			newColTypeInfo("pk", pkTag, typeinfo.Int32Type, true, schema.NotNullConstraint{}),
    71  		)),
    72  	},
    73  	{
    74  		Name:      "get super schema without commit",
    75  		TableName: "testable",
    76  		Commands: []tc.Command{
    77  			tc.Query{Query: testableDef},
    78  		},
    79  		ExpectedBranch: "master",
    80  		ExpectedSchema: schema.MustSchemaFromCols(columnCollection(
    81  			newColTypeInfo("pk", pkTag, typeinfo.Int32Type, true, schema.NotNullConstraint{}),
    82  		)),
    83  		ExpectedSuperSchema: superSchemaFromCols(columnCollection(
    84  			newColTypeInfo("pk", pkTag, typeinfo.Int32Type, true, schema.NotNullConstraint{}),
    85  		)),
    86  	},
    87  	{
    88  		Name:      "add column",
    89  		TableName: "testable",
    90  		Commands: []tc.Command{
    91  			tc.Query{Query: testableDef},
    92  			tc.CommitAll{Message: "created table testable"},
    93  			tc.Query{Query: fmt.Sprintf("alter table testable add column c0 int;")},
    94  		},
    95  		ExpectedBranch: "master",
    96  		ExpectedSchema: schema.MustSchemaFromCols(columnCollection(
    97  			newColTypeInfo("pk", pkTag, typeinfo.Int32Type, true, schema.NotNullConstraint{}),
    98  			newColTypeInfo("c0", c0Tag, typeinfo.Int32Type, false),
    99  		)),
   100  		ExpectedSuperSchema: superSchemaFromCols(columnCollection(
   101  			newColTypeInfo("pk", pkTag, typeinfo.Int32Type, true, schema.NotNullConstraint{}),
   102  			newColTypeInfo("c0", c0Tag, typeinfo.Int32Type, false),
   103  		)),
   104  	},
   105  	{
   106  		Name:      "drop column",
   107  		TableName: "testable",
   108  		Commands: []tc.Command{
   109  			tc.Query{Query: testableDef},
   110  			tc.Query{Query: fmt.Sprintf("alter table testable add column c0 int")},
   111  			tc.CommitAll{Message: "created table testable"},
   112  			tc.Query{Query: "alter table testable drop column c0"},
   113  			tc.CommitAll{Message: "dropped column c0"},
   114  		},
   115  		ExpectedBranch: "master",
   116  		ExpectedSchema: schema.MustSchemaFromCols(columnCollection(
   117  			newColTypeInfo("pk", pkTag, typeinfo.Int32Type, true, schema.NotNullConstraint{}),
   118  		)),
   119  		ExpectedSuperSchema: superSchemaFromCols(columnCollection(
   120  			newColTypeInfo("pk", pkTag, typeinfo.Int32Type, true, schema.NotNullConstraint{}),
   121  			newColTypeInfo("c0", c0Tag, typeinfo.Int32Type, false),
   122  		)),
   123  	},
   124  	{
   125  		Name:      "modify column",
   126  		TableName: "testable",
   127  		Commands: []tc.Command{
   128  			tc.Query{Query: testableDef},
   129  			tc.Query{Query: fmt.Sprintf("alter table testable add column c0 int;")},
   130  			tc.CommitAll{Message: "created table testable"},
   131  			tc.Query{Query: "alter table testable drop column c0"},
   132  		},
   133  		ExpectedBranch: "master",
   134  		ExpectedSchema: schema.MustSchemaFromCols(columnCollection(
   135  			newColTypeInfo("pk", pkTag, typeinfo.Int32Type, true, schema.NotNullConstraint{}),
   136  		)),
   137  		ExpectedSuperSchema: superSchemaFromCols(columnCollection(
   138  			newColTypeInfo("pk", pkTag, typeinfo.Int32Type, true, schema.NotNullConstraint{}),
   139  			newColTypeInfo("c0", c0Tag, typeinfo.Int32Type, false),
   140  		)),
   141  	},
   142  	{
   143  		Name:      "drop column from working set",
   144  		TableName: "testable",
   145  		Commands: []tc.Command{
   146  			tc.Query{Query: testableDef},
   147  			tc.Query{Query: fmt.Sprintf("alter table testable add column c0 int;")},
   148  			tc.Query{Query: "alter table testable drop column c0"},
   149  		},
   150  		ExpectedBranch: "master",
   151  		ExpectedSchema: schema.MustSchemaFromCols(columnCollection(
   152  			newColTypeInfo("pk", pkTag, typeinfo.Int32Type, true, schema.NotNullConstraint{}),
   153  		)),
   154  		ExpectedSuperSchema: superSchemaFromCols(columnCollection(
   155  			newColTypeInfo("pk", pkTag, typeinfo.Int32Type, true, schema.NotNullConstraint{}),
   156  		)),
   157  	},
   158  	{
   159  		Name:      "staged column persisted on commit, not working column",
   160  		TableName: "testable",
   161  		Commands: []tc.Command{
   162  			tc.Query{Query: testableDef},
   163  			tc.CommitAll{Message: "created table testable"},
   164  			tc.Query{Query: fmt.Sprintf("alter table testable add column c0 int;")},
   165  			tc.StageAll{},
   166  			tc.Query{Query: fmt.Sprintf("alter table testable add column c1 int;")},
   167  			tc.CommitStaged{Message: "adding staged column c0"},
   168  			tc.ResetHard{},
   169  		},
   170  		ExpectedBranch: "master",
   171  		ExpectedSchema: schema.MustSchemaFromCols(columnCollection(
   172  			newColTypeInfo("pk", pkTag, typeinfo.Int32Type, true, schema.NotNullConstraint{}),
   173  			newColTypeInfo("c0", c0Tag, typeinfo.Int32Type, false),
   174  		)),
   175  		ExpectedSuperSchema: superSchemaFromCols(columnCollection(
   176  			newColTypeInfo("pk", pkTag, typeinfo.Int32Type, true, schema.NotNullConstraint{}),
   177  			newColTypeInfo("c0", c0Tag, typeinfo.Int32Type, false),
   178  		)),
   179  	},
   180  	{
   181  		Name:      "super schema on branch master",
   182  		TableName: "testable",
   183  		Commands: []tc.Command{
   184  			tc.Query{Query: testableDef},
   185  			tc.Query{Query: fmt.Sprintf("alter table testable add column c0 int;")},
   186  			tc.CommitAll{Message: "created table testable"},
   187  			tc.Branch{BranchName: "other"},
   188  			tc.Checkout{BranchName: "other"},
   189  			tc.Query{Query: fmt.Sprintf("alter table testable add column c11 int;")},
   190  			tc.CommitAll{Message: "added column c11 on branch other"},
   191  			tc.Checkout{BranchName: "master"},
   192  			tc.Query{Query: fmt.Sprintf("alter table testable add column c1 int;")},
   193  		},
   194  		ExpectedBranch: "master",
   195  		ExpectedSchema: schema.MustSchemaFromCols(columnCollection(
   196  			newColTypeInfo("pk", pkTag, typeinfo.Int32Type, true, schema.NotNullConstraint{}),
   197  			newColTypeInfo("c0", c0Tag, typeinfo.Int32Type, false),
   198  			newColTypeInfo("c1", c1Tag, typeinfo.Int32Type, false),
   199  		)),
   200  		ExpectedSuperSchema: superSchemaFromCols(columnCollection(
   201  			newColTypeInfo("pk", pkTag, typeinfo.Int32Type, true, schema.NotNullConstraint{}),
   202  			newColTypeInfo("c0", c0Tag, typeinfo.Int32Type, false),
   203  			newColTypeInfo("c1", c1Tag, typeinfo.Int32Type, false),
   204  		)),
   205  	},
   206  	{
   207  		Name:      "super schema on branch other",
   208  		TableName: "testable",
   209  		Commands: []tc.Command{
   210  			tc.Query{Query: testableDef},
   211  			tc.Query{Query: fmt.Sprintf("alter table testable add column c0 int;")},
   212  			tc.CommitAll{Message: "created table testable"},
   213  			tc.Branch{BranchName: "other"},
   214  			tc.Checkout{BranchName: "other"},
   215  			tc.Query{Query: fmt.Sprintf("alter table testable add column c11 int;")},
   216  			tc.CommitAll{Message: "added column c11 on branch other"},
   217  			tc.Checkout{BranchName: "master"},
   218  			tc.Query{Query: fmt.Sprintf("alter table testable add column c1 int;")},
   219  			tc.CommitAll{Message: "added column c1 on branch master"},
   220  			tc.Checkout{BranchName: "other"},
   221  		},
   222  		ExpectedBranch: "other",
   223  		ExpectedSchema: schema.MustSchemaFromCols(columnCollection(
   224  			newColTypeInfo("pk", pkTag, typeinfo.Int32Type, true, schema.NotNullConstraint{}),
   225  			newColTypeInfo("c0", c0Tag, typeinfo.Int32Type, false),
   226  			newColTypeInfo("c11", c11Tag, typeinfo.Int32Type, false),
   227  		)),
   228  		ExpectedSuperSchema: superSchemaFromCols(columnCollection(
   229  			newColTypeInfo("pk", pkTag, typeinfo.Int32Type, true, schema.NotNullConstraint{}),
   230  			newColTypeInfo("c0", c0Tag, typeinfo.Int32Type, false),
   231  			newColTypeInfo("c11", c11Tag, typeinfo.Int32Type, false),
   232  		)),
   233  	},
   234  	// https://github.com/dolthub/dolt/issues/773
   235  	/*{
   236  		Name:      "super schema merge",
   237  		TableName: "testable",
   238  		Commands: []tc.Command{
   239  			tc.Query{Query: testableDef},
   240  			tc.Query{Query: fmt.Sprintf("alter table testable add column c0 int;")},
   241  			tc.CommitAll{Message: "created table testable"},
   242  			tc.Branch{BranchName: "other"},
   243  			tc.Checkout{BranchName: "other"},
   244  			tc.Query{Query: fmt.Sprintf("alter table testable add column c11 int;")},
   245  			tc.CommitAll{Message: "added column c11 on branch other"},
   246  			tc.Checkout{BranchName: "master"},
   247  			tc.Query{Query: fmt.Sprintf("alter table testable add column c1 int;")},
   248  			tc.CommitAll{Message: "added column c1 on branch master"},
   249  			tc.Merge{BranchName: "other"},
   250  		},
   251  		ExpectedBranch: "master",
   252  		ExpectedSchema: schema.MustSchemaFromCols(columnCollection(
   253  			newColTypeInfo("pk", pkTag, typeinfo.Int32Type, true, schema.NotNullConstraint{}),
   254  			newColTypeInfo("c0", c0Tag, typeinfo.Int32Type, false),
   255  			newColTypeInfo("c1", c1Tag, typeinfo.Int32Type, false),
   256  			newColTypeInfo("c11", c11Tag, typeinfo.Int32Type, false),
   257  		)),
   258  		ExpectedSuperSchema: superSchemaFromCols(columnCollection(
   259  			newColTypeInfo("pk", pkTag, typeinfo.Int32Type, true, schema.NotNullConstraint{}),
   260  			newColTypeInfo("c0", c0Tag, typeinfo.Int32Type, false),
   261  			newColTypeInfo("c1", c1Tag, typeinfo.Int32Type, false),
   262  			newColTypeInfo("c11", c11Tag, typeinfo.Int32Type, false),
   263  		)),
   264  	},
   265  	{
   266  		Name:      "super schema merge with drops",
   267  		TableName: "testable",
   268  		Commands: []tc.Command{
   269  			tc.Query{Query: testableDef},
   270  			tc.Query{Query: fmt.Sprintf("alter table testable add column c0 int;")},
   271  			tc.CommitAll{Message: "created table testable"},
   272  			tc.Branch{BranchName: "other"},
   273  			tc.Checkout{BranchName: "other"},
   274  			tc.Query{Query: fmt.Sprintf("alter table testable add column c11 int;")},
   275  			tc.Query{Query: fmt.Sprintf("alter table testable add column c12 int;")},
   276  			tc.CommitAll{Message: "added columns c11 and c12 on branch other"},
   277  			tc.Query{Query: "alter table testable drop column c12;"},
   278  			tc.CommitAll{Message: "dropped column c12 on branch other"},
   279  			tc.Checkout{BranchName: "master"},
   280  			tc.Query{Query: fmt.Sprintf("alter table testable add column c1 int;")},
   281  			tc.CommitAll{Message: "added column c1 on branch master"},
   282  			tc.Merge{BranchName: "other"},
   283  			tc.CommitAll{Message: "Merged other into master"},
   284  		},
   285  		ExpectedBranch: "master",
   286  		ExpectedSchema: schema.MustSchemaFromCols(columnCollection(
   287  			newColTypeInfo("pk", pkTag, typeinfo.Int32Type, true, schema.NotNullConstraint{}),
   288  			newColTypeInfo("c0", c0Tag, typeinfo.Int32Type, false),
   289  			newColTypeInfo("c1", c1Tag, typeinfo.Int32Type, false),
   290  			newColTypeInfo("c11", c11Tag, typeinfo.Int32Type, false),
   291  		)),
   292  		ExpectedSuperSchema: superSchemaFromCols(columnCollection(
   293  			newColTypeInfo("pk", pkTag, typeinfo.Int32Type, true, schema.NotNullConstraint{}),
   294  			newColTypeInfo("c0", c0Tag, typeinfo.Int32Type, false),
   295  			newColTypeInfo("c1", c1Tag, typeinfo.Int32Type, false),
   296  			newColTypeInfo("c11", c11Tag, typeinfo.Int32Type, false),
   297  			newColTypeInfo("c12", c12Tag, typeinfo.Int32Type, false),
   298  		)),
   299  	},*/
   300  	{
   301  		Name:      "super schema with table add/drops",
   302  		TableName: "testable",
   303  		Commands: []tc.Command{
   304  			tc.Query{Query: testableDef},
   305  			tc.Query{Query: fmt.Sprintf("alter table testable add column c0 int;")},
   306  			tc.Query{Query: "create table foo (pk int not null primary key);"},
   307  			tc.CommitAll{Message: "created tables testable and foo"},
   308  			tc.Query{Query: fmt.Sprintf("alter table testable add column c1 int;")},
   309  			tc.Query{Query: "create table qux (pk int not null primary key);"},
   310  			tc.Query{Query: "drop table foo;"},
   311  			tc.CommitAll{Message: "added column c1 on branch master, created table qux, dropped table foo"},
   312  		},
   313  		ExpectedBranch: "master",
   314  		ExpectedSchema: schema.MustSchemaFromCols(columnCollection(
   315  			newColTypeInfo("pk", pkTag, typeinfo.Int32Type, true, schema.NotNullConstraint{}),
   316  			newColTypeInfo("c0", c0Tag, typeinfo.Int32Type, false),
   317  			newColTypeInfo("c1", c1Tag, typeinfo.Int32Type, false),
   318  		)),
   319  		ExpectedSuperSchema: superSchemaFromCols(columnCollection(
   320  			newColTypeInfo("pk", pkTag, typeinfo.Int32Type, true, schema.NotNullConstraint{}),
   321  			newColTypeInfo("c0", c0Tag, typeinfo.Int32Type, false),
   322  			newColTypeInfo("c1", c1Tag, typeinfo.Int32Type, false),
   323  		)),
   324  	},
   325  	{
   326  		// This test corresponds to @test "diff sql reconciles DROP TABLE" in sql_diff.bats
   327  		Name:      "sql diff bats test",
   328  		TableName: "testable",
   329  		Commands: []tc.Command{
   330  			tc.Branch{BranchName: "first"},
   331  			tc.Checkout{BranchName: "first"},
   332  			tc.Query{Query: testableDef},
   333  			tc.Query{Query: "insert into testable values (1);"},
   334  			tc.CommitAll{Message: "setup table"},
   335  			tc.Branch{BranchName: "other"},
   336  			tc.Checkout{BranchName: "other"},
   337  			tc.Query{Query: "drop table testable;"},
   338  			tc.CommitAll{Message: "removed table"},
   339  			tc.Checkout{BranchName: "first"},
   340  		},
   341  		ExpectedBranch: "first",
   342  		ExpectedSchema: schema.MustSchemaFromCols(columnCollection(
   343  			newColTypeInfo("pk", pkTag, typeinfo.Int32Type, true, schema.NotNullConstraint{}),
   344  		)),
   345  		ExpectedSuperSchema: superSchemaFromCols(columnCollection(
   346  			newColTypeInfo("pk", pkTag, typeinfo.Int32Type, true, schema.NotNullConstraint{}),
   347  		)),
   348  	},
   349  }
   350  
   351  func TestSuperSchema(t *testing.T) {
   352  	for _, test := range SuperSchemaTests {
   353  		t.Run(test.Name, func(t *testing.T) {
   354  			testSuperSchema(t, test)
   355  		})
   356  	}
   357  }
   358  
   359  func testSuperSchema(t *testing.T, test SuperSchemaTest) {
   360  	dEnv := dtestutils.CreateTestEnv()
   361  
   362  	var ee error
   363  	for idx, cmd := range test.Commands {
   364  		require.NoError(t, ee)
   365  		fmt.Println(fmt.Sprintf("%d: %s: %s", idx, cmd.CommandString(), cmd))
   366  		ee = cmd.Exec(t, dEnv)
   367  	}
   368  
   369  	if test.ExpectedErrStr != "" {
   370  		require.Error(t, ee, test.ExpectedErrStr)
   371  	} else {
   372  		spec := dEnv.RepoState.CWBHeadRef()
   373  		require.Equal(t, "refs/heads/"+test.ExpectedBranch, spec.String())
   374  
   375  		r, err := dEnv.WorkingRoot(context.Background())
   376  		require.NoError(t, err)
   377  
   378  		tbl, ok, err := r.GetTable(context.Background(), test.TableName)
   379  		require.NoError(t, err)
   380  		require.True(t, ok)
   381  
   382  		ss, found, err := r.GetSuperSchema(context.Background(), test.TableName)
   383  		require.True(t, found)
   384  		require.NoError(t, err)
   385  		assert.Equal(t, test.ExpectedSuperSchema, ss)
   386  
   387  		sch, err := tbl.GetSchema(context.Background())
   388  		require.NoError(t, err)
   389  		assert.Equal(t, test.ExpectedSchema, sch)
   390  	}
   391  }
   392  
   393  func superSchemaFromCols(cols *schema.ColCollection) *schema.SuperSchema {
   394  	sch := schema.MustSchemaFromCols(cols)
   395  	ss, _ := schema.NewSuperSchema(sch)
   396  	return ss
   397  }