|
1 | 1 | package storage |
2 | 2 |
|
3 | 3 | import ( |
| 4 | + "context" |
4 | 5 | "errors" |
| 6 | + "io" |
5 | 7 | "net/http" |
| 8 | + "strings" |
| 9 | + "sync/atomic" |
6 | 10 | "testing" |
7 | 11 |
|
8 | 12 | "github.com/minio/minio-go/v7" |
| 13 | + "github.com/minio/minio-go/v7/pkg/credentials" |
9 | 14 | "github.com/samber/lo" |
10 | 15 | "github.com/stretchr/testify/assert" |
| 16 | + "github.com/stretchr/testify/require" |
11 | 17 | ) |
12 | 18 |
|
13 | 19 | func TestSplitIntoParts(t *testing.T) { |
@@ -89,3 +95,148 @@ func TestIsDeleteSuccessful(t *testing.T) { |
89 | 95 | }) |
90 | 96 | } |
91 | 97 | } |
| 98 | + |
| 99 | +func TestBucketExistStopsAfterFirstResult(t *testing.T) { |
| 100 | + var listReqCount atomic.Int32 |
| 101 | + var firstReqPath string |
| 102 | + var firstReqMaxKeys string |
| 103 | + var firstReqContinuationToken string |
| 104 | + cli, err := newInternalMinio(Config{ |
| 105 | + Provider: "s3", |
| 106 | + Endpoint: "example.com", |
| 107 | + UseSSL: true, |
| 108 | + Bucket: "test-bucket", |
| 109 | + Credential: Credential{ |
| 110 | + Type: Static, |
| 111 | + AK: "ak", |
| 112 | + SK: "sk", |
| 113 | + }, |
| 114 | + }, &minio.Options{ |
| 115 | + Secure: true, |
| 116 | + Creds: credentials.NewStaticV4("ak", "sk", ""), |
| 117 | + Transport: roundTripperFunc(func(r *http.Request) (*http.Response, error) { |
| 118 | + if _, ok := r.URL.Query()["location"]; ok { |
| 119 | + return &http.Response{ |
| 120 | + StatusCode: http.StatusOK, |
| 121 | + Header: http.Header{"Content-Type": []string{"application/xml"}}, |
| 122 | + Body: io.NopCloser(strings.NewReader(`<LocationConstraint xmlns="http://s3.amazonaws.com/doc/2006-03-01/"></LocationConstraint>`)), |
| 123 | + Request: r, |
| 124 | + }, nil |
| 125 | + } |
| 126 | + |
| 127 | + if r.URL.Query().Get("list-type") != "2" { |
| 128 | + return nil, errors.New("unexpected request") |
| 129 | + } |
| 130 | + |
| 131 | + if token := r.URL.Query().Get("continuation-token"); token != "" { |
| 132 | + <-r.Context().Done() |
| 133 | + return nil, r.Context().Err() |
| 134 | + } |
| 135 | + |
| 136 | + listReqCount.Add(1) |
| 137 | + firstReqPath = r.URL.Path |
| 138 | + firstReqMaxKeys = r.URL.Query().Get("max-keys") |
| 139 | + firstReqContinuationToken = r.URL.Query().Get("continuation-token") |
| 140 | + |
| 141 | + return &http.Response{ |
| 142 | + StatusCode: http.StatusOK, |
| 143 | + Header: http.Header{"Content-Type": []string{"application/xml"}}, |
| 144 | + Body: io.NopCloser(strings.NewReader(`<?xml version="1.0" encoding="UTF-8"?> |
| 145 | +<ListBucketResult> |
| 146 | + <Name>test-bucket</Name> |
| 147 | + <Prefix></Prefix> |
| 148 | + <MaxKeys>1</MaxKeys> |
| 149 | + <IsTruncated>true</IsTruncated> |
| 150 | + <Contents> |
| 151 | + <Key>first-object</Key> |
| 152 | + <Size>1</Size> |
| 153 | + </Contents> |
| 154 | + <NextContinuationToken>next-page</NextContinuationToken> |
| 155 | +</ListBucketResult>`)), |
| 156 | + Request: r, |
| 157 | + }, nil |
| 158 | + }), |
| 159 | + }) |
| 160 | + require.NoError(t, err) |
| 161 | + |
| 162 | + exists, err := cli.BucketExist(context.Background(), "") |
| 163 | + require.NoError(t, err) |
| 164 | + assert.True(t, exists) |
| 165 | + assert.EqualValues(t, 1, listReqCount.Load()) |
| 166 | + assert.Equal(t, "/test-bucket/", firstReqPath) |
| 167 | + assert.Equal(t, "1", firstReqMaxKeys) |
| 168 | + assert.Empty(t, firstReqContinuationToken) |
| 169 | +} |
| 170 | + |
| 171 | +func TestBucketExistReturnsFalseForNoSuchBucket(t *testing.T) { |
| 172 | + cli, err := newInternalMinio(Config{ |
| 173 | + Provider: "s3", |
| 174 | + Endpoint: "example.com", |
| 175 | + UseSSL: true, |
| 176 | + Bucket: "missing-bucket", |
| 177 | + Credential: Credential{ |
| 178 | + Type: Static, |
| 179 | + AK: "ak", |
| 180 | + SK: "sk", |
| 181 | + }, |
| 182 | + }, &minio.Options{ |
| 183 | + Secure: true, |
| 184 | + Creds: credentials.NewStaticV4("ak", "sk", ""), |
| 185 | + Transport: roundTripperFunc(func(r *http.Request) (*http.Response, error) { |
| 186 | + return &http.Response{ |
| 187 | + StatusCode: http.StatusNotFound, |
| 188 | + Header: http.Header{"Content-Type": []string{"application/xml"}}, |
| 189 | + Body: io.NopCloser(strings.NewReader(`<?xml version="1.0" encoding="UTF-8"?> |
| 190 | +<Error> |
| 191 | + <Code>NoSuchBucket</Code> |
| 192 | + <Message>The specified bucket does not exist</Message> |
| 193 | + <BucketName>missing-bucket</BucketName> |
| 194 | + <Resource>/missing-bucket/</Resource> |
| 195 | + <RequestId>req</RequestId> |
| 196 | + <HostId>host</HostId> |
| 197 | +</Error>`)), |
| 198 | + Request: r, |
| 199 | + }, nil |
| 200 | + }), |
| 201 | + }) |
| 202 | + require.NoError(t, err) |
| 203 | + |
| 204 | + exists, err := cli.BucketExist(context.Background(), "") |
| 205 | + require.NoError(t, err) |
| 206 | + assert.False(t, exists) |
| 207 | +} |
| 208 | + |
| 209 | +func TestBucketExistPropagatesContextCancellation(t *testing.T) { |
| 210 | + cli, err := newInternalMinio(Config{ |
| 211 | + Provider: "s3", |
| 212 | + Endpoint: "example.com", |
| 213 | + UseSSL: true, |
| 214 | + Bucket: "test-bucket", |
| 215 | + Credential: Credential{ |
| 216 | + Type: Static, |
| 217 | + AK: "ak", |
| 218 | + SK: "sk", |
| 219 | + }, |
| 220 | + }, &minio.Options{ |
| 221 | + Secure: true, |
| 222 | + Creds: credentials.NewStaticV4("ak", "sk", ""), |
| 223 | + Transport: roundTripperFunc(func(r *http.Request) (*http.Response, error) { |
| 224 | + return nil, context.Canceled |
| 225 | + }), |
| 226 | + }) |
| 227 | + require.NoError(t, err) |
| 228 | + |
| 229 | + ctx, cancel := context.WithCancel(context.Background()) |
| 230 | + cancel() |
| 231 | + |
| 232 | + exists, err := cli.BucketExist(ctx, "") |
| 233 | + assert.False(t, exists) |
| 234 | + require.Error(t, err) |
| 235 | + assert.ErrorIs(t, err, context.Canceled) |
| 236 | +} |
| 237 | + |
| 238 | +type roundTripperFunc func(*http.Request) (*http.Response, error) |
| 239 | + |
| 240 | +func (f roundTripperFunc) RoundTrip(req *http.Request) (*http.Response, error) { |
| 241 | + return f(req) |
| 242 | +} |
0 commit comments