github.com/pachyderm/pachyderm@v1.13.4/src/server/pfs/s3/master_test.go (about)

     1  package s3
     2  
     3  import (
     4  	"crypto/rand"
     5  	"fmt"
     6  	"io"
     7  	"io/ioutil"
     8  	"os"
     9  	"strings"
    10  	"testing"
    11  	"time"
    12  
    13  	minio "github.com/minio/minio-go/v6"
    14  	"github.com/pachyderm/pachyderm/src/client"
    15  	"github.com/pachyderm/pachyderm/src/client/pkg/errors"
    16  	"github.com/pachyderm/pachyderm/src/client/pkg/require"
    17  	tu "github.com/pachyderm/pachyderm/src/server/pkg/testutil"
    18  )
    19  
    20  func masterListBuckets(t *testing.T, pachClient *client.APIClient, minioClient *minio.Client) {
    21  	// `startTime` and `endTime` will be used to ensure that an object's
    22  	// `LastModified` date is correct. A few minutes are subtracted/added to
    23  	// each to tolerate the node time not being the same as the host time.
    24  	startTime := time.Now().Add(time.Duration(-5) * time.Minute)
    25  	repo := tu.UniqueString("testlistbuckets1")
    26  	require.NoError(t, pachClient.CreateRepo(repo))
    27  	endTime := time.Now().Add(time.Duration(5) * time.Minute)
    28  
    29  	require.NoError(t, pachClient.CreateBranch(repo, "master", "", nil))
    30  	require.NoError(t, pachClient.CreateBranch(repo, "branch", "", nil))
    31  
    32  	hasMaster := false
    33  	hasBranch := false
    34  
    35  	buckets, err := minioClient.ListBuckets()
    36  	require.NoError(t, err)
    37  
    38  	for _, bucket := range buckets {
    39  		if bucket.Name == fmt.Sprintf("master.%s", repo) {
    40  			hasMaster = true
    41  			require.True(t, startTime.Before(bucket.CreationDate))
    42  			require.True(t, endTime.After(bucket.CreationDate))
    43  		} else if bucket.Name == fmt.Sprintf("branch.%s", repo) {
    44  			hasBranch = true
    45  			require.True(t, startTime.Before(bucket.CreationDate))
    46  			require.True(t, endTime.After(bucket.CreationDate))
    47  		}
    48  	}
    49  
    50  	require.True(t, hasMaster)
    51  	require.True(t, hasBranch)
    52  }
    53  
    54  func masterListBucketsBranchless(t *testing.T, pachClient *client.APIClient, minioClient *minio.Client) {
    55  	repo1 := tu.UniqueString("testlistbucketsbranchless1")
    56  	require.NoError(t, pachClient.CreateRepo(repo1))
    57  	repo2 := tu.UniqueString("testlistbucketsbranchless2")
    58  	require.NoError(t, pachClient.CreateRepo(repo2))
    59  
    60  	// should be 0 since no branches have been made yet
    61  	buckets, err := minioClient.ListBuckets()
    62  	require.NoError(t, err)
    63  	for _, bucket := range buckets {
    64  		require.NotEqual(t, bucket.Name, repo1)
    65  		require.NotEqual(t, bucket.Name, repo2)
    66  	}
    67  }
    68  
    69  func masterGetObject(t *testing.T, pachClient *client.APIClient, minioClient *minio.Client) {
    70  	repo := tu.UniqueString("testgetobject")
    71  	require.NoError(t, pachClient.CreateRepo(repo))
    72  	_, err := pachClient.PutFile(repo, "master", "file", strings.NewReader("content"))
    73  	require.NoError(t, err)
    74  
    75  	fetchedContent, err := getObject(t, minioClient, fmt.Sprintf("master.%s", repo), "file")
    76  	require.NoError(t, err)
    77  	require.Equal(t, "content", fetchedContent)
    78  }
    79  
    80  func masterGetObjectInBranch(t *testing.T, pachClient *client.APIClient, minioClient *minio.Client) {
    81  	repo := tu.UniqueString("testgetobjectinbranch")
    82  	require.NoError(t, pachClient.CreateRepo(repo))
    83  	require.NoError(t, pachClient.CreateBranch(repo, "branch", "", nil))
    84  	_, err := pachClient.PutFile(repo, "branch", "file", strings.NewReader("content"))
    85  	require.NoError(t, err)
    86  
    87  	fetchedContent, err := getObject(t, minioClient, fmt.Sprintf("branch.%s", repo), "file")
    88  	require.NoError(t, err)
    89  	require.Equal(t, "content", fetchedContent)
    90  }
    91  
    92  func masterStatObject(t *testing.T, pachClient *client.APIClient, minioClient *minio.Client) {
    93  	repo := tu.UniqueString("teststatobject")
    94  	require.NoError(t, pachClient.CreateRepo(repo))
    95  	_, err := pachClient.PutFile(repo, "master", "file", strings.NewReader("content"))
    96  	require.NoError(t, err)
    97  
    98  	// `startTime` and `endTime` will be used to ensure that an object's
    99  	// `LastModified` date is correct. A few minutes are subtracted/added to
   100  	// each to tolerate the node time not being the same as the host time.
   101  	startTime := time.Now().Add(time.Duration(-5) * time.Minute)
   102  	_, err = pachClient.PutFileOverwrite(repo, "master", "file", strings.NewReader("new-content"), 0)
   103  	require.NoError(t, err)
   104  	endTime := time.Now().Add(time.Duration(5) * time.Minute)
   105  
   106  	info, err := minioClient.StatObject(fmt.Sprintf("master.%s", repo), "file", minio.StatObjectOptions{})
   107  	require.NoError(t, err)
   108  	require.True(t, startTime.Before(info.LastModified))
   109  	require.True(t, endTime.After(info.LastModified))
   110  	require.True(t, len(info.ETag) > 0)
   111  	require.Equal(t, "text/plain; charset=utf-8", info.ContentType)
   112  	require.Equal(t, int64(11), info.Size)
   113  }
   114  
   115  func masterPutObject(t *testing.T, pachClient *client.APIClient, minioClient *minio.Client) {
   116  	repo := tu.UniqueString("testputobject")
   117  	require.NoError(t, pachClient.CreateRepo(repo))
   118  	require.NoError(t, pachClient.CreateBranch(repo, "branch", "", nil))
   119  
   120  	r := strings.NewReader("content1")
   121  	_, err := minioClient.PutObject(fmt.Sprintf("branch.%s", repo), "file", r, int64(r.Len()), minio.PutObjectOptions{ContentType: "text/plain"})
   122  	require.NoError(t, err)
   123  
   124  	// this should act as a PFS PutFileOverwrite
   125  	r2 := strings.NewReader("content2")
   126  	_, err = minioClient.PutObject(fmt.Sprintf("branch.%s", repo), "file", r2, int64(r2.Len()), minio.PutObjectOptions{ContentType: "text/plain"})
   127  	require.NoError(t, err)
   128  
   129  	fetchedContent, err := getObject(t, minioClient, fmt.Sprintf("branch.%s", repo), "file")
   130  	require.NoError(t, err)
   131  	require.Equal(t, "content2", fetchedContent)
   132  }
   133  
   134  func masterPutObjectLarge(t *testing.T, pachClient *client.APIClient, minioClient *minio.Client) {
   135  	repo := tu.UniqueString("testputlargeobject")
   136  	require.NoError(t, pachClient.CreateRepo(repo))
   137  	require.NoError(t, pachClient.CreateBranch(repo, "branch", "", nil))
   138  
   139  	const size = 3e9
   140  	r := io.LimitReader(rand.Reader, size)
   141  	_, err := minioClient.PutObject(fmt.Sprintf("branch.%s", repo), "file", r, int64(size), minio.PutObjectOptions{ContentType: "text/plain", DisableMultipart: true})
   142  	require.NoError(t, err)
   143  }
   144  
   145  func masterRemoveObject(t *testing.T, pachClient *client.APIClient, minioClient *minio.Client) {
   146  	repo := tu.UniqueString("testremoveobject")
   147  	require.NoError(t, pachClient.CreateRepo(repo))
   148  	_, err := pachClient.PutFile(repo, "master", "file", strings.NewReader("content"))
   149  	require.NoError(t, err)
   150  
   151  	// as per PFS semantics, the second delete should be a no-op
   152  	require.NoError(t, minioClient.RemoveObject(fmt.Sprintf("master.%s", repo), "file"))
   153  	require.NoError(t, minioClient.RemoveObject(fmt.Sprintf("master.%s", repo), "file"))
   154  
   155  	// make sure the object no longer exists
   156  	_, err = getObject(t, minioClient, fmt.Sprintf("master.%s", repo), "file")
   157  	keyNotFoundError(t, err)
   158  }
   159  
   160  // Tests inserting and getting files over 64mb in size
   161  func masterLargeObjects(t *testing.T, pachClient *client.APIClient, minioClient *minio.Client) {
   162  	// test repos: repo1 exists, repo2 does not
   163  	repo1 := tu.UniqueString("testlargeobject1")
   164  	repo2 := tu.UniqueString("testlargeobject2")
   165  	require.NoError(t, pachClient.CreateRepo(repo1))
   166  	require.NoError(t, pachClient.CreateBranch(repo1, "master", "", nil))
   167  
   168  	// create a temporary file to put ~65mb of contents into it
   169  	inputFile, err := ioutil.TempFile("", "pachyderm-test-large-objects-input-*")
   170  	require.NoError(t, err)
   171  	defer os.Remove(inputFile.Name())
   172  	n, err := inputFile.WriteString(strings.Repeat("no tv and no beer make homer something something.\n", 1363149))
   173  	require.NoError(t, err)
   174  	require.Equal(t, n, 68157450)
   175  	require.NoError(t, inputFile.Sync())
   176  
   177  	// first ensure that putting into a repo that doesn't exist triggers an
   178  	// error
   179  	_, err = minioClient.FPutObject(fmt.Sprintf("master.%s", repo2), "file", inputFile.Name(), minio.PutObjectOptions{
   180  		ContentType: "text/plain",
   181  	})
   182  	bucketNotFoundError(t, err)
   183  
   184  	// now try putting into a legit repo
   185  	l, err := minioClient.FPutObject(fmt.Sprintf("master.%s", repo1), "file", inputFile.Name(), minio.PutObjectOptions{
   186  		ContentType: "text/plain",
   187  	})
   188  	require.NoError(t, err)
   189  	require.Equal(t, int(l), 68157450)
   190  
   191  	// try getting an object that does not exist
   192  	err = minioClient.FGetObject(fmt.Sprintf("master.%s", repo2), "file", "foo", minio.GetObjectOptions{})
   193  	bucketNotFoundError(t, err)
   194  
   195  	// get the file that does exist
   196  	outputFile, err := ioutil.TempFile("", "pachyderm-test-large-objects-output-*")
   197  	require.NoError(t, err)
   198  	defer os.Remove(outputFile.Name())
   199  	err = minioClient.FGetObject(fmt.Sprintf("master.%s", repo1), "file", outputFile.Name(), minio.GetObjectOptions{})
   200  	require.True(t, err == nil || errors.Is(err, io.EOF), fmt.Sprintf("unexpected error: %s", err))
   201  
   202  	// compare the files and ensure they're the same
   203  	// NOTE: Because minio's `FGetObject` does a rename from a buffer file
   204  	// to the given filepath, `outputFile` will refer to an empty, overwritten
   205  	// file. We can still use `outputFile.Name()` though.
   206  	inputFileSize, inputFileHash := fileHash(t, inputFile.Name())
   207  	outputFileSize, outputFileHash := fileHash(t, inputFile.Name())
   208  	require.Equal(t, inputFileSize, outputFileSize)
   209  	require.Equal(t, inputFileHash, outputFileHash)
   210  }
   211  
   212  func masterGetObjectNoHead(t *testing.T, pachClient *client.APIClient, minioClient *minio.Client) {
   213  	repo := tu.UniqueString("testgetobjectnohead")
   214  	require.NoError(t, pachClient.CreateRepo(repo))
   215  	require.NoError(t, pachClient.CreateBranch(repo, "branch", "", nil))
   216  
   217  	_, err := getObject(t, minioClient, fmt.Sprintf("branch.%s", repo), "file")
   218  	keyNotFoundError(t, err)
   219  }
   220  
   221  func masterGetObjectNoBranch(t *testing.T, pachClient *client.APIClient, minioClient *minio.Client) {
   222  	repo := tu.UniqueString("testgetobjectnobranch")
   223  	require.NoError(t, pachClient.CreateRepo(repo))
   224  
   225  	_, err := getObject(t, minioClient, fmt.Sprintf("branch.%s", repo), "file")
   226  	bucketNotFoundError(t, err)
   227  }
   228  
   229  func masterGetObjectNoRepo(t *testing.T, pachClient *client.APIClient, minioClient *minio.Client) {
   230  	repo := tu.UniqueString("testgetobjectnorepo")
   231  	_, err := getObject(t, minioClient, fmt.Sprintf("master.%s", repo), "file")
   232  	bucketNotFoundError(t, err)
   233  }
   234  
   235  func masterMakeBucket(t *testing.T, pachClient *client.APIClient, minioClient *minio.Client) {
   236  	repo := tu.UniqueString("testmakebucket")
   237  	require.NoError(t, minioClient.MakeBucket(fmt.Sprintf("master.%s", repo), ""))
   238  
   239  	repoInfo, err := pachClient.InspectRepo(repo)
   240  	require.NoError(t, err)
   241  	require.Equal(t, len(repoInfo.Branches), 1)
   242  	require.Equal(t, repoInfo.Branches[0].Name, "master")
   243  }
   244  
   245  func masterMakeBucketWithBranch(t *testing.T, pachClient *client.APIClient, minioClient *minio.Client) {
   246  	repo := tu.UniqueString("testmakebucketwithbranch")
   247  	require.NoError(t, minioClient.MakeBucket(fmt.Sprintf("branch.%s", repo), ""))
   248  
   249  	repoInfo, err := pachClient.InspectRepo(repo)
   250  	require.NoError(t, err)
   251  	require.Equal(t, len(repoInfo.Branches), 1)
   252  	require.Equal(t, repoInfo.Branches[0].Name, "branch")
   253  }
   254  
   255  func masterMakeBucketWithRegion(t *testing.T, pachClient *client.APIClient, minioClient *minio.Client) {
   256  	repo := tu.UniqueString("testmakebucketwithregion")
   257  	require.NoError(t, minioClient.MakeBucket(fmt.Sprintf("master.%s", repo), "us-east-1"))
   258  	_, err := pachClient.InspectRepo(repo)
   259  	require.NoError(t, err)
   260  }
   261  
   262  func masterMakeBucketRedundant(t *testing.T, pachClient *client.APIClient, minioClient *minio.Client) {
   263  	repo := tu.UniqueString("testmakebucketredundant")
   264  	require.NoError(t, minioClient.MakeBucket(fmt.Sprintf("master.%s", repo), ""))
   265  	err := minioClient.MakeBucket(fmt.Sprintf("master.%s", repo), "")
   266  	require.YesError(t, err)
   267  	require.Equal(t, err.Error(), "The bucket you tried to create already exists, and you own it.")
   268  }
   269  
   270  func masterMakeBucketDifferentBranches(t *testing.T, pachClient *client.APIClient, minioClient *minio.Client) {
   271  	repo := tu.UniqueString("testmakebucketdifferentbranches")
   272  	require.NoError(t, minioClient.MakeBucket(fmt.Sprintf("master.%s", repo), ""))
   273  	require.NoError(t, minioClient.MakeBucket(fmt.Sprintf("branch.%s", repo), ""))
   274  }
   275  
   276  func masterBucketExists(t *testing.T, pachClient *client.APIClient, minioClient *minio.Client) {
   277  	repo := tu.UniqueString("testbucketexists")
   278  
   279  	exists, err := minioClient.BucketExists(fmt.Sprintf("master.%s", repo))
   280  	require.NoError(t, err)
   281  	require.False(t, exists)
   282  
   283  	// repo exists, but branch doesn't: should be false
   284  	require.NoError(t, pachClient.CreateRepo(repo))
   285  	exists, err = minioClient.BucketExists(fmt.Sprintf("master.%s", repo))
   286  	require.NoError(t, err)
   287  	require.False(t, exists)
   288  
   289  	// repo and branch exists: should be true
   290  	require.NoError(t, pachClient.CreateBranch(repo, "master", "", nil))
   291  	exists, err = minioClient.BucketExists(fmt.Sprintf("master.%s", repo))
   292  	require.NoError(t, err)
   293  	require.True(t, exists)
   294  
   295  	// repo exists, but branch doesn't: should be false
   296  	exists, err = minioClient.BucketExists(fmt.Sprintf("branch.%s", repo))
   297  	require.NoError(t, err)
   298  	require.False(t, exists)
   299  
   300  	// repo and branch exists: should be true
   301  	require.NoError(t, pachClient.CreateBranch(repo, "branch", "", nil))
   302  	exists, err = minioClient.BucketExists(fmt.Sprintf("branch.%s", repo))
   303  	require.NoError(t, err)
   304  	require.True(t, exists)
   305  }
   306  
   307  func masterRemoveBucket(t *testing.T, pachClient *client.APIClient, minioClient *minio.Client) {
   308  	repo := tu.UniqueString("testremovebucket")
   309  
   310  	require.NoError(t, pachClient.CreateRepo(repo))
   311  	require.NoError(t, pachClient.CreateBranch(repo, "master", "", nil))
   312  	require.NoError(t, pachClient.CreateBranch(repo, "branch", "", nil))
   313  
   314  	require.NoError(t, minioClient.RemoveBucket(fmt.Sprintf("master.%s", repo)))
   315  	require.NoError(t, minioClient.RemoveBucket(fmt.Sprintf("branch.%s", repo)))
   316  }
   317  
   318  func masterRemoveBucketBranchless(t *testing.T, pachClient *client.APIClient, minioClient *minio.Client) {
   319  	repo := tu.UniqueString("testremovebucketbranchless")
   320  
   321  	// should error out because the repo doesn't have a branch
   322  	require.NoError(t, pachClient.CreateRepo(repo))
   323  	bucketNotFoundError(t, minioClient.RemoveBucket(fmt.Sprintf("master.%s", repo)))
   324  }
   325  
   326  func masterListObjectsPaginated(t *testing.T, pachClient *client.APIClient, minioClient *minio.Client) {
   327  	// create a bunch of files - enough to require the use of paginated
   328  	// requests when browsing all files. One file will be included on a
   329  	// separate branch to ensure it's not returned when querying against the
   330  	// master branch.
   331  	// `startTime` and `endTime` will be used to ensure that an object's
   332  	// `LastModified` date is correct. A few minutes are subtracted/added to
   333  	// each to tolerate the node time not being the same as the host time.
   334  	startTime := time.Now().Add(time.Duration(-5) * time.Minute)
   335  	// S3 client limits bucket name to 63 chars, and our commit_ids are 32 chars,
   336  	// leaving us with 31 free chars to use
   337  	repo := tu.UniqueString("testLOP")
   338  	require.NoError(t, pachClient.CreateRepo(repo))
   339  	commit, err := pachClient.StartCommit(repo, "master")
   340  	require.NoError(t, err)
   341  	for i := 0; i <= 1000; i++ {
   342  		putListFileTestObject(t, pachClient, repo, commit.ID, "", i)
   343  	}
   344  	for i := 0; i < 10; i++ {
   345  		putListFileTestObject(t, pachClient, repo, commit.ID, "dir/", i)
   346  	}
   347  	putListFileTestObject(t, pachClient, repo, "branch", "", 1001)
   348  	require.NoError(t, pachClient.FinishCommit(repo, commit.ID))
   349  	endTime := time.Now().Add(time.Duration(5) * time.Minute)
   350  
   351  	// Request that will list all files in master's root
   352  	ch := minioClient.ListObjects(fmt.Sprintf("master.%s", repo), "", false, make(chan struct{}))
   353  	expectedFiles := []string{}
   354  	for i := 0; i <= 1000; i++ {
   355  		expectedFiles = append(expectedFiles, fmt.Sprintf("%d", i))
   356  	}
   357  	checkListObjects(t, ch, &startTime, &endTime, expectedFiles, []string{"dir/"})
   358  
   359  	// Query by commit.repo
   360  	ch = minioClient.ListObjects(fmt.Sprintf("%s.%s", commit.ID, repo), "", false, make(chan struct{}))
   361  	checkListObjects(t, ch, &startTime, &endTime, expectedFiles, []string{"dir/"})
   362  
   363  	// Query by commit.branch.repo
   364  	ch = minioClient.ListObjects(fmt.Sprintf("%s.%s.%s", commit.ID, "master", repo), "", false, make(chan struct{}))
   365  	checkListObjects(t, ch, &startTime, &endTime, expectedFiles, []string{"dir/"})
   366  
   367  	// Query a different branch other than master
   368  	ch = minioClient.ListObjects(fmt.Sprintf("%s.%s", "branch", repo), "", false, make(chan struct{}))
   369  	checkListObjects(t, ch, &startTime, &endTime, []string{"1001"}, []string{})
   370  
   371  	// Request that will list all files in master starting with 1
   372  	ch = minioClient.ListObjects(fmt.Sprintf("master.%s", repo), "1", false, make(chan struct{}))
   373  	expectedFiles = []string{}
   374  	for i := 0; i <= 1000; i++ {
   375  		file := fmt.Sprintf("%d", i)
   376  		if strings.HasPrefix(file, "1") {
   377  			expectedFiles = append(expectedFiles, file)
   378  		}
   379  	}
   380  	checkListObjects(t, ch, &startTime, &endTime, expectedFiles, []string{})
   381  
   382  	// Request that will list all files in a directory in master
   383  	ch = minioClient.ListObjects(fmt.Sprintf("master.%s", repo), "dir/", false, make(chan struct{}))
   384  	expectedFiles = []string{}
   385  	for i := 0; i < 10; i++ {
   386  		expectedFiles = append(expectedFiles, fmt.Sprintf("dir/%d", i))
   387  	}
   388  	checkListObjects(t, ch, &startTime, &endTime, expectedFiles, []string{})
   389  }
   390  
   391  func masterListObjectsHeadlessBranch(t *testing.T, pachClient *client.APIClient, minioClient *minio.Client) {
   392  	repo := tu.UniqueString("testlistobjectsheadlessbranch")
   393  	require.NoError(t, pachClient.CreateRepo(repo))
   394  	require.NoError(t, pachClient.CreateBranch(repo, "emptybranch", "", nil))
   395  
   396  	// Request into branch that has no head
   397  	ch := minioClient.ListObjects(fmt.Sprintf("emptybranch.%s", repo), "", false, make(chan struct{}))
   398  	checkListObjects(t, ch, nil, nil, []string{}, []string{})
   399  }
   400  
   401  func masterListObjectsRecursive(t *testing.T, pachClient *client.APIClient, minioClient *minio.Client) {
   402  	// `startTime` and `endTime` will be used to ensure that an object's
   403  	// `LastModified` date is correct. A few minutes are subtracted/added to
   404  	// each to tolerate the node time not being the same as the host time.
   405  	startTime := time.Now().Add(time.Duration(-5) * time.Minute)
   406  	repo := tu.UniqueString("testlistobjectsrecursive")
   407  	require.NoError(t, pachClient.CreateRepo(repo))
   408  	require.NoError(t, pachClient.CreateBranch(repo, "branch", "", nil))
   409  	require.NoError(t, pachClient.CreateBranch(repo, "emptybranch", "", nil))
   410  	commit, err := pachClient.StartCommit(repo, "master")
   411  	require.NoError(t, err)
   412  	putListFileTestObject(t, pachClient, repo, commit.ID, "", 0)
   413  	putListFileTestObject(t, pachClient, repo, commit.ID, "rootdir/", 1)
   414  	putListFileTestObject(t, pachClient, repo, commit.ID, "rootdir/subdir/", 2)
   415  	putListFileTestObject(t, pachClient, repo, "branch", "", 3)
   416  	require.NoError(t, pachClient.FinishCommit(repo, commit.ID))
   417  	endTime := time.Now().Add(time.Duration(5) * time.Minute)
   418  
   419  	// Request that will list all files in master
   420  	expectedFiles := []string{"0", "rootdir/1", "rootdir/subdir/2"}
   421  	ch := minioClient.ListObjects(fmt.Sprintf("master.%s", repo), "", true, make(chan struct{}))
   422  	checkListObjects(t, ch, &startTime, &endTime, expectedFiles, []string{})
   423  
   424  	// Requests that will list all files in rootdir
   425  	expectedFiles = []string{"rootdir/1", "rootdir/subdir/2"}
   426  	ch = minioClient.ListObjects(fmt.Sprintf("master.%s", repo), "r", true, make(chan struct{}))
   427  	checkListObjects(t, ch, &startTime, &endTime, expectedFiles, []string{})
   428  	ch = minioClient.ListObjects(fmt.Sprintf("master.%s", repo), "rootdir", true, make(chan struct{}))
   429  	checkListObjects(t, ch, &startTime, &endTime, expectedFiles, []string{})
   430  	ch = minioClient.ListObjects(fmt.Sprintf("master.%s", repo), "rootdir/", true, make(chan struct{}))
   431  	checkListObjects(t, ch, &startTime, &endTime, expectedFiles, []string{})
   432  
   433  	// Requests that will list all files in subdir
   434  	expectedFiles = []string{"rootdir/subdir/2"}
   435  	ch = minioClient.ListObjects(fmt.Sprintf("master.%s", repo), "rootdir/s", true, make(chan struct{}))
   436  	checkListObjects(t, ch, &startTime, &endTime, expectedFiles, []string{})
   437  	ch = minioClient.ListObjects(fmt.Sprintf("master.%s", repo), "rootdir/subdir", true, make(chan struct{}))
   438  	checkListObjects(t, ch, &startTime, &endTime, expectedFiles, []string{})
   439  	ch = minioClient.ListObjects(fmt.Sprintf("master.%s", repo), "rootdir/subdir/", true, make(chan struct{}))
   440  	checkListObjects(t, ch, &startTime, &endTime, expectedFiles, []string{})
   441  	ch = minioClient.ListObjects(fmt.Sprintf("master.%s", repo), "rootdir/subdir/2", true, make(chan struct{}))
   442  	checkListObjects(t, ch, &startTime, &endTime, expectedFiles, []string{})
   443  }
   444  
   445  func masterAuthV2(t *testing.T, pachClient *client.APIClient, minioClient *minio.Client) {
   446  	// The other tests use auth V4, versus this which checks auth V2
   447  	host := os.Getenv("VM_IP")
   448  	if host == "" {
   449  		host = "127.0.0.1"
   450  	}
   451  	minioClientV2, err := minio.NewV2(fmt.Sprintf("%v:30600", host), "", "", false)
   452  	require.NoError(t, err)
   453  	_, err = minioClientV2.ListBuckets()
   454  	require.NoError(t, err)
   455  }
   456  
   457  func TestMasterDriver(t *testing.T) {
   458  	if testing.Short() {
   459  		t.Skip("Skipping integration tests in short mode")
   460  	}
   461  
   462  	testRunner(t, "master", NewMasterDriver(), func(t *testing.T, pachClient *client.APIClient, minioClient *minio.Client) {
   463  		t.Run("ListBuckets", func(t *testing.T) {
   464  			masterListBuckets(t, pachClient, minioClient)
   465  		})
   466  		t.Run("ListBucketsBranchless", func(t *testing.T) {
   467  			masterListBucketsBranchless(t, pachClient, minioClient)
   468  		})
   469  		t.Run("GetObject", func(t *testing.T) {
   470  			masterGetObject(t, pachClient, minioClient)
   471  		})
   472  		t.Run("GetObjectInBranch", func(t *testing.T) {
   473  			masterGetObjectInBranch(t, pachClient, minioClient)
   474  		})
   475  		t.Run("StatObject", func(t *testing.T) {
   476  			masterStatObject(t, pachClient, minioClient)
   477  		})
   478  		t.Run("PutObject", func(t *testing.T) {
   479  			masterPutObject(t, pachClient, minioClient)
   480  		})
   481  		t.Run("PutLargeObject", func(t *testing.T) {
   482  			masterPutObjectLarge(t, pachClient, minioClient)
   483  		})
   484  		t.Run("RemoveObject", func(t *testing.T) {
   485  			masterRemoveObject(t, pachClient, minioClient)
   486  		})
   487  		t.Run("LargeObjects", func(t *testing.T) {
   488  			masterLargeObjects(t, pachClient, minioClient)
   489  		})
   490  		t.Run("GetObjectNoHead", func(t *testing.T) {
   491  			masterGetObjectNoHead(t, pachClient, minioClient)
   492  		})
   493  		t.Run("GetObjectNoBranch", func(t *testing.T) {
   494  			masterGetObjectNoBranch(t, pachClient, minioClient)
   495  		})
   496  		t.Run("GetObjectNoRepo", func(t *testing.T) {
   497  			masterGetObjectNoRepo(t, pachClient, minioClient)
   498  		})
   499  		t.Run("MakeBucket", func(t *testing.T) {
   500  			masterMakeBucket(t, pachClient, minioClient)
   501  		})
   502  		t.Run("MakeBucketWithBranch", func(t *testing.T) {
   503  			masterMakeBucketWithBranch(t, pachClient, minioClient)
   504  		})
   505  		t.Run("MakeBucketWithRegion", func(t *testing.T) {
   506  			masterMakeBucketWithRegion(t, pachClient, minioClient)
   507  		})
   508  		t.Run("MakeBucketRedundant", func(t *testing.T) {
   509  			masterMakeBucketRedundant(t, pachClient, minioClient)
   510  		})
   511  		t.Run("MakeBucketDifferentBranches", func(t *testing.T) {
   512  			masterMakeBucketDifferentBranches(t, pachClient, minioClient)
   513  		})
   514  		t.Run("BucketExists", func(t *testing.T) {
   515  			masterBucketExists(t, pachClient, minioClient)
   516  		})
   517  		t.Run("RemoveBucket", func(t *testing.T) {
   518  			masterRemoveBucket(t, pachClient, minioClient)
   519  		})
   520  		t.Run("RemoveBucketBranchless", func(t *testing.T) {
   521  			masterRemoveBucketBranchless(t, pachClient, minioClient)
   522  		})
   523  		t.Run("ListObjectsPaginated", func(t *testing.T) {
   524  			masterListObjectsPaginated(t, pachClient, minioClient)
   525  		})
   526  		t.Run("ListObjectsHeadlessBranch", func(t *testing.T) {
   527  			masterListObjectsHeadlessBranch(t, pachClient, minioClient)
   528  		})
   529  		t.Run("ListObjectsRecursive", func(t *testing.T) {
   530  			masterListObjectsRecursive(t, pachClient, minioClient)
   531  		})
   532  		t.Run("AuthV2", func(t *testing.T) {
   533  			masterAuthV2(t, pachClient, minioClient)
   534  		})
   535  	})
   536  }