package s3
import (
"context"
"errors"
"strings"
"testing"
"time"
)
// Copy replaces an object's metadata in place, by CopyObject from the
// key to itself: the bytes never pass through the forge, and the type,
// the disposition and the metadata are the ones given now.
func TestCopyReplacesMetadata(t *testing.T) {
srv, m := newMetaBucket(t)
b := Bucket{Endpoint: srv.URL, Name: "files", Region: "auto", AccessKey: "AK", Secret: testSecret}
ctx := context.Background()
key := "unversioned/releases/a b+c.txt"
if err := b.PutWith(ctx, nil, key, []byte("12345"), PutOptions{ContentType: "text/plain",
Meta: map[string]string{"mtime": "1", "hash": "c0ffee"}}, time.Now()); err != nil {
t.Fatal(err)
}
err := b.Copy(ctx, nil, key, key, PutOptions{ContentType: "text/plain; charset=utf-8",
Meta: map[string]string{"mtime": "2", "hash": "c0ffee"}}, time.Now())
if err != nil {
t.Fatalf("FAIL: copy: %v", err)
}
o := m.objects[key]
if string(o.body) != "12345" || o.meta["mtime"] != "2" || o.meta["hash"] != "c0ffee" || o.ctype != "text/plain; charset=utf-8" || m.copies != 1 {
t.Errorf("FAIL: after copy %+v copies=%d", o, m.copies)
} else {
t.Log("ok: the metadata is replaced and the bytes stay where they are")
}
if err := b.Copy(ctx, nil, "unversioned/none", "unversioned/none", PutOptions{}, time.Now()); err == nil {
t.Error("FAIL: copying an absent object succeeded")
}
// CopyObject can answer 200 and then report the failure in the
// body; that is a failure, and the object is unchanged.
m.copyFails = true
err = b.Copy(ctx, nil, key, key, PutOptions{ContentType: "text/plain", Meta: map[string]string{"mtime": "3"}}, time.Now())
var pe *ProbeError
if !errors.As(err, &pe) || pe.Code != "InternalError" || m.objects[key].meta["mtime"] != "2" {
t.Errorf("FAIL: a 200 carrying an error: %v, mtime %s", err, m.objects[key].meta["mtime"])
} else {
t.Log("ok: a copy that answers 200 with an error body is a failure")
}
}
// GetMax reads an object whole when it fits and refuses one that does
// not, without reading past the bound.
func TestGetMaxIsBounded(t *testing.T) {
srv, m := newMetaBucket(t)
m.objects["unversioned/a"] = metaObject{body: []byte("0123456789")}
b := Bucket{Endpoint: srv.URL, Name: "files", Region: "auto", AccessKey: "AK", Secret: testSecret}
ctx := context.Background()
got, err := b.GetMax(ctx, nil, "unversioned/a", 10, time.Now())
if err != nil || string(got) != "0123456789" {
t.Errorf("FAIL: at the bound: %q %v", got, err)
}
if _, err := b.GetMax(ctx, nil, "unversioned/a", 9, time.Now()); err == nil || !strings.Contains(err.Error(), "larger than 9") {
t.Errorf("FAIL: over the bound: %v", err)
}
if _, err := b.GetMax(ctx, nil, "unversioned/none", 9, time.Now()); err == nil {
t.Error("FAIL: an absent object read as empty")
}
t.Log("ok: a bounded read takes what fits and refuses the rest")
}