package assets import ( "bytes" "context" "errors" "io" "testing" ) type ossClientStub struct { puts []OSSPutRequest acls []OSSACLRequest gets []OSSObjectRequest deletes []OSSObjectRequest body []byte contentType string getErr, errorToReturn error } func (s *ossClientStub) Put(_ context.Context, r OSSPutRequest) error { s.puts = append(s.puts, r) _, _ = io.ReadAll(r.Body) return s.errorToReturn } func (s *ossClientStub) SetACL(_ context.Context, r OSSACLRequest) error { s.acls = append(s.acls, r) return s.errorToReturn } func (s *ossClientStub) Get(_ context.Context, r OSSObjectRequest) (Blob, error) { s.gets = append(s.gets, r) if s.getErr != nil { return Blob{}, s.getErr } return Blob{Body: io.NopCloser(bytes.NewReader(s.body)), ContentType: s.contentType, Size: int64(len(s.body))}, nil } func (s *ossClientStub) Delete(_ context.Context, r OSSObjectRequest) error { s.deletes = append(s.deletes, r) return s.errorToReturn } func TestOSSPutUsesConfiguredAddressContentTypeAndPublicACL(t *testing.T) { client := &ossClientStub{} store, err := NewOSS(OSSConfig{Endpoint: "https://oss-cn.test", Bucket: "bucket-a", PublicBaseURL: "https://cdn.test/root", PublicRead: true}, client) if err != nil { t.Fatal(err) } got, err := store.Put(context.Background(), "uploads/a b.png", bytes.NewReader([]byte("png")), 3, "image/png") if err != nil { t.Fatal(err) } if got.Key != "uploads/a b.png" || got.URL != "https://cdn.test/root/uploads/a%20b.png" { t.Fatalf("stored=%#v", got) } if len(client.puts) != 1 || client.puts[0].Endpoint != "https://oss-cn.test" || client.puts[0].Bucket != "bucket-a" || client.puts[0].ContentType != "image/png" || client.puts[0].Size != 3 { t.Fatalf("puts=%#v", client.puts) } if len(client.acls) != 1 || client.acls[0].ACL != OSSACLPublicRead { t.Fatalf("acls=%#v", client.acls) } } func TestOSSReadDeleteAndMissingMapping(t *testing.T) { client := &ossClientStub{body: []byte("x"), contentType: "image/png"} store, _ := NewOSS(OSSConfig{Endpoint: "e", Bucket: "b", PublicBaseURL: "https://cdn.test"}, client) blob, err := store.Read(context.Background(), "generated-results/x.png") if err != nil { t.Fatal(err) } _ = blob.Body.Close() if len(client.gets) != 1 || client.gets[0].Key != "generated-results/x.png" { t.Fatalf("gets=%#v", client.gets) } if err = store.Delete(context.Background(), "generated-results/x.png"); err != nil || len(client.deletes) != 1 { t.Fatalf("delete=%v %#v", err, client.deletes) } client.getErr = &OSSError{Status: 404, Code: "NoSuchKey", Err: errors.New("secret response")} if _, err = store.Read(context.Background(), "missing"); !errors.Is(err, ErrBlobNotFound) { t.Fatalf("missing=%v", err) } client.errorToReturn = &OSSError{Status: 404, Code: "NoSuchKey"} if err = store.Delete(context.Background(), "missing"); err != nil { t.Fatalf("delete missing=%v", err) } } func TestOSSRejectsUnsafeKeysAndIncompleteConfiguration(t *testing.T) { if _, err := NewOSS(OSSConfig{Endpoint: "e", Bucket: "b"}, &ossClientStub{}); err == nil { t.Fatal("expected config error") } store, _ := NewOSS(OSSConfig{Endpoint: "e", Bucket: "b", PublicBaseURL: "https://cdn.test"}, &ossClientStub{}) for _, key := range []string{"", "../secret", "/absolute", "a\\b"} { if _, err := store.Put(context.Background(), key, bytes.NewReader(nil), 0, "x"); !errors.Is(err, ErrUnsafeBlobKey) { t.Errorf("key %q: %v", key, err) } } }