1package main
2
3import (
4	"bytes"
5	"fmt"
6
7	"github.com/aws/aws-sdk-go/aws"
8	"github.com/aws/aws-sdk-go/service/s3"
9)
10
11// Here we are checking to see if a bucket that has never had versioning enabled
12// will respond successfully to ListVersions; turns out it will.
13//
14// Discoveries:
15//
16// - S3 responds to ListVersions even if the bucket has never been versioned.
17//   We will probably need to fake this in in the GoFakeS3 struct to use the
18//   normal bucket listing API when the backend does not implement versioning,
19//   but this will probably need to wait until we implement proper pagination.
20//
21// - The API returns the _string_ 'null' for the version ID, which the Go SDK
22//   happily returns as the *string* value 'null' (yecch!). GoFakeS3 backend
23//   implementers should be able to simply return the empty string; GoFakeS3
24//   itself should handle this particular bit of jank once and once only.
25//
26type S300005ListVersionsWithNeverVersionedBucket struct{}
27
28func (s S300005ListVersionsWithNeverVersionedBucket) Run(ctx *Context) error {
29	client := ctx.S3Client()
30	config := ctx.Config()
31	bucket := aws.String(config.BucketUnversioned())
32
33	if err := ctx.EnsureVersioningNeverEnabled(client, config.BucketUnversioned()); err != nil {
34		return err
35	}
36
37	prefix := ctx.RandString(50)
38	key1, key2 := prefix+ctx.RandString(100), prefix+ctx.RandString(100)
39	keys := []string{key1, key2}
40
41	versions := map[string][]string{}
42	for _, key := range keys {
43		for i := 0; i < 2; i++ {
44			body := ctx.RandBytes(32)
45			vrs, err := client.PutObject(&s3.PutObjectInput{
46				Key:    aws.String(key),
47				Bucket: bucket,
48				Body:   bytes.NewReader(body),
49			})
50			if err != nil {
51				return err
52			}
53			versions[key] = append(versions[key], aws.StringValue(vrs.VersionId))
54		}
55	}
56
57	{ // Sanity check version length
58		rs, err := client.ListObjectVersions(&s3.ListObjectVersionsInput{
59			Bucket: bucket,
60			Prefix: aws.String(prefix),
61		})
62		if err != nil {
63			return err
64		}
65
66		// We have uploaded two keys, two versions per key, but as we have never
67		// enabled versioning, we only expect two results
68		if len(rs.Versions) != 2 {
69			return fmt.Errorf("unexpected version length")
70		}
71
72		for _, ver := range rs.Versions {
73			// This is pretty bad... the AWS SDK returns the *STRING* 'null' if there's no version ID.
74			if aws.StringValue(ver.VersionId) != "null" {
75				return fmt.Errorf("version id was not nil; found %q", aws.StringValue(ver.VersionId))
76			}
77		}
78	}
79
80	return nil
81}
82