mirror of
https://github.com/logos-storage/logos-storage-go.git
synced 2026-01-03 05:43:12 +00:00
285 lines
9.5 KiB
Go
285 lines
9.5 KiB
Go
//go:build codex_integration
|
|
// +build codex_integration
|
|
|
|
package codexclient_test
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"errors"
|
|
"io"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"github.com/stretchr/testify/suite"
|
|
|
|
"go-codex-client/codexclient"
|
|
"go-codex-client/codextestutils"
|
|
)
|
|
|
|
func upload(client codexclient.CodexClient, t *testing.T, buf *bytes.Buffer) string {
|
|
filename := "hello.txt"
|
|
cid, err := client.Upload(buf, filename)
|
|
if err != nil {
|
|
t.Fatalf("Failed to upload file: %v", err)
|
|
}
|
|
|
|
if cid == "" {
|
|
t.Fatalf("Expected non-empty CID after upload")
|
|
}
|
|
|
|
return cid
|
|
}
|
|
|
|
// CodexClientTestSuite demonstrates testify's suite functionality for CodexClient tests
|
|
type CodexClientTestSuite struct {
|
|
suite.Suite
|
|
client *codexclient.CodexClient
|
|
}
|
|
|
|
// SetupTest runs before each test method
|
|
func (suite *CodexClientTestSuite) SetupTest() {
|
|
suite.client = codextestutils.NewCodexClientTest(suite.T())
|
|
}
|
|
|
|
// TearDownTest runs after each test method
|
|
func (suite *CodexClientTestSuite) TearDownTest() {
|
|
}
|
|
|
|
// TestCodexClientTestSuite runs the test suite
|
|
func TestCodexClientTestSuite(t *testing.T) {
|
|
suite.Run(t, new(CodexClientTestSuite))
|
|
}
|
|
|
|
func (suite *CodexClientTestSuite) TestUpload_Success() {
|
|
// Act
|
|
cid, err := suite.client.Upload(bytes.NewReader([]byte("payload")), "hello.txt")
|
|
|
|
// Assert
|
|
require.NoError(suite.T(), err)
|
|
// Codex uses CIDv1 with base58btc encoding (prefix: zDv)
|
|
assert.Equal(suite.T(), "zDvZRwzmBEaJ338xaCHbKbGAJ4X41YyccS6eyorrYBbmPnWuLxCh", cid)
|
|
}
|
|
|
|
func (suite *CodexClientTestSuite) TestDownloadWithContext_Cancel() {
|
|
// skip test
|
|
suite.T().Skip("Wait for cancellation support PR to be merged in codex-go-bindings")
|
|
|
|
len := 1024 * 1024 * 50
|
|
buf := bytes.NewBuffer(make([]byte, len))
|
|
cid := upload(*suite.client, suite.T(), buf)
|
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Millisecond)
|
|
|
|
channelError := make(chan error, 1)
|
|
go func() {
|
|
err := suite.client.DownloadWithContext(ctx, cid, io.Discard)
|
|
channelError <- err
|
|
}()
|
|
|
|
cancel()
|
|
err := <-channelError
|
|
|
|
require.Error(suite.T(), err)
|
|
// Accept either canceled or deadline exceeded depending on timing
|
|
if !errors.Is(err, context.Canceled) && !errors.Is(err, context.DeadlineExceeded) {
|
|
// net/http may wrap the context error; check error string as a fallback
|
|
es := err.Error()
|
|
if !(es == context.Canceled.Error() || es == context.DeadlineExceeded.Error()) {
|
|
suite.T().Fatalf("expected context cancellation, got: %v", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (suite *CodexClientTestSuite) TestHasCid_Success() {
|
|
const payload = "hello from codex"
|
|
cid := upload(*suite.client, suite.T(), bytes.NewBuffer([]byte(payload)))
|
|
|
|
tests := []struct {
|
|
name string
|
|
cid string
|
|
wantBool bool
|
|
}{
|
|
{"has CID returns true", cid, true},
|
|
{"has CID returns false", "zDvZRwzmBEaJ338xaCHbKbGAJ4X41YyccS6eyorrYBbmPnWuLxCe", false},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
suite.Run(tt.name, func() {
|
|
got, err := suite.client.HasCid(tt.cid)
|
|
require.NoError(suite.T(), err)
|
|
assert.Equal(suite.T(), tt.wantBool, got, "HasCid(%q) = %v, want %v", tt.cid, got, tt.wantBool)
|
|
})
|
|
}
|
|
}
|
|
|
|
func (suite *CodexClientTestSuite) TestDownload_Success() {
|
|
const payload = "hello from codex"
|
|
cid := upload(*suite.client, suite.T(), bytes.NewBuffer([]byte(payload)))
|
|
|
|
var buf bytes.Buffer
|
|
err := suite.client.Download(cid, &buf)
|
|
require.NoError(suite.T(), err)
|
|
assert.Equal(suite.T(), payload, buf.String())
|
|
}
|
|
|
|
func (suite *CodexClientTestSuite) TestRemoveCid_Success() {
|
|
const payload = "hello from codex"
|
|
cid := upload(*suite.client, suite.T(), bytes.NewBuffer([]byte(payload)))
|
|
|
|
err := suite.client.RemoveCid(cid)
|
|
require.NoError(suite.T(), err)
|
|
}
|
|
|
|
func (suite *CodexClientTestSuite) TestTriggerDownload() {
|
|
const payload = "hello from codex"
|
|
cid := upload(*suite.client, suite.T(), bytes.NewBuffer([]byte(payload)))
|
|
|
|
ctx := context.Background()
|
|
manifest, err := suite.client.TriggerDownloadWithContext(ctx, cid)
|
|
require.NoError(suite.T(), err)
|
|
assert.Equal(suite.T(), cid, manifest.Cid)
|
|
assert.Equal(suite.T(), "zDzSvJTf7mGkC3yuiVGco7Qc6s4LA8edye9inT4w2QqHnfbuRvMr", manifest.TreeCid)
|
|
assert.Equal(suite.T(), len(payload), manifest.DatasetSize)
|
|
assert.Equal(suite.T(), "hello.txt", manifest.Filename)
|
|
}
|
|
|
|
func (suite *CodexClientTestSuite) TestTriggerDownloadWithContext_Cancellation() {
|
|
suite.T().Skip("Not sure if we are going to have cancellation in trigger download")
|
|
|
|
const testCid = "zDvZRwzmTestCID"
|
|
|
|
// Cancel after 50ms (before server responds)
|
|
ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
|
|
defer cancel()
|
|
|
|
manifest, err := suite.client.TriggerDownloadWithContext(ctx, testCid)
|
|
require.Error(suite.T(), err, "expected cancellation error")
|
|
assert.Nil(suite.T(), manifest, "expected nil manifest on cancellation")
|
|
// Accept either canceled or deadline exceeded depending on timing
|
|
if !errors.Is(err, context.Canceled) && !errors.Is(err, context.DeadlineExceeded) {
|
|
// net/http may wrap the context error; check error string as a fallback
|
|
es := err.Error()
|
|
if !(es == context.Canceled.Error() || es == context.DeadlineExceeded.Error()) {
|
|
suite.T().Fatalf("expected context cancellation, got: %v", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (suite *CodexClientTestSuite) TestLocalDownload() {
|
|
const payload = "test data for local download"
|
|
cid := upload(*suite.client, suite.T(), bytes.NewBuffer([]byte(payload)))
|
|
|
|
var buf bytes.Buffer
|
|
err := suite.client.LocalDownload(cid, &buf)
|
|
require.NoError(suite.T(), err, "LocalDownload failed")
|
|
assert.Equal(suite.T(), payload, buf.String(), "Downloaded data mismatch")
|
|
}
|
|
|
|
func (suite *CodexClientTestSuite) TestLocalDownloadWithContext_Success() {
|
|
const payload = "test data for local download with context"
|
|
cid := upload(*suite.client, suite.T(), bytes.NewBuffer([]byte(payload)))
|
|
|
|
ctx := context.Background()
|
|
var buf bytes.Buffer
|
|
err := suite.client.LocalDownloadWithContext(ctx, cid, &buf)
|
|
require.NoError(suite.T(), err, "LocalDownloadWithContext failed")
|
|
assert.Equal(suite.T(), payload, buf.String(), "Downloaded data mismatch")
|
|
}
|
|
|
|
func (suite *CodexClientTestSuite) TestLocalDownloadWithContext_Cancellation() {
|
|
suite.T().Skip("Wait for cancellation support PR to be merged in codex-go-bindings")
|
|
|
|
len := 1024 * 1024 * 50
|
|
buf := bytes.NewBuffer(make([]byte, len))
|
|
cid := upload(*suite.client, suite.T(), buf)
|
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond)
|
|
|
|
channelError := make(chan error, 1)
|
|
go func() {
|
|
err := suite.client.LocalDownloadWithContext(ctx, cid, io.Discard)
|
|
channelError <- err
|
|
}()
|
|
|
|
cancel()
|
|
err := <-channelError
|
|
|
|
require.Error(suite.T(), err, "Expected context cancellation error")
|
|
// Accept either canceled or deadline exceeded depending on timing
|
|
if !errors.Is(err, context.Canceled) && !errors.Is(err, context.DeadlineExceeded) {
|
|
// net/http may wrap the context error; check error string as a fallback
|
|
es := err.Error()
|
|
if !(es == context.Canceled.Error() || es == context.DeadlineExceeded.Error()) {
|
|
suite.T().Fatalf("expected context cancellation, got: %v", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (suite *CodexClientTestSuite) TestFetchManifestWithContext_Success() {
|
|
const payload = "hello from codex"
|
|
cid := upload(*suite.client, suite.T(), bytes.NewBuffer([]byte(payload)))
|
|
|
|
ctx := context.Background()
|
|
manifest, err := suite.client.FetchManifestWithContext(ctx, cid)
|
|
require.NoError(suite.T(), err, "Expected no error")
|
|
require.NotNil(suite.T(), manifest, "Expected manifest, got nil")
|
|
|
|
assert.Equal(suite.T(), cid, manifest.Cid)
|
|
assert.Equal(suite.T(), "zDzSvJTf7mGkC3yuiVGco7Qc6s4LA8edye9inT4w2QqHnfbuRvMr", manifest.TreeCid)
|
|
assert.Equal(suite.T(), len(payload), manifest.DatasetSize)
|
|
assert.Equal(suite.T(), 65536, manifest.BlockSize)
|
|
assert.True(suite.T(), !manifest.Protected, "Expected Protected to be false")
|
|
assert.Equal(suite.T(), "hello.txt", manifest.Filename)
|
|
assert.Equal(suite.T(), "text/plain", manifest.Mimetype)
|
|
}
|
|
|
|
func (suite *CodexClientTestSuite) TestFetchManifestWithContext_Cancellation() {
|
|
suite.T().Skip("Not sure if we are going to have cancellation in fetch manifest")
|
|
|
|
testCid := "zDvZRwzmTestCID"
|
|
|
|
// Create a context with a very short timeout
|
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond)
|
|
defer cancel()
|
|
|
|
manifest, err := suite.client.FetchManifestWithContext(ctx, testCid)
|
|
require.Error(suite.T(), err, "Expected context cancellation error")
|
|
assert.Nil(suite.T(), manifest, "Expected nil manifest on cancellation")
|
|
|
|
// Accept either canceled or deadline exceeded depending on timing
|
|
if !errors.Is(err, context.Canceled) && !errors.Is(err, context.DeadlineExceeded) {
|
|
// net/http may wrap the context error; check error string as a fallback
|
|
es := err.Error()
|
|
if !(es == context.Canceled.Error() || es == context.DeadlineExceeded.Error()) {
|
|
suite.T().Fatalf("expected context cancellation, got: %v", err)
|
|
}
|
|
}
|
|
|
|
buf := bytes.NewBuffer([]byte("Hello World!"))
|
|
if buf.Len() != manifest.DatasetSize {
|
|
suite.T().Errorf("expected size %d, got %d", buf.Len(), manifest.DatasetSize)
|
|
}
|
|
|
|
defaultBlockSize := 1024 * 64
|
|
if manifest.BlockSize != defaultBlockSize {
|
|
suite.T().Errorf("expected block size %d, got %d", defaultBlockSize, manifest.BlockSize)
|
|
}
|
|
|
|
if manifest.Filename != "test.txt" {
|
|
suite.T().Errorf("expected filename %q, got %q", "test.txt", manifest.Filename)
|
|
}
|
|
|
|
if manifest.Protected {
|
|
suite.T().Errorf("expected protected to be false, got true")
|
|
}
|
|
|
|
if manifest.Mimetype != "text/plain" {
|
|
suite.T().Errorf("expected mimetype %q, got %q", "text/plain", manifest.Mimetype)
|
|
}
|
|
|
|
if manifest.TreeCid == "" {
|
|
suite.T().Errorf("expected non-empty TreeCid")
|
|
}
|
|
}
|