mirror of
https://github.com/logos-storage/logos-storage-go.git
synced 2026-01-02 13:23:11 +00:00
239 lines
8.7 KiB
Go
239 lines
8.7 KiB
Go
//go:build codex_integration
|
|
// +build codex_integration
|
|
|
|
package codexclient_test
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"crypto/rand"
|
|
"encoding/hex"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/codex-storage/codex-go-bindings/codex"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"github.com/stretchr/testify/suite"
|
|
|
|
"go-codex-client/codexclient"
|
|
"go-codex-client/codextestutils"
|
|
"go-codex-client/communities"
|
|
)
|
|
|
|
// CodexClientIntegrationTestSuite demonstrates testify's suite functionality for CodexClient integration tests
|
|
type CodexClientIntegrationTestSuite struct {
|
|
suite.Suite
|
|
client communities.CodexClientInterface
|
|
}
|
|
|
|
// SetupSuite runs once before all tests in the suite
|
|
func (suite *CodexClientIntegrationTestSuite) SetupSuite() {
|
|
var err error
|
|
suite.client, err = codexclient.NewCodexClient(codex.Config{
|
|
DataDir: suite.T().TempDir(),
|
|
LogFormat: codex.LogFormatNoColors,
|
|
MetricsEnabled: false,
|
|
BlockRetries: 5,
|
|
})
|
|
if err != nil {
|
|
suite.T().Fatalf("Failed to create Codex client: %v", err)
|
|
}
|
|
}
|
|
|
|
// 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)
|
|
_, 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 := 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 := suite.client.RemoveCid(cid); err != nil {
|
|
suite.T().Logf("Warning: Failed to remove CID %s: %v", cid, err)
|
|
}
|
|
}()
|
|
|
|
// Verify existence via HasCid
|
|
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
|
|
err = suite.client.DownloadWithContext(ctx, cid, &buf)
|
|
require.NoError(suite.T(), err, "download failed")
|
|
assert.Equal(suite.T(), payload, buf.Bytes(), "payload mismatch")
|
|
}
|
|
|
|
func (suite *CodexClientIntegrationTestSuite) TestIntegration_CheckNonExistingCID() {
|
|
// Generate random payload to ensure proper round-trip verification
|
|
payload := make([]byte, 1024)
|
|
_, 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 := 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 := 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
|
|
err = suite.client.RemoveCid(cid)
|
|
require.NoError(suite.T(), err, "RemoveCid failed")
|
|
suite.T().Logf("RemoveCid confirmed deletion of CID: %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 (suite *CodexClientIntegrationTestSuite) TestIntegration_TriggerDownload() {
|
|
client := codextestutils.NewCodexClientTest(suite.T())
|
|
|
|
// Generate random payload to ensure proper round-trip verification
|
|
payload := make([]byte, 1024)
|
|
_, 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")
|
|
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 {
|
|
suite.T().Logf("Warning: Failed to remove CID %s: %v", cid, err)
|
|
}
|
|
}()
|
|
|
|
// Trigger async download
|
|
manifest, err := client.TriggerDownload(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)
|
|
go func() {
|
|
ticker := time.NewTicker(500 * time.Millisecond)
|
|
defer ticker.Stop()
|
|
for range ticker.C {
|
|
hasCid, err := client.HasCid(cid)
|
|
if err != nil {
|
|
suite.T().Logf("HasCid check failed: %v", err)
|
|
continue
|
|
}
|
|
if hasCid {
|
|
suite.T().Logf("CID is now available locally")
|
|
downloadComplete <- true
|
|
return
|
|
} else {
|
|
suite.T().Logf("CID not yet available locally, continuing to poll...")
|
|
}
|
|
}
|
|
}()
|
|
|
|
// Wait for download completion or timeout
|
|
select {
|
|
case <-downloadComplete:
|
|
// Download completed successfully
|
|
case <-time.After(10 * time.Second):
|
|
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
|
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
|
defer cancel()
|
|
|
|
var downloadBuf bytes.Buffer
|
|
err = client.LocalDownloadWithContext(ctx, cid, &downloadBuf)
|
|
require.NoError(suite.T(), err, "LocalDownload after trigger download failed")
|
|
|
|
downloadedData := downloadBuf.Bytes()
|
|
suite.T().Logf("Downloaded data (first 32 bytes hex): %s", hex.EncodeToString(downloadedData[:32]))
|
|
|
|
// Verify the data matches
|
|
assert.Equal(suite.T(), payload, downloadedData, "Downloaded data does not match uploaded data")
|
|
}
|
|
|
|
func (suite *CodexClientIntegrationTestSuite) TestIntegration_FetchManifest() {
|
|
// Generate random payload to ensure proper round-trip verification
|
|
payload := make([]byte, 1024)
|
|
_, 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 := 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 := 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 := 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 := 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
|
|
assert.Equal(suite.T(), cid, manifest.Cid, "Manifest CID mismatch")
|
|
|
|
// Verify manifest has expected fields
|
|
assert.NotEmpty(suite.T(), manifest.TreeCid, "Expected TreeCid to be non-empty")
|
|
suite.T().Logf("Manifest TreeCid: %s", manifest.TreeCid)
|
|
|
|
assert.Greater(suite.T(), manifest.DatasetSize, 0, "Expected DatasetSize > 0")
|
|
suite.T().Logf("Manifest DatasetSize: %d", manifest.DatasetSize)
|
|
|
|
assert.Greater(suite.T(), manifest.BlockSize, 0, "Expected BlockSize > 0")
|
|
suite.T().Logf("Manifest BlockSize: %d", manifest.BlockSize)
|
|
|
|
assert.Equal(suite.T(), "fetch-manifest-test.bin", manifest.Filename, "Filename mismatch")
|
|
suite.T().Logf("Manifest Filename: %s", manifest.Filename)
|
|
|
|
// Log manifest details for verification
|
|
suite.T().Logf("Manifest Protected: %v", manifest.Protected)
|
|
suite.T().Logf("Manifest Mimetype: %s", manifest.Mimetype)
|
|
|
|
// Test fetching manifest for non-existent CID (should fail gracefully)
|
|
nonExistentCID := "zDvZRwzmNonExistentCID123456789"
|
|
_, 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)
|
|
}
|