mirror of
https://github.com/logos-storage/logos-storage-go.git
synced 2026-01-03 05:43:12 +00:00
converts CodexClient tests to also use testify
This commit is contained in:
parent
a72a1873c6
commit
2b2e21bb1b
@ -154,7 +154,7 @@ CODEX_API_PORT=8001 gotestsum --packages="./communities" -f standard-verbose --r
|
||||
or to run all integration tests:
|
||||
|
||||
```bash
|
||||
CODEX_API_PORT=8001 gotestsum --packages="./communities" -f standard-verbose --rerun-fails -- -tags=integration -v -count 1
|
||||
CODEX_API_PORT=8001 gotestsum --packages="./communities" -f standard-verbose --rerun-fails -- -tags=integration -v -count 1 -run Integration
|
||||
```
|
||||
|
||||
I prefer to be more selective when running integration tests.
|
||||
|
||||
@ -12,124 +12,111 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
"go-codex-client/communities"
|
||||
)
|
||||
|
||||
// This test exercises real network calls against a running Codex node.
|
||||
// It is disabled by default via the "integration" build tag.
|
||||
// Run with:
|
||||
//
|
||||
// go test -v -tags=integration ./communities -run Integration
|
||||
//
|
||||
// CodexClientIntegrationTestSuite demonstrates testify's suite functionality for CodexClient integration tests
|
||||
// These tests exercise real network calls against a running Codex node.
|
||||
// Required env vars (with defaults):
|
||||
//
|
||||
// CODEX_HOST (default: localhost)
|
||||
// CODEX_API_PORT (default: 8080)
|
||||
// CODEX_TIMEOUT_MS (optional; default: 60000)
|
||||
func TestIntegration_UploadAndDownload(t *testing.T) {
|
||||
host := getenv("CODEX_HOST", "localhost")
|
||||
port := getenv("CODEX_API_PORT", "8080")
|
||||
client := communities.NewCodexClient(host, port)
|
||||
// - CODEX_HOST (default: localhost)
|
||||
// - CODEX_API_PORT (default: 8080)
|
||||
// - CODEX_TIMEOUT_MS (optional; default: 60000)
|
||||
type CodexClientIntegrationTestSuite struct {
|
||||
suite.Suite
|
||||
client *communities.CodexClient
|
||||
host string
|
||||
port string
|
||||
}
|
||||
|
||||
// SetupSuite runs once before all tests in the suite
|
||||
func (suite *CodexClientIntegrationTestSuite) SetupSuite() {
|
||||
suite.host = getenv("CODEX_HOST", "localhost")
|
||||
suite.port = getenv("CODEX_API_PORT", "8080")
|
||||
suite.client = communities.NewCodexClient(suite.host, suite.port)
|
||||
|
||||
// Optional request timeout override
|
||||
if ms := os.Getenv("CODEX_TIMEOUT_MS"); ms != "" {
|
||||
if d, err := time.ParseDuration(ms + "ms"); err == nil {
|
||||
client.SetRequestTimeout(d)
|
||||
suite.client.SetRequestTimeout(d)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestCodexClientIntegrationTestSuite runs the integration test suite
|
||||
func TestCodexClientIntegrationTestSuite(t *testing.T) {
|
||||
suite.Run(t, new(CodexClientIntegrationTestSuite))
|
||||
}
|
||||
|
||||
func (suite *CodexClientIntegrationTestSuite) TestIntegration_UploadAndDownload() {
|
||||
// Generate random payload to ensure proper round-trip verification
|
||||
payload := make([]byte, 1024)
|
||||
if _, err := rand.Read(payload); err != nil {
|
||||
t.Fatalf("failed to generate random payload: %v", err)
|
||||
}
|
||||
t.Logf("Generated payload (first 32 bytes hex): %s", hex.EncodeToString(payload[:32]))
|
||||
_, err := rand.Read(payload)
|
||||
require.NoError(suite.T(), err, "failed to generate random payload")
|
||||
suite.T().Logf("Generated payload (first 32 bytes hex): %s", hex.EncodeToString(payload[:32]))
|
||||
|
||||
cid, err := client.Upload(bytes.NewReader(payload), "it.bin")
|
||||
if err != nil {
|
||||
t.Fatalf("upload failed: %v", err)
|
||||
}
|
||||
t.Logf("Upload successful, CID: %s", cid)
|
||||
cid, err := suite.client.Upload(bytes.NewReader(payload), "it.bin")
|
||||
require.NoError(suite.T(), err, "upload failed")
|
||||
suite.T().Logf("Upload successful, CID: %s", cid)
|
||||
|
||||
// Clean up after test
|
||||
defer func() {
|
||||
if err := client.RemoveCid(cid); err != nil {
|
||||
t.Logf("Warning: Failed to remove CID %s: %v", cid, err)
|
||||
if err := suite.client.RemoveCid(cid); err != nil {
|
||||
suite.T().Logf("Warning: Failed to remove CID %s: %v", cid, err)
|
||||
}
|
||||
}()
|
||||
|
||||
// Verify existence via HasCid
|
||||
exists, err := client.HasCid(cid)
|
||||
if err != nil {
|
||||
t.Fatalf("HasCid failed: %v", err)
|
||||
}
|
||||
if !exists {
|
||||
t.Fatalf("HasCid returned false for uploaded CID %s", cid)
|
||||
}
|
||||
t.Logf("HasCid confirmed existence of CID: %s", cid)
|
||||
exists, err := suite.client.HasCid(cid)
|
||||
require.NoError(suite.T(), err, "HasCid failed")
|
||||
assert.True(suite.T(), exists, "HasCid returned false for uploaded CID %s", cid)
|
||||
suite.T().Logf("HasCid confirmed existence of CID: %s", cid)
|
||||
|
||||
// Download via network stream with a context timeout to avoid hanging
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
defer cancel()
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := client.DownloadWithContext(ctx, cid, &buf); err != nil {
|
||||
t.Fatalf("download failed: %v", err)
|
||||
}
|
||||
if got := buf.Bytes(); !bytes.Equal(got, payload) {
|
||||
t.Fatalf("payload mismatch: got %q want %q", string(got), string(payload))
|
||||
}
|
||||
err = suite.client.DownloadWithContext(ctx, cid, &buf)
|
||||
require.NoError(suite.T(), err, "download failed")
|
||||
assert.Equal(suite.T(), payload, buf.Bytes(), "payload mismatch")
|
||||
}
|
||||
|
||||
func TestIntegration_CheckNonExistingCID(t *testing.T) {
|
||||
host := getenv("CODEX_HOST", "localhost")
|
||||
port := getenv("CODEX_API_PORT", "8080")
|
||||
client := communities.NewCodexClient(host, port)
|
||||
|
||||
func (suite *CodexClientIntegrationTestSuite) TestIntegration_CheckNonExistingCID() {
|
||||
// Generate random payload to ensure proper round-trip verification
|
||||
payload := make([]byte, 1024)
|
||||
if _, err := rand.Read(payload); err != nil {
|
||||
t.Fatalf("failed to generate random payload: %v", err)
|
||||
}
|
||||
t.Logf("Generated payload (first 32 bytes hex): %s", hex.EncodeToString(payload[:32]))
|
||||
_, err := rand.Read(payload)
|
||||
require.NoError(suite.T(), err, "failed to generate random payload")
|
||||
suite.T().Logf("Generated payload (first 32 bytes hex): %s", hex.EncodeToString(payload[:32]))
|
||||
|
||||
cid, err := client.Upload(bytes.NewReader(payload), "it.bin")
|
||||
if err != nil {
|
||||
t.Fatalf("upload failed: %v", err)
|
||||
}
|
||||
t.Logf("Upload successful, CID: %s", cid)
|
||||
cid, err := suite.client.Upload(bytes.NewReader(payload), "it.bin")
|
||||
require.NoError(suite.T(), err, "upload failed")
|
||||
suite.T().Logf("Upload successful, CID: %s", cid)
|
||||
|
||||
// Verify existence via HasCid
|
||||
exists, err := client.HasCid(cid)
|
||||
if err != nil {
|
||||
t.Fatalf("HasCid failed: %v", err)
|
||||
}
|
||||
if !exists {
|
||||
t.Fatalf("HasCid returned false for uploaded CID %s", cid)
|
||||
}
|
||||
t.Logf("HasCid confirmed existence of CID: %s", cid)
|
||||
exists, err := suite.client.HasCid(cid)
|
||||
require.NoError(suite.T(), err, "HasCid failed")
|
||||
assert.True(suite.T(), exists, "HasCid returned false for uploaded CID %s", cid)
|
||||
suite.T().Logf("HasCid confirmed existence of CID: %s", cid)
|
||||
|
||||
// Remove CID from Codex
|
||||
if err := client.RemoveCid(cid); err != nil {
|
||||
t.Fatalf("RemoveCid failed: %v", err)
|
||||
}
|
||||
t.Logf("RemoveCid confirmed deletion of CID: %s", cid)
|
||||
err = suite.client.RemoveCid(cid)
|
||||
require.NoError(suite.T(), err, "RemoveCid failed")
|
||||
suite.T().Logf("RemoveCid confirmed deletion of CID: %s", cid)
|
||||
|
||||
exists, err = client.HasCid(cid)
|
||||
if err != nil {
|
||||
t.Fatalf("HasCid failed: %v", err)
|
||||
}
|
||||
if exists {
|
||||
t.Fatalf("HasCid returned true for removed CID %s", cid)
|
||||
}
|
||||
t.Logf("HasCid confirmed CID is no longer present: %s", cid)
|
||||
exists, err = suite.client.HasCid(cid)
|
||||
require.NoError(suite.T(), err, "HasCid failed after removal")
|
||||
assert.False(suite.T(), exists, "HasCid returned true for removed CID %s", cid)
|
||||
suite.T().Logf("HasCid confirmed CID is no longer present: %s", cid)
|
||||
}
|
||||
|
||||
func TestIntegration_TriggerDownload(t *testing.T) {
|
||||
host := getenv("CODEX_HOST", "localhost")
|
||||
port := getenv("CODEX_API_PORT", "8001") // Use port 8001 as specified by user
|
||||
client := communities.NewCodexClient(host, port)
|
||||
|
||||
func (suite *CodexClientIntegrationTestSuite) TestIntegration_TriggerDownload() {
|
||||
// Use port 8001 for this test as specified
|
||||
client := communities.NewCodexClient(suite.host, "8001")
|
||||
|
||||
// Optional request timeout override
|
||||
if ms := os.Getenv("CODEX_TIMEOUT_MS"); ms != "" {
|
||||
if d, err := time.ParseDuration(ms + "ms"); err == nil {
|
||||
@ -139,31 +126,26 @@ func TestIntegration_TriggerDownload(t *testing.T) {
|
||||
|
||||
// Generate random payload to ensure proper round-trip verification
|
||||
payload := make([]byte, 1024)
|
||||
if _, err := rand.Read(payload); err != nil {
|
||||
t.Fatalf("failed to generate random payload: %v", err)
|
||||
}
|
||||
t.Logf("Generated payload (first 32 bytes hex): %s", hex.EncodeToString(payload[:32]))
|
||||
_, err := rand.Read(payload)
|
||||
require.NoError(suite.T(), err, "failed to generate random payload")
|
||||
suite.T().Logf("Generated payload (first 32 bytes hex): %s", hex.EncodeToString(payload[:32]))
|
||||
|
||||
// Upload the data
|
||||
cid, err := client.Upload(bytes.NewReader(payload), "local-download-test.bin")
|
||||
if err != nil {
|
||||
t.Fatalf("upload failed: %v", err)
|
||||
}
|
||||
t.Logf("Upload successful, CID: %s", cid)
|
||||
require.NoError(suite.T(), err, "upload failed")
|
||||
suite.T().Logf("Upload successful, CID: %s", cid)
|
||||
|
||||
// Clean up after test
|
||||
defer func() {
|
||||
if err := client.RemoveCid(cid); err != nil {
|
||||
t.Logf("Warning: Failed to remove CID %s: %v", cid, err)
|
||||
suite.T().Logf("Warning: Failed to remove CID %s: %v", cid, err)
|
||||
}
|
||||
}()
|
||||
|
||||
// Trigger async download
|
||||
manifest, err := client.TriggerDownload(cid)
|
||||
if err != nil {
|
||||
t.Fatalf("TriggerDownload failed: %v", err)
|
||||
}
|
||||
t.Logf("Async download triggered, manifest CID: %s", manifest.CID)
|
||||
require.NoError(suite.T(), err, "TriggerDownload failed")
|
||||
suite.T().Logf("Async download triggered, manifest CID: %s", manifest.CID)
|
||||
|
||||
// Poll HasCid for up to 10 seconds using goroutine and channel
|
||||
downloadComplete := make(chan bool, 1)
|
||||
@ -173,15 +155,15 @@ func TestIntegration_TriggerDownload(t *testing.T) {
|
||||
for range ticker.C {
|
||||
hasCid, err := client.HasCid(cid)
|
||||
if err != nil {
|
||||
t.Logf("HasCid check failed: %v", err)
|
||||
suite.T().Logf("HasCid check failed: %v", err)
|
||||
continue
|
||||
}
|
||||
if hasCid {
|
||||
t.Logf("CID is now available locally")
|
||||
suite.T().Logf("CID is now available locally")
|
||||
downloadComplete <- true
|
||||
return
|
||||
} else {
|
||||
t.Logf("CID not yet available locally, continuing to poll...")
|
||||
suite.T().Logf("CID not yet available locally, continuing to poll...")
|
||||
}
|
||||
}
|
||||
}()
|
||||
@ -191,7 +173,7 @@ func TestIntegration_TriggerDownload(t *testing.T) {
|
||||
case <-downloadComplete:
|
||||
// Download completed successfully
|
||||
case <-time.After(10 * time.Second):
|
||||
t.Fatalf("Timeout waiting for CID to be available locally after 10 seconds")
|
||||
suite.T().Fatalf("Timeout waiting for CID to be available locally after 10 seconds")
|
||||
}
|
||||
|
||||
// Now download the actual content from local storage and verify it matches
|
||||
@ -199,110 +181,73 @@ func TestIntegration_TriggerDownload(t *testing.T) {
|
||||
defer cancel()
|
||||
|
||||
var downloadBuf bytes.Buffer
|
||||
if err := client.LocalDownloadWithContext(ctx, cid, &downloadBuf); err != nil {
|
||||
t.Fatalf("LocalDownload after trigger download failed: %v", err)
|
||||
}
|
||||
err = client.LocalDownloadWithContext(ctx, cid, &downloadBuf)
|
||||
require.NoError(suite.T(), err, "LocalDownload after trigger download failed")
|
||||
|
||||
downloadedData := downloadBuf.Bytes()
|
||||
t.Logf("Downloaded data (first 32 bytes hex): %s", hex.EncodeToString(downloadedData[:32]))
|
||||
suite.T().Logf("Downloaded data (first 32 bytes hex): %s", hex.EncodeToString(downloadedData[:32]))
|
||||
|
||||
// Verify the data matches
|
||||
if !bytes.Equal(payload, downloadedData) {
|
||||
t.Errorf("Downloaded data does not match uploaded data")
|
||||
t.Errorf("Expected length: %d, got: %d", len(payload), len(downloadedData))
|
||||
}
|
||||
assert.Equal(suite.T(), payload, downloadedData, "Downloaded data does not match uploaded data")
|
||||
}
|
||||
|
||||
func TestIntegration_FetchManifest(t *testing.T) {
|
||||
host := getenv("CODEX_HOST", "localhost")
|
||||
port := getenv("CODEX_API_PORT", "8080")
|
||||
client := communities.NewCodexClient(host, port)
|
||||
|
||||
// Optional request timeout override
|
||||
if ms := os.Getenv("CODEX_TIMEOUT_MS"); ms != "" {
|
||||
if d, err := time.ParseDuration(ms + "ms"); err == nil {
|
||||
client.SetRequestTimeout(d)
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *CodexClientIntegrationTestSuite) TestIntegration_FetchManifest() {
|
||||
// Generate random payload to ensure proper round-trip verification
|
||||
payload := make([]byte, 1024)
|
||||
if _, err := rand.Read(payload); err != nil {
|
||||
t.Fatalf("failed to generate random payload: %v", err)
|
||||
}
|
||||
t.Logf("Generated payload (first 32 bytes hex): %s", hex.EncodeToString(payload[:32]))
|
||||
_, err := rand.Read(payload)
|
||||
require.NoError(suite.T(), err, "failed to generate random payload")
|
||||
suite.T().Logf("Generated payload (first 32 bytes hex): %s", hex.EncodeToString(payload[:32]))
|
||||
|
||||
cid, err := client.Upload(bytes.NewReader(payload), "fetch-manifest-test.bin")
|
||||
if err != nil {
|
||||
t.Fatalf("upload failed: %v", err)
|
||||
}
|
||||
t.Logf("Upload successful, CID: %s", cid)
|
||||
cid, err := suite.client.Upload(bytes.NewReader(payload), "fetch-manifest-test.bin")
|
||||
require.NoError(suite.T(), err, "upload failed")
|
||||
suite.T().Logf("Upload successful, CID: %s", cid)
|
||||
|
||||
// Clean up after test
|
||||
defer func() {
|
||||
if err := client.RemoveCid(cid); err != nil {
|
||||
t.Logf("Warning: Failed to remove CID %s: %v", cid, err)
|
||||
if err := suite.client.RemoveCid(cid); err != nil {
|
||||
suite.T().Logf("Warning: Failed to remove CID %s: %v", cid, err)
|
||||
}
|
||||
}()
|
||||
|
||||
// Verify existence via HasCid first
|
||||
exists, err := client.HasCid(cid)
|
||||
if err != nil {
|
||||
t.Fatalf("HasCid failed: %v", err)
|
||||
}
|
||||
if !exists {
|
||||
t.Fatalf("HasCid returned false for uploaded CID %s", cid)
|
||||
}
|
||||
t.Logf("HasCid confirmed existence of CID: %s", cid)
|
||||
exists, err := suite.client.HasCid(cid)
|
||||
require.NoError(suite.T(), err, "HasCid failed")
|
||||
assert.True(suite.T(), exists, "HasCid returned false for uploaded CID %s", cid)
|
||||
suite.T().Logf("HasCid confirmed existence of CID: %s", cid)
|
||||
|
||||
// Fetch manifest with context timeout
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
defer cancel()
|
||||
|
||||
manifest, err := client.FetchManifestWithContext(ctx, cid)
|
||||
if err != nil {
|
||||
t.Fatalf("FetchManifestWithContext failed: %v", err)
|
||||
}
|
||||
t.Logf("FetchManifest successful, manifest CID: %s", manifest.CID)
|
||||
manifest, err := suite.client.FetchManifestWithContext(ctx, cid)
|
||||
require.NoError(suite.T(), err, "FetchManifestWithContext failed")
|
||||
suite.T().Logf("FetchManifest successful, manifest CID: %s", manifest.CID)
|
||||
|
||||
// Verify manifest properties
|
||||
if manifest.CID != cid {
|
||||
t.Errorf("Manifest CID mismatch: expected %s, got %s", cid, manifest.CID)
|
||||
}
|
||||
assert.Equal(suite.T(), cid, manifest.CID, "Manifest CID mismatch")
|
||||
|
||||
// Verify manifest has expected fields
|
||||
if manifest.Manifest.TreeCid == "" {
|
||||
t.Error("Expected TreeCid to be non-empty")
|
||||
}
|
||||
t.Logf("Manifest TreeCid: %s", manifest.Manifest.TreeCid)
|
||||
assert.NotEmpty(suite.T(), manifest.Manifest.TreeCid, "Expected TreeCid to be non-empty")
|
||||
suite.T().Logf("Manifest TreeCid: %s", manifest.Manifest.TreeCid)
|
||||
|
||||
if manifest.Manifest.DatasetSize <= 0 {
|
||||
t.Errorf("Expected DatasetSize > 0, got %d", manifest.Manifest.DatasetSize)
|
||||
}
|
||||
t.Logf("Manifest DatasetSize: %d", manifest.Manifest.DatasetSize)
|
||||
assert.Greater(suite.T(), manifest.Manifest.DatasetSize, int64(0), "Expected DatasetSize > 0")
|
||||
suite.T().Logf("Manifest DatasetSize: %d", manifest.Manifest.DatasetSize)
|
||||
|
||||
if manifest.Manifest.BlockSize <= 0 {
|
||||
t.Errorf("Expected BlockSize > 0, got %d", manifest.Manifest.BlockSize)
|
||||
}
|
||||
t.Logf("Manifest BlockSize: %d", manifest.Manifest.BlockSize)
|
||||
assert.Greater(suite.T(), manifest.Manifest.BlockSize, 0, "Expected BlockSize > 0")
|
||||
suite.T().Logf("Manifest BlockSize: %d", manifest.Manifest.BlockSize)
|
||||
|
||||
if manifest.Manifest.Filename != "fetch-manifest-test.bin" {
|
||||
t.Errorf("Expected Filename 'fetch-manifest-test.bin', got '%s'", manifest.Manifest.Filename)
|
||||
}
|
||||
t.Logf("Manifest Filename: %s", manifest.Manifest.Filename)
|
||||
assert.Equal(suite.T(), "fetch-manifest-test.bin", manifest.Manifest.Filename, "Filename mismatch")
|
||||
suite.T().Logf("Manifest Filename: %s", manifest.Manifest.Filename)
|
||||
|
||||
// Log manifest details for verification
|
||||
t.Logf("Manifest Protected: %v", manifest.Manifest.Protected)
|
||||
t.Logf("Manifest Mimetype: %s", manifest.Manifest.Mimetype)
|
||||
suite.T().Logf("Manifest Protected: %v", manifest.Manifest.Protected)
|
||||
suite.T().Logf("Manifest Mimetype: %s", manifest.Manifest.Mimetype)
|
||||
|
||||
// Test fetching manifest for non-existent CID (should fail gracefully)
|
||||
nonExistentCID := "zDvZRwzmNonExistentCID123456789"
|
||||
_, err = client.FetchManifestWithContext(ctx, nonExistentCID)
|
||||
if err == nil {
|
||||
t.Error("Expected error when fetching manifest for non-existent CID, got nil")
|
||||
} else {
|
||||
t.Logf("Expected error for non-existent CID: %v", err)
|
||||
}
|
||||
_, err = suite.client.FetchManifestWithContext(ctx, nonExistentCID)
|
||||
assert.Error(suite.T(), err, "Expected error when fetching manifest for non-existent CID")
|
||||
suite.T().Logf("Expected error for non-existent CID: %v", err)
|
||||
}
|
||||
|
||||
func getenv(k, def string) string {
|
||||
|
||||
@ -8,16 +8,44 @@ import (
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
"go-codex-client/communities"
|
||||
)
|
||||
|
||||
func TestUpload_Success(t *testing.T) {
|
||||
// CodexClientTestSuite demonstrates testify's suite functionality for CodexClient tests
|
||||
type CodexClientTestSuite struct {
|
||||
suite.Suite
|
||||
client *communities.CodexClient
|
||||
server *httptest.Server
|
||||
}
|
||||
|
||||
// SetupTest runs before each test method
|
||||
func (suite *CodexClientTestSuite) SetupTest() {
|
||||
suite.client = communities.NewCodexClient("localhost", "8080")
|
||||
}
|
||||
|
||||
// TearDownTest runs after each test method
|
||||
func (suite *CodexClientTestSuite) TearDownTest() {
|
||||
if suite.server != nil {
|
||||
suite.server.Close()
|
||||
suite.server = nil
|
||||
}
|
||||
}
|
||||
|
||||
// TestCodexClientTestSuite runs the test suite
|
||||
func TestCodexClientTestSuite(t *testing.T) {
|
||||
suite.Run(t, new(CodexClientTestSuite))
|
||||
}
|
||||
|
||||
func (suite *CodexClientTestSuite) TestUpload_Success() {
|
||||
// Arrange a fake Codex server that validates headers and returns a CID
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
suite.server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
@ -47,29 +75,23 @@ func TestUpload_Success(t *testing.T) {
|
||||
// we add a newline to simulate real response
|
||||
_, _ = w.Write([]byte("zDvZRwzmTestCID123\n"))
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
client := communities.NewCodexClient("localhost", "8080")
|
||||
client.BaseURL = server.URL
|
||||
suite.client.BaseURL = suite.server.URL
|
||||
|
||||
// Act
|
||||
cid, err := client.Upload(bytes.NewReader([]byte("payload")), "hello.txt")
|
||||
cid, err := suite.client.Upload(bytes.NewReader([]byte("payload")), "hello.txt")
|
||||
|
||||
// Assert
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
require.NoError(suite.T(), err)
|
||||
// Codex uses CIDv1 with base58btc encoding (prefix: zDv)
|
||||
if cid != "zDvZRwzmTestCID123" {
|
||||
t.Fatalf("unexpected cid: %q", cid)
|
||||
}
|
||||
assert.Equal(suite.T(), "zDvZRwzmTestCID123", cid)
|
||||
}
|
||||
|
||||
func TestDownload_Success(t *testing.T) {
|
||||
func (suite *CodexClientTestSuite) TestDownload_Success() {
|
||||
const wantCID = "zDvZRwzm"
|
||||
const payload = "hello from codex"
|
||||
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
suite.server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
@ -82,24 +104,19 @@ func TestDownload_Success(t *testing.T) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, _ = w.Write([]byte(payload))
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
client := communities.NewCodexClient("localhost", "8080")
|
||||
client.BaseURL = server.URL
|
||||
suite.client.BaseURL = suite.server.URL
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := client.Download(wantCID, &buf); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if got := buf.String(); got != payload {
|
||||
t.Fatalf("unexpected payload: %q", got)
|
||||
}
|
||||
err := suite.client.Download(wantCID, &buf)
|
||||
require.NoError(suite.T(), err)
|
||||
assert.Equal(suite.T(), payload, buf.String())
|
||||
}
|
||||
|
||||
func TestDownloadWithContext_Cancel(t *testing.T) {
|
||||
func (suite *CodexClientTestSuite) TestDownloadWithContext_Cancel() {
|
||||
const cid = "zDvZRwzm"
|
||||
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
suite.server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path != "/api/codex/v1/data/"+cid+"/network/stream" {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
@ -124,29 +141,25 @@ func TestDownloadWithContext_Cancel(t *testing.T) {
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
client := communities.NewCodexClient("localhost", "8080")
|
||||
client.BaseURL = server.URL
|
||||
suite.client.BaseURL = suite.server.URL
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Millisecond)
|
||||
defer cancel()
|
||||
|
||||
err := client.DownloadWithContext(ctx, cid, io.Discard)
|
||||
if err == nil {
|
||||
t.Fatalf("expected cancellation error, got nil")
|
||||
}
|
||||
err := suite.client.DownloadWithContext(ctx, cid, io.Discard)
|
||||
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()) {
|
||||
t.Fatalf("expected context cancellation, got: %v", err)
|
||||
suite.T().Fatalf("expected context cancellation, got: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestHasCid_Success(t *testing.T) {
|
||||
func (suite *CodexClientTestSuite) TestHasCid_Success() {
|
||||
tests := []struct {
|
||||
name string
|
||||
cid string
|
||||
@ -158,8 +171,8 @@ func TestHasCid_Success(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
suite.Run(tt.name, func() {
|
||||
suite.server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path != "/api/codex/v1/data/"+tt.cid+"/exists" {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
@ -169,71 +182,52 @@ func TestHasCid_Success(t *testing.T) {
|
||||
// Return JSON: {"<cid>": <bool>}
|
||||
fmt.Fprintf(w, `{"%s": %t}`, tt.cid, tt.hasIt)
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
client := communities.NewCodexClient("localhost", "8080")
|
||||
client.BaseURL = server.URL
|
||||
suite.client.BaseURL = suite.server.URL
|
||||
|
||||
got, err := client.HasCid(tt.cid)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if got != tt.wantBool {
|
||||
t.Fatalf("HasCid(%q) = %v, want %v", tt.cid, got, tt.wantBool)
|
||||
}
|
||||
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 TestHasCid_RequestError(t *testing.T) {
|
||||
func (suite *CodexClientTestSuite) TestHasCid_RequestError() {
|
||||
// Create a server and immediately close it to trigger connection error
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
|
||||
server.Close() // Close immediately so connection fails
|
||||
suite.server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
|
||||
suite.server.Close() // Close immediately so connection fails
|
||||
|
||||
client := communities.NewCodexClient("localhost", "8080")
|
||||
client.BaseURL = server.URL // Use the closed server's URL
|
||||
suite.client.BaseURL = suite.server.URL // Use the closed server's URL
|
||||
|
||||
got, err := client.HasCid("zDvZRwzmTestCID")
|
||||
if err == nil {
|
||||
t.Fatal("expected error, got nil")
|
||||
}
|
||||
if got != false {
|
||||
t.Fatalf("expected false on error, got %v", got)
|
||||
}
|
||||
got, err := suite.client.HasCid("zDvZRwzmTestCID")
|
||||
require.Error(suite.T(), err)
|
||||
assert.False(suite.T(), got, "expected false on error")
|
||||
}
|
||||
|
||||
func TestHasCid_CidMismatch(t *testing.T) {
|
||||
func (suite *CodexClientTestSuite) TestHasCid_CidMismatch() {
|
||||
const requestCid = "zDvZRwzmRequestCID"
|
||||
const responseCid = "zDvZRwzmDifferentCID"
|
||||
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
suite.server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
// Return a different CID in the response
|
||||
fmt.Fprintf(w, `{"%s": true}`, responseCid)
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
client := communities.NewCodexClient("localhost", "8080")
|
||||
client.BaseURL = server.URL
|
||||
suite.client.BaseURL = suite.server.URL
|
||||
|
||||
got, err := client.HasCid(requestCid)
|
||||
if err == nil {
|
||||
t.Fatal("expected error for CID mismatch, got nil")
|
||||
}
|
||||
if got != false {
|
||||
t.Fatalf("expected false on CID mismatch, got %v", got)
|
||||
}
|
||||
got, err := suite.client.HasCid(requestCid)
|
||||
require.Error(suite.T(), err, "expected error for CID mismatch")
|
||||
assert.False(suite.T(), got, "expected false on CID mismatch")
|
||||
// Check error message mentions the missing/mismatched CID
|
||||
if !strings.Contains(err.Error(), requestCid) {
|
||||
t.Fatalf("error should mention request CID %q, got: %v", requestCid, err)
|
||||
}
|
||||
assert.Contains(suite.T(), err.Error(), requestCid, "error should mention request CID")
|
||||
}
|
||||
|
||||
func TestRemoveCid_Success(t *testing.T) {
|
||||
func (suite *CodexClientTestSuite) TestRemoveCid_Success() {
|
||||
const testCid = "zDvZRwzmTestCID"
|
||||
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
suite.server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodDelete {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
@ -245,40 +239,30 @@ func TestRemoveCid_Success(t *testing.T) {
|
||||
// DELETE should return 204 No Content
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
client := communities.NewCodexClient("localhost", "8080")
|
||||
client.BaseURL = server.URL
|
||||
suite.client.BaseURL = suite.server.URL
|
||||
|
||||
err := client.RemoveCid(testCid)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
err := suite.client.RemoveCid(testCid)
|
||||
require.NoError(suite.T(), err)
|
||||
}
|
||||
|
||||
func TestRemoveCid_Error(t *testing.T) {
|
||||
func (suite *CodexClientTestSuite) TestRemoveCid_Error() {
|
||||
const testCid = "zDvZRwzmTestCID"
|
||||
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
suite.server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// Return error status
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte("server error"))
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
client := communities.NewCodexClient("localhost", "8080")
|
||||
client.BaseURL = server.URL
|
||||
suite.client.BaseURL = suite.server.URL
|
||||
|
||||
err := client.RemoveCid(testCid)
|
||||
if err == nil {
|
||||
t.Fatal("expected error, got nil")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "500") {
|
||||
t.Fatalf("error should mention status 500, got: %v", err)
|
||||
}
|
||||
err := suite.client.RemoveCid(testCid)
|
||||
require.Error(suite.T(), err)
|
||||
assert.Contains(suite.T(), err.Error(), "500", "error should mention status 500")
|
||||
}
|
||||
|
||||
func TestTriggerDownload(t *testing.T) {
|
||||
func (suite *CodexClientTestSuite) TestTriggerDownload() {
|
||||
const testCid = "zDvZRwzmTestCID"
|
||||
const expectedManifest = `{
|
||||
"cid": "zDvZRwzmTestCID",
|
||||
@ -292,7 +276,7 @@ func TestTriggerDownload(t *testing.T) {
|
||||
}
|
||||
}`
|
||||
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
suite.server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
@ -305,105 +289,71 @@ func TestTriggerDownload(t *testing.T) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(expectedManifest))
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
client := communities.NewCodexClient("localhost", "8080")
|
||||
client.BaseURL = server.URL
|
||||
suite.client.BaseURL = suite.server.URL
|
||||
|
||||
ctx := context.Background()
|
||||
manifest, err := client.TriggerDownloadWithContext(ctx, testCid)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if manifest.CID != testCid {
|
||||
t.Fatalf("expected CID %q, got %q", testCid, manifest.CID)
|
||||
}
|
||||
if manifest.Manifest.TreeCid != "zDvZRwzmTreeCID" {
|
||||
t.Fatalf("expected TreeCid %q, got %q", "zDvZRwzmTreeCID", manifest.Manifest.TreeCid)
|
||||
}
|
||||
if manifest.Manifest.DatasetSize != 1024 {
|
||||
t.Fatalf("expected DatasetSize %d, got %d", 1024, manifest.Manifest.DatasetSize)
|
||||
}
|
||||
if manifest.Manifest.Filename != "test-file.bin" {
|
||||
t.Fatalf("expected Filename %q, got %q", "test-file.bin", manifest.Manifest.Filename)
|
||||
}
|
||||
manifest, err := suite.client.TriggerDownloadWithContext(ctx, testCid)
|
||||
require.NoError(suite.T(), err)
|
||||
assert.Equal(suite.T(), testCid, manifest.CID)
|
||||
assert.Equal(suite.T(), "zDvZRwzmTreeCID", manifest.Manifest.TreeCid)
|
||||
assert.Equal(suite.T(), int64(1024), manifest.Manifest.DatasetSize)
|
||||
assert.Equal(suite.T(), "test-file.bin", manifest.Manifest.Filename)
|
||||
}
|
||||
|
||||
func TestTriggerDownloadWithContext_RequestError(t *testing.T) {
|
||||
func (suite *CodexClientTestSuite) TestTriggerDownloadWithContext_RequestError() {
|
||||
// Create a server and immediately close it to trigger connection error
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
|
||||
server.Close()
|
||||
suite.server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
|
||||
suite.server.Close()
|
||||
|
||||
client := communities.NewCodexClient("localhost", "8080")
|
||||
client.BaseURL = server.URL
|
||||
suite.client.BaseURL = suite.server.URL
|
||||
|
||||
ctx := context.Background()
|
||||
manifest, err := client.TriggerDownloadWithContext(ctx, "zDvZRwzmRigWseNB7WqmudkKAPgZmrDCE9u5cY4KvCqhRo9Ki")
|
||||
if err == nil {
|
||||
t.Fatal("expected error, got nil")
|
||||
}
|
||||
if manifest != nil {
|
||||
t.Fatalf("expected nil manifest on error, got %v", manifest)
|
||||
}
|
||||
manifest, err := suite.client.TriggerDownloadWithContext(ctx, "zDvZRwzmRigWseNB7WqmudkKAPgZmrDCE9u5cY4KvCqhRo9Ki")
|
||||
require.Error(suite.T(), err)
|
||||
assert.Nil(suite.T(), manifest, "expected nil manifest on error")
|
||||
}
|
||||
|
||||
func TestTriggerDownloadWithContext_JSONParseError(t *testing.T) {
|
||||
func (suite *CodexClientTestSuite) TestTriggerDownloadWithContext_JSONParseError() {
|
||||
const testCid = "zDvZRwzmTestCID"
|
||||
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
suite.server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
// Return invalid JSON
|
||||
w.Write([]byte(`{"invalid": json}`))
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
client := communities.NewCodexClient("localhost", "8080")
|
||||
client.BaseURL = server.URL
|
||||
suite.client.BaseURL = suite.server.URL
|
||||
|
||||
ctx := context.Background()
|
||||
manifest, err := client.TriggerDownloadWithContext(ctx, testCid)
|
||||
if err == nil {
|
||||
t.Fatal("expected JSON parse error, got nil")
|
||||
}
|
||||
if manifest != nil {
|
||||
t.Fatalf("expected nil manifest on parse error, got %v", manifest)
|
||||
}
|
||||
if !strings.Contains(err.Error(), "failed to parse download manifest") {
|
||||
t.Fatalf("error should mention parse failure, got: %v", err)
|
||||
}
|
||||
manifest, err := suite.client.TriggerDownloadWithContext(ctx, testCid)
|
||||
require.Error(suite.T(), err, "expected JSON parse error")
|
||||
assert.Nil(suite.T(), manifest, "expected nil manifest on parse error")
|
||||
assert.Contains(suite.T(), err.Error(), "failed to parse download manifest", "error should mention parse failure")
|
||||
}
|
||||
|
||||
func TestTriggerDownloadWithContext_HTTPError(t *testing.T) {
|
||||
func (suite *CodexClientTestSuite) TestTriggerDownloadWithContext_HTTPError() {
|
||||
const testCid = "zDvZRwzmTestCID"
|
||||
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
suite.server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
w.Write([]byte("CID not found"))
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
client := communities.NewCodexClient("localhost", "8080")
|
||||
client.BaseURL = server.URL
|
||||
suite.client.BaseURL = suite.server.URL
|
||||
|
||||
ctx := context.Background()
|
||||
manifest, err := client.TriggerDownloadWithContext(ctx, testCid)
|
||||
if err == nil {
|
||||
t.Fatal("expected error for 404 status, got nil")
|
||||
}
|
||||
if manifest != nil {
|
||||
t.Fatalf("expected nil manifest on HTTP error, got %v", manifest)
|
||||
}
|
||||
if !strings.Contains(err.Error(), "404") {
|
||||
t.Fatalf("error should mention status 404, got: %v", err)
|
||||
}
|
||||
manifest, err := suite.client.TriggerDownloadWithContext(ctx, testCid)
|
||||
require.Error(suite.T(), err, "expected error for 404 status")
|
||||
assert.Nil(suite.T(), manifest, "expected nil manifest on HTTP error")
|
||||
assert.Contains(suite.T(), err.Error(), "404", "error should mention status 404")
|
||||
}
|
||||
|
||||
func TestTriggerDownloadWithContext_Cancellation(t *testing.T) {
|
||||
func (suite *CodexClientTestSuite) TestTriggerDownloadWithContext_Cancellation() {
|
||||
const testCid = "zDvZRwzmTestCID"
|
||||
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
suite.server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// Simulate slow response to allow cancellation
|
||||
select {
|
||||
case <-r.Context().Done():
|
||||
@ -414,177 +364,132 @@ func TestTriggerDownloadWithContext_Cancellation(t *testing.T) {
|
||||
w.Write([]byte(`{"cid": "test"}`))
|
||||
}
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
client := communities.NewCodexClient("localhost", "8080")
|
||||
client.BaseURL = server.URL
|
||||
suite.client.BaseURL = suite.server.URL
|
||||
|
||||
// Cancel after 50ms (before server responds)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
|
||||
defer cancel()
|
||||
|
||||
manifest, err := client.TriggerDownloadWithContext(ctx, testCid)
|
||||
if err == nil {
|
||||
t.Fatal("expected cancellation error, got nil")
|
||||
}
|
||||
if manifest != nil {
|
||||
t.Fatalf("expected nil manifest on cancellation, got %v", manifest)
|
||||
}
|
||||
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()) {
|
||||
t.Fatalf("expected context cancellation, got: %v", err)
|
||||
suite.T().Fatalf("expected context cancellation, got: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalDownload(t *testing.T) {
|
||||
func (suite *CodexClientTestSuite) TestLocalDownload() {
|
||||
testData := []byte("test data for local download")
|
||||
testCid := "zDvZRwzmTestCID"
|
||||
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
suite.server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// Verify request method and path
|
||||
if r.Method != "GET" {
|
||||
t.Errorf("Expected GET request, got %s", r.Method)
|
||||
}
|
||||
assert.Equal(suite.T(), "GET", r.Method, "Expected GET request")
|
||||
expectedPath := "/api/codex/v1/data/" + testCid
|
||||
if r.URL.Path != expectedPath {
|
||||
t.Errorf("Expected path %s, got %s", expectedPath, r.URL.Path)
|
||||
}
|
||||
assert.Equal(suite.T(), expectedPath, r.URL.Path, "Expected correct path")
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(testData)
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
client := communities.NewCodexClient("localhost", "8080")
|
||||
client.BaseURL = server.URL
|
||||
suite.client.BaseURL = suite.server.URL
|
||||
|
||||
var buf bytes.Buffer
|
||||
err := client.LocalDownload(testCid, &buf)
|
||||
if err != nil {
|
||||
t.Fatalf("LocalDownload failed: %v", err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(buf.Bytes(), testData) {
|
||||
t.Errorf("Downloaded data mismatch. Expected %q, got %q", string(testData), buf.String())
|
||||
}
|
||||
err := suite.client.LocalDownload(testCid, &buf)
|
||||
require.NoError(suite.T(), err, "LocalDownload failed")
|
||||
assert.Equal(suite.T(), testData, buf.Bytes(), "Downloaded data mismatch")
|
||||
}
|
||||
|
||||
func TestLocalDownloadWithContext_Success(t *testing.T) {
|
||||
func (suite *CodexClientTestSuite) TestLocalDownloadWithContext_Success() {
|
||||
testData := []byte("test data for local download with context")
|
||||
testCid := "zDvZRwzmTestCID"
|
||||
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
suite.server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// Verify request method and path
|
||||
if r.Method != "GET" {
|
||||
t.Errorf("Expected GET request, got %s", r.Method)
|
||||
}
|
||||
assert.Equal(suite.T(), "GET", r.Method, "Expected GET request")
|
||||
expectedPath := "/api/codex/v1/data/" + testCid
|
||||
if r.URL.Path != expectedPath {
|
||||
t.Errorf("Expected path %s, got %s", expectedPath, r.URL.Path)
|
||||
}
|
||||
assert.Equal(suite.T(), expectedPath, r.URL.Path, "Expected correct path")
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(testData)
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
client := communities.NewCodexClient("localhost", "8080")
|
||||
client.BaseURL = server.URL
|
||||
suite.client.BaseURL = suite.server.URL
|
||||
|
||||
ctx := context.Background()
|
||||
var buf bytes.Buffer
|
||||
err := client.LocalDownloadWithContext(ctx, testCid, &buf)
|
||||
if err != nil {
|
||||
t.Fatalf("LocalDownloadWithContext failed: %v", err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(buf.Bytes(), testData) {
|
||||
t.Errorf("Downloaded data mismatch. Expected %q, got %q", string(testData), buf.String())
|
||||
}
|
||||
err := suite.client.LocalDownloadWithContext(ctx, testCid, &buf)
|
||||
require.NoError(suite.T(), err, "LocalDownloadWithContext failed")
|
||||
assert.Equal(suite.T(), testData, buf.Bytes(), "Downloaded data mismatch")
|
||||
}
|
||||
|
||||
func TestLocalDownloadWithContext_RequestError(t *testing.T) {
|
||||
func (suite *CodexClientTestSuite) TestLocalDownloadWithContext_RequestError() {
|
||||
// Create a server and immediately close it to trigger connection error
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
|
||||
server.Close()
|
||||
suite.server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
|
||||
suite.server.Close()
|
||||
|
||||
client := communities.NewCodexClient("localhost", "8080")
|
||||
client.BaseURL = server.URL
|
||||
suite.client.BaseURL = suite.server.URL
|
||||
|
||||
ctx := context.Background()
|
||||
var buf bytes.Buffer
|
||||
err := client.LocalDownloadWithContext(ctx, "zDvZRwzmTestCID", &buf)
|
||||
if err == nil {
|
||||
t.Fatal("Expected error due to closed server, got nil")
|
||||
}
|
||||
|
||||
if !strings.Contains(err.Error(), "failed to download from codex") {
|
||||
t.Errorf("Expected 'failed to download from codex' in error, got: %v", err)
|
||||
}
|
||||
err := suite.client.LocalDownloadWithContext(ctx, "zDvZRwzmTestCID", &buf)
|
||||
require.Error(suite.T(), err, "Expected error due to closed server")
|
||||
assert.Contains(suite.T(), err.Error(), "failed to download from codex")
|
||||
}
|
||||
|
||||
func TestLocalDownloadWithContext_HTTPError(t *testing.T) {
|
||||
func (suite *CodexClientTestSuite) TestLocalDownloadWithContext_HTTPError() {
|
||||
testCid := "zDvZRwzmTestCID"
|
||||
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
suite.server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
w.Write([]byte("CID not found in local storage"))
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
client := communities.NewCodexClient("localhost", "8080")
|
||||
client.BaseURL = server.URL
|
||||
suite.client.BaseURL = suite.server.URL
|
||||
|
||||
ctx := context.Background()
|
||||
var buf bytes.Buffer
|
||||
err := client.LocalDownloadWithContext(ctx, testCid, &buf)
|
||||
if err == nil {
|
||||
t.Fatal("Expected error for HTTP 404, got nil")
|
||||
}
|
||||
|
||||
if !strings.Contains(err.Error(), "404") {
|
||||
t.Errorf("Expected '404' in error message, got: %v", err)
|
||||
}
|
||||
err := suite.client.LocalDownloadWithContext(ctx, testCid, &buf)
|
||||
require.Error(suite.T(), err, "Expected error for HTTP 404")
|
||||
assert.Contains(suite.T(), err.Error(), "404", "Expected '404' in error message")
|
||||
}
|
||||
|
||||
func TestLocalDownloadWithContext_Cancellation(t *testing.T) {
|
||||
func (suite *CodexClientTestSuite) TestLocalDownloadWithContext_Cancellation() {
|
||||
testCid := "zDvZRwzmTestCID"
|
||||
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
suite.server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// Simulate a slow response
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte("slow response"))
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
client := communities.NewCodexClient("localhost", "8080")
|
||||
client.BaseURL = server.URL
|
||||
suite.client.BaseURL = suite.server.URL
|
||||
|
||||
// Create a context with a very short timeout
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond)
|
||||
defer cancel()
|
||||
|
||||
var buf bytes.Buffer
|
||||
err := client.LocalDownloadWithContext(ctx, testCid, &buf)
|
||||
if err == nil {
|
||||
t.Fatal("Expected context cancellation error, got nil")
|
||||
}
|
||||
err := suite.client.LocalDownloadWithContext(ctx, testCid, &buf)
|
||||
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()) {
|
||||
t.Fatalf("expected context cancellation, got: %v", err)
|
||||
suite.T().Fatalf("expected context cancellation, got: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFetchManifestWithContext_Success(t *testing.T) {
|
||||
func (suite *CodexClientTestSuite) TestFetchManifestWithContext_Success() {
|
||||
testCid := "zDvZRwzmTestCID"
|
||||
expectedManifest := `{
|
||||
"cid": "zDvZRwzmTestCID",
|
||||
@ -598,173 +503,108 @@ func TestFetchManifestWithContext_Success(t *testing.T) {
|
||||
}
|
||||
}`
|
||||
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
suite.server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(suite.T(), http.MethodGet, r.Method)
|
||||
expectedPath := fmt.Sprintf("/api/codex/v1/data/%s/network/manifest", testCid)
|
||||
if r.URL.Path != expectedPath {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
assert.Equal(suite.T(), expectedPath, r.URL.Path)
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(expectedManifest))
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
client := communities.NewCodexClient("localhost", "8080")
|
||||
client.BaseURL = server.URL
|
||||
suite.client.BaseURL = suite.server.URL
|
||||
|
||||
ctx := context.Background()
|
||||
manifest, err := client.FetchManifestWithContext(ctx, testCid)
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got: %v", err)
|
||||
}
|
||||
manifest, err := suite.client.FetchManifestWithContext(ctx, testCid)
|
||||
require.NoError(suite.T(), err, "Expected no error")
|
||||
require.NotNil(suite.T(), manifest, "Expected manifest, got nil")
|
||||
|
||||
if manifest == nil {
|
||||
t.Fatal("Expected manifest, got nil")
|
||||
}
|
||||
|
||||
if manifest.CID != testCid {
|
||||
t.Errorf("Expected CID %s, got %s", testCid, manifest.CID)
|
||||
}
|
||||
|
||||
if manifest.Manifest.TreeCid != "zDvZRwzmTreeCID123" {
|
||||
t.Errorf("Expected TreeCid %s, got %s", "zDvZRwzmTreeCID123", manifest.Manifest.TreeCid)
|
||||
}
|
||||
|
||||
if manifest.Manifest.DatasetSize != 1024 {
|
||||
t.Errorf("Expected DatasetSize %d, got %d", 1024, manifest.Manifest.DatasetSize)
|
||||
}
|
||||
|
||||
if manifest.Manifest.BlockSize != 256 {
|
||||
t.Errorf("Expected BlockSize %d, got %d", 256, manifest.Manifest.BlockSize)
|
||||
}
|
||||
|
||||
if !manifest.Manifest.Protected {
|
||||
t.Error("Expected Protected to be true, got false")
|
||||
}
|
||||
|
||||
if manifest.Manifest.Filename != "test-file.bin" {
|
||||
t.Errorf("Expected Filename %s, got %s", "test-file.bin", manifest.Manifest.Filename)
|
||||
}
|
||||
|
||||
if manifest.Manifest.Mimetype != "application/octet-stream" {
|
||||
t.Errorf("Expected Mimetype %s, got %s", "application/octet-stream", manifest.Manifest.Mimetype)
|
||||
}
|
||||
assert.Equal(suite.T(), testCid, manifest.CID)
|
||||
assert.Equal(suite.T(), "zDvZRwzmTreeCID123", manifest.Manifest.TreeCid)
|
||||
assert.Equal(suite.T(), int64(1024), manifest.Manifest.DatasetSize)
|
||||
assert.Equal(suite.T(), 256, manifest.Manifest.BlockSize)
|
||||
assert.True(suite.T(), manifest.Manifest.Protected, "Expected Protected to be true")
|
||||
assert.Equal(suite.T(), "test-file.bin", manifest.Manifest.Filename)
|
||||
assert.Equal(suite.T(), "application/octet-stream", manifest.Manifest.Mimetype)
|
||||
}
|
||||
|
||||
func TestFetchManifestWithContext_RequestError(t *testing.T) {
|
||||
func (suite *CodexClientTestSuite) TestFetchManifestWithContext_RequestError() {
|
||||
// Create a server and immediately close it to trigger connection error
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
|
||||
server.Close()
|
||||
suite.server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
|
||||
suite.server.Close()
|
||||
|
||||
client := communities.NewCodexClient("localhost", "8080")
|
||||
client.BaseURL = server.URL
|
||||
suite.client.BaseURL = suite.server.URL
|
||||
|
||||
ctx := context.Background()
|
||||
manifest, err := client.FetchManifestWithContext(ctx, "test-cid")
|
||||
if err == nil {
|
||||
t.Fatal("Expected error for closed server, got nil")
|
||||
}
|
||||
if manifest != nil {
|
||||
t.Fatal("Expected nil manifest on error, got non-nil")
|
||||
}
|
||||
|
||||
if !strings.Contains(err.Error(), "failed to fetch manifest from codex") {
|
||||
t.Errorf("Expected 'failed to fetch manifest from codex' in error message, got: %v", err)
|
||||
}
|
||||
manifest, err := suite.client.FetchManifestWithContext(ctx, "test-cid")
|
||||
require.Error(suite.T(), err, "Expected error for closed server")
|
||||
assert.Nil(suite.T(), manifest, "Expected nil manifest on error")
|
||||
assert.Contains(suite.T(), err.Error(), "failed to fetch manifest from codex")
|
||||
}
|
||||
|
||||
func TestFetchManifestWithContext_HTTPError(t *testing.T) {
|
||||
func (suite *CodexClientTestSuite) TestFetchManifestWithContext_HTTPError() {
|
||||
testCid := "zDvZRwzmTestCID"
|
||||
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
suite.server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
w.Write([]byte("Manifest not found"))
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
client := communities.NewCodexClient("localhost", "8080")
|
||||
client.BaseURL = server.URL
|
||||
suite.client.BaseURL = suite.server.URL
|
||||
|
||||
ctx := context.Background()
|
||||
manifest, err := client.FetchManifestWithContext(ctx, testCid)
|
||||
if err == nil {
|
||||
t.Fatal("Expected error for HTTP 404, got nil")
|
||||
}
|
||||
if manifest != nil {
|
||||
t.Fatal("Expected nil manifest on error, got non-nil")
|
||||
}
|
||||
|
||||
if !strings.Contains(err.Error(), "404") {
|
||||
t.Errorf("Expected '404' in error message, got: %v", err)
|
||||
}
|
||||
manifest, err := suite.client.FetchManifestWithContext(ctx, testCid)
|
||||
require.Error(suite.T(), err, "Expected error for HTTP 404")
|
||||
assert.Nil(suite.T(), manifest, "Expected nil manifest on error")
|
||||
assert.Contains(suite.T(), err.Error(), "404", "Expected '404' in error message")
|
||||
}
|
||||
|
||||
func TestFetchManifestWithContext_JSONParseError(t *testing.T) {
|
||||
func (suite *CodexClientTestSuite) TestFetchManifestWithContext_JSONParseError() {
|
||||
testCid := "zDvZRwzmTestCID"
|
||||
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
suite.server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte("invalid json {"))
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
client := communities.NewCodexClient("localhost", "8080")
|
||||
client.BaseURL = server.URL
|
||||
suite.client.BaseURL = suite.server.URL
|
||||
|
||||
ctx := context.Background()
|
||||
manifest, err := client.FetchManifestWithContext(ctx, testCid)
|
||||
if err == nil {
|
||||
t.Fatal("Expected error for invalid JSON, got nil")
|
||||
}
|
||||
if manifest != nil {
|
||||
t.Fatal("Expected nil manifest on JSON parse error, got non-nil")
|
||||
}
|
||||
|
||||
if !strings.Contains(err.Error(), "failed to parse manifest") {
|
||||
t.Errorf("Expected 'failed to parse manifest' in error message, got: %v", err)
|
||||
}
|
||||
manifest, err := suite.client.FetchManifestWithContext(ctx, testCid)
|
||||
require.Error(suite.T(), err, "Expected error for invalid JSON")
|
||||
assert.Nil(suite.T(), manifest, "Expected nil manifest on JSON parse error")
|
||||
assert.Contains(suite.T(), err.Error(), "failed to parse manifest", "Expected 'failed to parse manifest' in error message")
|
||||
}
|
||||
|
||||
func TestFetchManifestWithContext_Cancellation(t *testing.T) {
|
||||
func (suite *CodexClientTestSuite) TestFetchManifestWithContext_Cancellation() {
|
||||
testCid := "zDvZRwzmTestCID"
|
||||
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
suite.server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// Simulate a slow response
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(`{"cid": "test"}`))
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
client := communities.NewCodexClient("localhost", "8080")
|
||||
client.BaseURL = server.URL
|
||||
suite.client.BaseURL = suite.server.URL
|
||||
|
||||
// Create a context with a very short timeout
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond)
|
||||
defer cancel()
|
||||
|
||||
manifest, err := client.FetchManifestWithContext(ctx, testCid)
|
||||
if err == nil {
|
||||
t.Fatal("Expected context cancellation error, got nil")
|
||||
}
|
||||
if manifest != nil {
|
||||
t.Fatal("Expected nil manifest on cancellation, got non-nil")
|
||||
}
|
||||
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()) {
|
||||
t.Fatalf("expected context cancellation, got: %v", err)
|
||||
suite.T().Fatalf("expected context cancellation, got: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user