github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/ccl/importccl/client_import_test.go (about)

     1  // Copyright 2020 The Cockroach Authors.
     2  //
     3  // Licensed as a CockroachDB Enterprise file under the Cockroach Community
     4  // License (the "License"); you may not use this file except in compliance with
     5  // the License. You may obtain a copy of the License at
     6  //
     7  //     https://github.com/cockroachdb/cockroach/blob/master/licenses/CCL.txt
     8  
     9  package importccl_test
    10  
    11  import (
    12  	"context"
    13  	"net/http"
    14  	"net/http/httptest"
    15  	"sync"
    16  	"testing"
    17  
    18  	"github.com/cockroachdb/cockroach/pkg/base"
    19  	"github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgcode"
    20  	"github.com/cockroachdb/cockroach/pkg/testutils/sqlutils"
    21  	"github.com/cockroachdb/cockroach/pkg/testutils/testcluster"
    22  	"github.com/cockroachdb/cockroach/pkg/util/leaktest"
    23  	"github.com/cockroachdb/errors"
    24  	"github.com/lib/pq"
    25  	"github.com/stretchr/testify/require"
    26  )
    27  
    28  // TestDropDatabaseCascadeDuringImportsFails ensures that dropping a database
    29  // while an IMPORT is ongoing fails with an error. This is critical because
    30  // otherwise we may end up with orphaned table descriptors. See #48589 for
    31  // more details.
    32  func TestDropDatabaseCascadeDuringImportsFails(t *testing.T) {
    33  	defer leaktest.AfterTest(t)()
    34  
    35  	ctx, cancel := context.WithCancel(context.Background())
    36  	defer cancel()
    37  	args := base.TestClusterArgs{}
    38  	tc := testcluster.StartTestCluster(t, 1, args)
    39  	defer tc.Stopper().Stop(ctx)
    40  
    41  	tc.WaitForNodeLiveness(t)
    42  	require.NoError(t, tc.WaitForFullReplication())
    43  
    44  	db := tc.ServerConn(0)
    45  	runner := sqlutils.MakeSQLRunner(db)
    46  
    47  	// Use some names that need quoting to ensure that the error quoting is correct.
    48  	const dbName, tableName = `"fooBarBaz"`, `"foo bar"`
    49  	runner.Exec(t, `CREATE DATABASE `+dbName)
    50  
    51  	mkServer := func(method string, handler func(w http.ResponseWriter, r *http.Request)) *httptest.Server {
    52  		return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    53  			if r.Method == method {
    54  				handler(w, r)
    55  			}
    56  		}))
    57  	}
    58  
    59  	// Let's start an import into this table of ours.
    60  	allowResponse := make(chan struct{})
    61  	var gotRequestOnce sync.Once
    62  	gotRequest := make(chan struct{})
    63  	srv := mkServer("GET", func(w http.ResponseWriter, r *http.Request) {
    64  		gotRequestOnce.Do(func() { close(gotRequest) })
    65  		select {
    66  		case <-allowResponse:
    67  		case <-ctx.Done(): // Deal with test failures.
    68  		}
    69  		_, _ = w.Write([]byte("1,asdfasdfasdfasdf"))
    70  	})
    71  	defer srv.Close()
    72  
    73  	importErrCh := make(chan error, 1)
    74  	go func() {
    75  		_, err := db.Exec(`IMPORT TABLE `+dbName+"."+tableName+
    76  			` (k INT, v STRING) CSV DATA ($1)`, srv.URL)
    77  		importErrCh <- err
    78  	}()
    79  	select {
    80  	case <-gotRequest:
    81  	case err := <-importErrCh:
    82  		t.Fatalf("err %v", err)
    83  	}
    84  
    85  	_, err := db.Exec(`DROP DATABASE "fooBarBaz" CASCADE`)
    86  	require.Regexp(t, `cannot drop a database with OFFLINE tables, ensure `+
    87  		dbName+`\.public\.`+tableName+` is dropped or made public before dropping`+
    88  		` database `+dbName, err)
    89  	pgErr := new(pq.Error)
    90  	require.True(t, errors.As(err, &pgErr))
    91  	require.Equal(t, pgcode.ObjectNotInPrerequisiteState, string(pgErr.Code))
    92  
    93  	close(allowResponse)
    94  	require.NoError(t, <-importErrCh)
    95  	runner.Exec(t, `DROP DATABASE `+dbName+` CASCADE`)
    96  }