github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/copy_file_upload_test.go (about)

     1  // Copyright 2019 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  package sql
    12  
    13  import (
    14  	"bytes"
    15  	"context"
    16  	gosql "database/sql"
    17  	"io"
    18  	"io/ioutil"
    19  	"net/url"
    20  	"os"
    21  	"path/filepath"
    22  	"testing"
    23  
    24  	"github.com/cockroachdb/cockroach/pkg/sql/tests"
    25  	"github.com/cockroachdb/cockroach/pkg/testutils"
    26  	"github.com/cockroachdb/cockroach/pkg/testutils/serverutils"
    27  	"github.com/cockroachdb/cockroach/pkg/testutils/sqlutils"
    28  	"github.com/cockroachdb/cockroach/pkg/util/leaktest"
    29  	"github.com/stretchr/testify/require"
    30  )
    31  
    32  const filename = "/test/test_file_upload.csv"
    33  
    34  func writeFile(t *testing.T, testSendFile string, fileContent []byte) {
    35  	err := os.MkdirAll(filepath.Dir(testSendFile), 0755)
    36  	if err != nil {
    37  		t.Fatal(err)
    38  	}
    39  	err = ioutil.WriteFile(testSendFile, fileContent, 0644)
    40  	if err != nil {
    41  		t.Fatal(err)
    42  	}
    43  }
    44  
    45  func runCopyFile(t *testing.T, db *gosql.DB, testSendFile string) error {
    46  	// Make sure we can open this file first
    47  	reader, err := os.Open(testSendFile)
    48  	if err != nil {
    49  		return err
    50  	}
    51  
    52  	txn, err := db.Begin()
    53  	if err != nil {
    54  		t.Fatal(err)
    55  	}
    56  	defer func() {
    57  		if newErr := txn.Commit(); err == nil && newErr != nil {
    58  			t.Fatal(newErr)
    59  		}
    60  	}()
    61  
    62  	stmt, err := txn.Prepare(CopyInFileStmt(filename, crdbInternalName, fileUploadTable))
    63  	if err != nil {
    64  		return err
    65  	}
    66  
    67  	for {
    68  		send := make([]byte, 1024)
    69  		n, err := reader.Read(send)
    70  		if err == io.EOF {
    71  			break
    72  		}
    73  		if err != nil {
    74  			t.Fatal(err)
    75  		}
    76  		_, err = stmt.Exec(string(send[:n]))
    77  		if err != nil {
    78  			t.Fatal(err)
    79  		}
    80  	}
    81  
    82  	err = stmt.Close()
    83  	if err != nil {
    84  		t.Fatal(err)
    85  	}
    86  	return nil
    87  }
    88  
    89  func TestFileUpload(t *testing.T) {
    90  	defer leaktest.AfterTest(t)()
    91  
    92  	params, _ := tests.CreateTestServerParams()
    93  	localExternalDir, cleanup := testutils.TempDir(t)
    94  	defer cleanup()
    95  	params.ExternalIODir = localExternalDir
    96  
    97  	s, db, _ := serverutils.StartServer(t, params)
    98  	defer s.Stopper().Stop(context.Background())
    99  
   100  	testFileDir, cleanup2 := testutils.TempDir(t)
   101  	defer cleanup2()
   102  	testSendFile := filepath.Join(testFileDir, filename)
   103  	fileContent := []byte("hello \n blah 1@#% some data hello \n @#%^&&*")
   104  	writeFile(t, testSendFile, fileContent)
   105  
   106  	err := runCopyFile(t, db, testSendFile)
   107  	if err != nil {
   108  		t.Fatal(err)
   109  	}
   110  
   111  	content, err := ioutil.ReadFile(filepath.Join(localExternalDir, filename))
   112  	if err != nil {
   113  		t.Fatal(err)
   114  	}
   115  	if !bytes.Equal(fileContent, content) {
   116  		t.Fatalf("content not the same. expected: %s got: %s", fileContent, content)
   117  	}
   118  }
   119  
   120  func TestUploadEmptyFile(t *testing.T) {
   121  	defer leaktest.AfterTest(t)()
   122  
   123  	params, _ := tests.CreateTestServerParams()
   124  	localExternalDir, cleanup := testutils.TempDir(t)
   125  	defer cleanup()
   126  	params.ExternalIODir = localExternalDir
   127  	s, db, _ := serverutils.StartServer(t, params)
   128  	defer s.Stopper().Stop(context.Background())
   129  
   130  	testFileDir, cleanup2 := testutils.TempDir(t)
   131  	defer cleanup2()
   132  	testSendFile := filepath.Join(testFileDir, filename)
   133  	fileContent := []byte("")
   134  	writeFile(t, testSendFile, fileContent)
   135  
   136  	err := runCopyFile(t, db, testSendFile)
   137  	if err != nil {
   138  		t.Fatal(err)
   139  	}
   140  
   141  	content, err := ioutil.ReadFile(filepath.Join(localExternalDir, filename))
   142  	if err != nil {
   143  		t.Fatal(err)
   144  	}
   145  	if !bytes.Equal(fileContent, content) {
   146  		t.Fatalf("content not the same. expected: %s got: %s", fileContent, content)
   147  	}
   148  }
   149  
   150  func TestFileNotExist(t *testing.T) {
   151  	defer leaktest.AfterTest(t)()
   152  
   153  	params, _ := tests.CreateTestServerParams()
   154  	localExternalDir, cleanup := testutils.TempDir(t)
   155  	defer cleanup()
   156  	params.ExternalIODir = localExternalDir
   157  	s, db, _ := serverutils.StartServer(t, params)
   158  	defer s.Stopper().Stop(context.Background())
   159  
   160  	err := runCopyFile(t, db, filepath.Join(localExternalDir, filename))
   161  	expectedErr := "no such file"
   162  	if !testutils.IsError(err, expectedErr) {
   163  		t.Fatalf(`expected error: %s, got: %s`, expectedErr, err)
   164  	}
   165  }
   166  
   167  func TestFileExist(t *testing.T) {
   168  	defer leaktest.AfterTest(t)()
   169  
   170  	params, _ := tests.CreateTestServerParams()
   171  	localExternalDir, cleanup := testutils.TempDir(t)
   172  	defer cleanup()
   173  	params.ExternalIODir = localExternalDir
   174  	s, db, _ := serverutils.StartServer(t, params)
   175  	defer s.Stopper().Stop(context.Background())
   176  
   177  	destination := filepath.Join(localExternalDir, filename)
   178  	writeFile(t, destination, []byte("file exists"))
   179  
   180  	err := runCopyFile(t, db, destination)
   181  	expectedErr := "file already exists"
   182  	if !testutils.IsError(err, expectedErr) {
   183  		t.Fatalf(`expected error: %s, got: %s`, expectedErr, err)
   184  	}
   185  }
   186  
   187  func TestNotAdmin(t *testing.T) {
   188  	defer leaktest.AfterTest(t)()
   189  
   190  	params, _ := tests.CreateTestServerParams()
   191  	localExternalDir, cleanup := testutils.TempDir(t)
   192  	defer cleanup()
   193  	params.ExternalIODir = localExternalDir
   194  	params.Insecure = true
   195  	s, rootDB, _ := serverutils.StartServer(t, params)
   196  	defer s.Stopper().Stop(context.Background())
   197  
   198  	_, err := rootDB.Exec("CREATE USER jsmith")
   199  	require.NoError(t, err)
   200  
   201  	pgURL, cleanupGoDB := sqlutils.PGUrlWithOptionalClientCerts(
   202  		t, s.ServingSQLAddr(), "notAdmin", url.User("jsmith"), false, /* withCerts */
   203  	)
   204  	defer cleanupGoDB()
   205  	pgURL.RawQuery = "sslmode=disable"
   206  	userDB, err := gosql.Open("postgres", pgURL.String())
   207  	require.NoError(t, err)
   208  	defer userDB.Close()
   209  
   210  	testFileDir, cleanup2 := testutils.TempDir(t)
   211  	defer cleanup2()
   212  	testSendFile := filepath.Join(testFileDir, filename)
   213  	fileContent := []byte("hello \n blah 1@#% some data hello \n @#%^&&*")
   214  	writeFile(t, testSendFile, fileContent)
   215  
   216  	err = runCopyFile(t, userDB, testSendFile)
   217  	expectedErr := "only users with the admin role are allowed to upload"
   218  	if !testutils.IsError(err, expectedErr) {
   219  		t.Fatalf(`expected error: %s, got: %s`, expectedErr, err)
   220  	}
   221  }