carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1//go:build linux && rootrunner
2
3package host
4
5import (
6 "context"
7 "encoding/xml"
8 "fmt"
9 "net/http"
10 "net/http/httptest"
11 "sort"
12 "strings"
13 "testing"
14 "time"
15
16 "github.com/aws/aws-sdk-go-v2/aws"
17 "github.com/aws/aws-sdk-go-v2/service/s3"
18 "github.com/carlosframework/platform/internal/lease/leasetest"
19)
20
21func TestPlan14LifecycleS3(t *testing.T) {
22 model := leasetest.NewVersionedBucket()
23 model.AddBucket("data")
24 handler, _ := leasetest.NewS3Server(model)
25 server := httptest.NewServer(lifecycleS3(handler, model))
26 defer server.Close()
27 lifecycleEnvironment(t, server.URL)
28 markers, err := newProductionClaimMarkers(t.Context(), "data", "eu-west-1")
29 if err != nil {
30 t.Fatal(err)
31 }
32 key := "instances/lifecycle/generations/one/generation.json"
33 id, err := markers.PutMarker(t.Context(), "data", key, []byte("marker"), "", func(context.Context) error { return nil })
34 if err != nil || id == "" {
35 t.Fatal(id, err)
36 }
37 listed, err := markers.(productionClaimMarkers).Client.ListObjectsV2(t.Context(), &s3.ListObjectsV2Input{Bucket: aws.String("data"), Prefix: aws.String("instances/")})
38 if err != nil || len(listed.Contents) != 1 || aws.ToString(listed.Contents[0].Key) != key {
39 t.Fatal(listed, err)
40 }
41}
42
43func lifecycleS3(next http.Handler, model *leasetest.VersionedBucket) http.Handler {
44 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
45 q := r.URL.Query()
46 if r.Method != http.MethodGet || strings.Trim(r.URL.Path, "/") != "data" || q.Get("list-type") != "2" {
47 next.ServeHTTP(w, r)
48 return
49 }
50 versions, err := model.ListVersions(r.Context(), "data", q.Get("prefix"))
51 if err != nil {
52 http.Error(w, err.Error(), 500)
53 return
54 }
55 type object struct {
56 Key, LastModified, ETag string
57 Size int64
58 }
59 type common struct{ Prefix string }
60 result := struct {
61 XMLName xml.Name `xml:"ListBucketResult"`
62 Name, Prefix, Delimiter string
63 MaxKeys, KeyCount int
64 IsTruncated bool
65 Contents []object
66 CommonPrefixes []common
67 }{Name: "data", Prefix: q.Get("prefix"), Delimiter: q.Get("delimiter"), MaxKeys: 1000}
68 prefixes := map[string]bool{}
69 for _, v := range versions {
70 if !v.IsLatest || v.DeleteMarker {
71 continue
72 }
73 if result.Delimiter != "" {
74 rest := strings.TrimPrefix(v.Key, result.Prefix)
75 if at := strings.Index(rest, result.Delimiter); at >= 0 {
76 prefixes[result.Prefix+rest[:at+len(result.Delimiter)]] = true
77 continue
78 }
79 }
80 result.Contents = append(result.Contents, object{v.Key, v.LastModified.UTC().Format(time.RFC3339Nano), fmt.Sprintf("%q", v.ETag), v.Size})
81 }
82 for p := range prefixes {
83 result.CommonPrefixes = append(result.CommonPrefixes, common{p})
84 }
85 sort.Slice(result.CommonPrefixes, func(i, j int) bool { return result.CommonPrefixes[i].Prefix < result.CommonPrefixes[j].Prefix })
86 result.KeyCount = len(result.Contents) + len(result.CommonPrefixes)
87 if result.KeyCount > result.MaxKeys {
88 http.Error(w, "fixture listing exceeds one page", 500)
89 return
90 }
91 w.Header().Set("Content-Type", "application/xml")
92 xml.NewEncoder(w).Encode(result)
93 })
94}
95