vitess.io/vitess@v0.16.2/go/test/endtoend/vtgate/transaction/rollback/txn_rollback_shutdown_test.go (about)

     1  /*
     2  Copyright 2019 The Vitess Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package rollback
    18  
    19  import (
    20  	"context"
    21  	"flag"
    22  	"fmt"
    23  	"os"
    24  	"testing"
    25  
    26  	"vitess.io/vitess/go/test/endtoend/utils"
    27  
    28  	"github.com/stretchr/testify/require"
    29  
    30  	"github.com/stretchr/testify/assert"
    31  
    32  	"vitess.io/vitess/go/mysql"
    33  	"vitess.io/vitess/go/test/endtoend/cluster"
    34  )
    35  
    36  var (
    37  	clusterInstance *cluster.LocalProcessCluster
    38  	vtParams        mysql.ConnParams
    39  	keyspaceName    = "ks"
    40  	cell            = "zone1"
    41  	hostname        = "localhost"
    42  	sqlSchema       = `
    43  	create table buffer(
    44  		id BIGINT NOT NULL,
    45  		msg VARCHAR(64) NOT NULL,
    46  		PRIMARY KEY (id)
    47  	) Engine=InnoDB;`
    48  )
    49  
    50  func TestMain(m *testing.M) {
    51  	defer cluster.PanicHandler(nil)
    52  	flag.Parse()
    53  
    54  	exitCode := func() int {
    55  		clusterInstance = cluster.NewCluster(cell, hostname)
    56  		defer clusterInstance.Teardown()
    57  
    58  		// Reserve vtGate port in order to pass it to vtTablet
    59  		clusterInstance.VtgateGrpcPort = clusterInstance.GetAndReservePort()
    60  
    61  		// Start topo server
    62  		err := clusterInstance.StartTopo()
    63  		if err != nil {
    64  			panic(err)
    65  		}
    66  
    67  		// Start keyspace
    68  		keyspace := &cluster.Keyspace{
    69  			Name:      keyspaceName,
    70  			SchemaSQL: sqlSchema,
    71  		}
    72  		err = clusterInstance.StartUnshardedKeyspace(*keyspace, 1, false)
    73  		if err != nil {
    74  			panic(err)
    75  		}
    76  
    77  		// Set a short onterm timeout so the test goes faster.
    78  		clusterInstance.VtGateExtraArgs = []string{"--onterm_timeout", "1s"}
    79  		err = clusterInstance.StartVtgate()
    80  		if err != nil {
    81  			panic(err)
    82  		}
    83  		vtParams = clusterInstance.GetVTParams(keyspaceName)
    84  		return m.Run()
    85  	}()
    86  	os.Exit(exitCode)
    87  }
    88  
    89  func TestTransactionRollBackWhenShutDown(t *testing.T) {
    90  	defer cluster.PanicHandler(t)
    91  	ctx := context.Background()
    92  	conn, err := mysql.Connect(ctx, &vtParams)
    93  	require.NoError(t, err)
    94  	defer conn.Close()
    95  
    96  	utils.Exec(t, conn, "insert into buffer(id, msg) values(3,'mark')")
    97  	utils.Exec(t, conn, "insert into buffer(id, msg) values(4,'doug')")
    98  
    99  	// start an incomplete transaction
   100  	utils.Exec(t, conn, "begin")
   101  	utils.Exec(t, conn, "insert into buffer(id, msg) values(33,'mark')")
   102  
   103  	// Enforce a restart to enforce rollback
   104  	if err = clusterInstance.RestartVtgate(); err != nil {
   105  		t.Errorf("Fail to re-start vtgate: %v", err)
   106  	}
   107  
   108  	want := ""
   109  
   110  	// Make a new mysql connection to vtGate
   111  	vtParams = clusterInstance.GetVTParams(keyspaceName)
   112  	conn2, err := mysql.Connect(ctx, &vtParams)
   113  	require.NoError(t, err)
   114  	defer conn2.Close()
   115  
   116  	vtParams = clusterInstance.GetVTParams(keyspaceName)
   117  	// Verify that rollback worked
   118  	qr := utils.Exec(t, conn2, "select id from buffer where msg='mark'")
   119  	got := fmt.Sprintf("%v", qr.Rows)
   120  	want = `[[INT64(3)]]`
   121  	assert.Equal(t, want, got)
   122  }
   123  
   124  func TestErrorInAutocommitSession(t *testing.T) {
   125  	defer cluster.PanicHandler(t)
   126  	ctx := context.Background()
   127  	conn, err := mysql.Connect(ctx, &vtParams)
   128  	require.NoError(t, err)
   129  	defer conn.Close()
   130  
   131  	utils.Exec(t, conn, "set autocommit=true")
   132  	utils.Exec(t, conn, "insert into buffer(id, msg) values(1,'foo')")
   133  	_, err = conn.ExecuteFetch("insert into buffer(id, msg) values(1,'bar')", 1, true)
   134  	require.Error(t, err) // this should fail with duplicate error
   135  	utils.Exec(t, conn, "insert into buffer(id, msg) values(2,'baz')")
   136  
   137  	conn2, err := mysql.Connect(ctx, &vtParams)
   138  	require.NoError(t, err)
   139  	defer conn2.Close()
   140  	result := utils.Exec(t, conn2, "select * from buffer order by id")
   141  
   142  	// if we have properly working autocommit code, both the successful inserts should be visible to a second
   143  	// connection, even if we have not done an explicit commit
   144  	assert.Equal(t, `[[INT64(1) VARCHAR("foo")] [INT64(2) VARCHAR("baz")] [INT64(3) VARCHAR("mark")] [INT64(4) VARCHAR("doug")]]`, fmt.Sprintf("%v", result.Rows))
   145  }