Skip to content

Commit 685d89f

Browse files
committed
test: add comprehensive SDK multi-wallet test suite and utilities
1 parent 4c4c351 commit 685d89f

File tree

10 files changed

+41114
-0
lines changed

10 files changed

+41114
-0
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
block_worker: https://dev.zus.network/dns
2+
default_test_case_timeout: 45s
3+
signature_scheme: bls0chain
4+
chain_id: 0afc093ffb509f059c55478bc1a60351cef7b4e9c008a53a6cc8241ca8617dfe
5+
max_txn_query: 5
6+
query_sleep_time: 5
7+
min_submit: 10
8+
min_confirmation: 10
9+
# Test wallet mnemonics for multi-wallet testing
10+
test_wallet_mnemonics: "cactus panther essence ability copper fox wise actual need cousin boat uncover ride diamond group jacket anchor current float rely tragic omit child payment"

tests/sdk_tests/config/wallets.json

Lines changed: 40018 additions & 0 deletions
Large diffs are not rendered by default.

tests/sdk_tests/main_test.go

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package sdk_tests
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"log"
7+
"os"
8+
"path/filepath"
9+
"strconv"
10+
"testing"
11+
"time"
12+
13+
"runtime"
14+
15+
"github.com/0chain/gosdk/core/client"
16+
"github.com/0chain/gosdk/core/conf"
17+
18+
"github.com/0chain/system_test/internal/api/util/config"
19+
"github.com/0chain/system_test/internal/api/util/test"
20+
)
21+
22+
func TestMain(m *testing.M) {
23+
configPath, ok := os.LookupEnv(config.ConfigPathEnv)
24+
if !ok {
25+
configPath = "./config/sdk_tests_config.yaml"
26+
log.Printf("CONFIG_PATH environment variable is not set so has defaulted to [%v]", configPath)
27+
}
28+
29+
// Parse configuration
30+
parsedConfig = parseConfig(configPath)
31+
32+
defaultTestTimeout, err := time.ParseDuration(parsedConfig.DefaultTestTimeout)
33+
if err != nil {
34+
log.Printf("Default test case timeout could not be parsed so has defaulted to [%v]", test.DefaultTestTimeout)
35+
} else {
36+
test.DefaultTestTimeout = defaultTestTimeout
37+
test.SmokeTestMode, _ = strconv.ParseBool(os.Getenv("SMOKE_TEST_MODE"))
38+
log.Printf("Default test case timeout is [%v]", test.DefaultTestTimeout)
39+
}
40+
41+
42+
// t := test.NewSystemTest(new(testing.T))
43+
44+
// Initialize the SDK client
45+
// Initialize the SDK client
46+
err = client.Init(context.Background(), conf.Config{
47+
BlockWorker: parsedConfig.BlockWorker,
48+
SignatureScheme: parsedConfig.SignatureScheme,
49+
ChainID: parsedConfig.ChainID,
50+
MaxTxnQuery: parsedConfig.MaxTxnQuery,
51+
QuerySleepTime: parsedConfig.QuerySleepTime,
52+
MinSubmit: parsedConfig.MinSubmit,
53+
MinConfirmation: parsedConfig.MinConfirmation,
54+
})
55+
// require.NoError(t, err, "Failed to initialize SDK client")
56+
if err != nil {
57+
log.Printf("Failed to initialize SDK client: %v", err)
58+
runtime.Breakpoint() // Force debugger to pause
59+
os.Exit(1)
60+
}
61+
client.SetSdkInitialized(true)
62+
client.SetSignatureScheme(parsedConfig.SignatureScheme)
63+
64+
// Load wallet pool if available
65+
walletMutex.Lock()
66+
walletFilePath := filepath.Join(".", "config", "wallets.json")
67+
if _, err := os.Stat(walletFilePath); err == nil {
68+
fileContent, err := os.ReadFile(walletFilePath)
69+
if err != nil {
70+
log.Printf("Warning: Could not read wallets file: %v", err)
71+
} else {
72+
err = json.Unmarshal(fileContent, &initialisedWallets)
73+
if err != nil {
74+
log.Printf("Warning: Could not parse wallets file: %v", err)
75+
} else {
76+
log.Printf("Loaded %d wallets from pool", len(initialisedWallets))
77+
}
78+
}
79+
} else {
80+
log.Printf("No wallet pool found at %s, tests will create wallets as needed", walletFilePath)
81+
}
82+
walletMutex.Unlock()
83+
84+
os.Exit(m.Run())
85+
}
86+
87+
func parseConfig(configPath string) *SDKTestConfig {
88+
cfg := &SDKTestConfig{
89+
SignatureScheme: "bls0chain",
90+
ChainID: "0afc093ffb509f059c55478bc1a60351cef7b4e9c008a53a6cc8241ca8617dfe",
91+
MaxTxnQuery: 5,
92+
QuerySleepTime: 5,
93+
MinSubmit: 10,
94+
MinConfirmation: 10,
95+
DefaultTestTimeout: "45s",
96+
}
97+
98+
parsed := config.Parse(configPath)
99+
if parsed != nil {
100+
// Map common fields
101+
cfg.BlockWorker = parsed.BlockWorker
102+
cfg.DefaultTestTimeout = parsed.DefaultTestCaseTimeout
103+
}
104+
105+
return cfg
106+
}
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
package sdk_tests
2+
3+
import (
4+
"sync"
5+
"testing"
6+
7+
"github.com/0chain/gosdk/core/client"
8+
"github.com/0chain/system_test/internal/api/util/test"
9+
"github.com/stretchr/testify/require"
10+
)
11+
12+
func TestMultiWalletManagement(testSetup *testing.T) {
13+
t := test.NewSystemTest(testSetup)
14+
t.SetSmokeTests("Test multi-wallet management and edge cases")
15+
16+
t.Run("AddWallet and GetWalletByKey", func(t *test.SystemTest) {
17+
wallets, err := LoadWalletsFromPool(1)
18+
require.NoError(t, err)
19+
wallet := wallets[0]
20+
21+
err = AddWalletToSDK(t, wallet)
22+
require.NoError(t, err)
23+
24+
pubkey := GetWalletPublicKey(wallet)
25+
26+
// Verify wallet exists
27+
retrieved := client.GetWalletByKey(pubkey)
28+
require.NotNil(t, retrieved, "Wallet should exist after adding")
29+
require.Equal(t, wallet.ClientID, retrieved.ClientID)
30+
31+
t.Logf("Successfully verified AddWallet and GetWalletByKey")
32+
})
33+
34+
t.Run("Concurrent wallet operations", func(t *test.SystemTest) {
35+
wallets, err := LoadWalletsFromPool(5)
36+
require.NoError(t, err)
37+
38+
var wg sync.WaitGroup
39+
errors := make(chan error, len(wallets)*2)
40+
41+
// Concurrently add wallets
42+
for i, wallet := range wallets {
43+
wg.Add(1)
44+
go func(w *Wallet, idx int) {
45+
defer wg.Done()
46+
if err := AddWalletToSDK(t, w); err != nil {
47+
errors <- err
48+
}
49+
}(wallet, i)
50+
}
51+
52+
wg.Wait()
53+
close(errors)
54+
55+
// Check for errors
56+
for err := range errors {
57+
require.NoError(t, err, "Concurrent wallet addition should not error")
58+
}
59+
60+
// Verify all wallets are accessible
61+
for _, wallet := range wallets {
62+
pubkey := GetWalletPublicKey(wallet)
63+
retrieved := client.GetWalletByKey(pubkey)
64+
require.NotNil(t, retrieved, "Wallet should be retrievable after concurrent add")
65+
}
66+
67+
t.Logf("Successfully verified concurrent wallet operations")
68+
})
69+
70+
t.Run("GetWalletByKey with non-existent key", func(t *test.SystemTest) {
71+
fakeKey := "nonexistent_key_12345"
72+
retrieved := client.GetWalletByKey(fakeKey)
73+
require.Nil(t, retrieved, "GetWalletByKey should return nil for non-existent key")
74+
75+
t.Logf("Successfully verified non-existent key handling")
76+
})
77+
78+
t.Run("PublicKey lookup with specific key", func(t *test.SystemTest) {
79+
wallets, err := LoadWalletsFromPool(1)
80+
require.NoError(t, err)
81+
wallet := wallets[0]
82+
83+
err = AddWalletToSDK(t, wallet)
84+
require.NoError(t, err)
85+
86+
pubkey := GetWalletPublicKey(wallet)
87+
88+
// Lookup using the key
89+
retrievedKey := client.PublicKey(pubkey)
90+
require.Equal(t, wallet.ClientKey, retrievedKey, "PublicKey should return correct client key")
91+
92+
t.Logf("Successfully verified PublicKey lookup with specific key")
93+
})
94+
95+
t.Run("Id lookup with specific key", func(t *test.SystemTest) {
96+
wallets, err := LoadWalletsFromPool(1)
97+
require.NoError(t, err)
98+
wallet := wallets[0]
99+
100+
err = AddWalletToSDK(t, wallet)
101+
require.NoError(t, err)
102+
103+
pubkey := GetWalletPublicKey(wallet)
104+
105+
// Lookup using the key
106+
retrievedID := client.Id(pubkey)
107+
require.Equal(t, wallet.ClientID, retrievedID, "Id should return correct client ID")
108+
109+
t.Logf("Successfully verified Id lookup with specific key")
110+
})
111+
112+
t.Run("IsWalletSplit with specific key", func(t *test.SystemTest) {
113+
wallets, err := LoadWalletsFromPool(1)
114+
require.NoError(t, err)
115+
wallet := wallets[0]
116+
117+
err = AddWalletToSDK(t, wallet)
118+
require.NoError(t, err)
119+
120+
pubkey := GetWalletPublicKey(wallet)
121+
122+
isSplit, err := client.IsWalletSplit(pubkey)
123+
require.NoError(t, err)
124+
require.False(t, isSplit, "Test wallets should not be split-key wallets")
125+
126+
t.Logf("Successfully verified IsWalletSplit with specific key")
127+
})
128+
}
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
package sdk_tests
2+
3+
import (
4+
"os"
5+
"path/filepath"
6+
"testing"
7+
"time"
8+
9+
"github.com/0chain/gosdk/zboxcore/sdk"
10+
"github.com/0chain/system_test/internal/api/util/test"
11+
"github.com/stretchr/testify/require"
12+
)
13+
14+
func TestMultiWalletStorageOperations(testSetup *testing.T) {
15+
t := test.NewSystemTest(testSetup)
16+
t.SetSmokeTests("Test multi-wallet storage operations lifecycle")
17+
18+
t.Run("Full lifecycle: Create -> Upload -> Download with specific key", func(t *test.SystemTest) {
19+
20+
wallets, err := LoadWalletsFromPool(2)
21+
require.NoError(t, err)
22+
wallet := wallets[1] // Use second wallet
23+
24+
err = AddWalletToSDK(t, wallet)
25+
require.NoError(t, err)
26+
27+
key := GetWalletPublicKey(wallet)
28+
29+
// 1. Get Blobbers
30+
storageVersion := 2
31+
priceRange := sdk.PriceRange{Min: 0, Max: 10000000000}
32+
blobbers, err := sdk.GetAllocationBlobbers(storageVersion, 2, 2, 1024*1024, 0, priceRange, priceRange)
33+
if err != nil {
34+
t.Logf("Failed to get blobbers: %v. Skipping test.", err)
35+
return
36+
}
37+
require.NotEmpty(t, blobbers)
38+
39+
// 2. Create Allocation
40+
options := sdk.CreateAllocationOptions{
41+
DataShards: 2,
42+
ParityShards: 2,
43+
Size: 1024*1024,
44+
ReadPrice: sdk.PriceRange{Min: 0, Max: 10000000000},
45+
WritePrice: sdk.PriceRange{Min: 0, Max: 10000000000},
46+
Lock: 1000000000, // 1 ZCN
47+
BlobberIds: blobbers,
48+
AuthRoundExpiry: 100, // Ensure enough time
49+
}
50+
51+
hash, _, _, err := sdk.CreateAllocationWith(options, key)
52+
require.NoError(t, err)
53+
require.NotEmpty(t, hash)
54+
t.Logf("Allocation creation hash: %s", hash)
55+
56+
// 3. Wait for allocation to be visible
57+
var alloc *sdk.Allocation
58+
for i := 0; i < 15; i++ {
59+
time.Sleep(2 * time.Second)
60+
allocs, err := sdk.GetAllocations(key)
61+
if err == nil && len(allocs) > 0 {
62+
alloc = allocs[0]
63+
if alloc.Tx == hash {
64+
break
65+
}
66+
}
67+
}
68+
69+
if alloc == nil {
70+
t.Logf("Allocation not confirmed after waiting. Skipping upload/download verification.")
71+
return
72+
}
73+
t.Logf("Allocation confirmed. ID: %s", alloc.ID)
74+
75+
// Re-fetch allocation to ensure initialized
76+
alloc, err = sdk.GetAllocation(alloc.ID, key)
77+
require.NoError(t, err)
78+
79+
// 4. Create dummy file
80+
tmpDir := os.TempDir()
81+
tmpFile := filepath.Join(tmpDir, "upload_test.txt")
82+
err = os.WriteFile(tmpFile, []byte("Hello Multi-Wallet World"), 0644)
83+
require.NoError(t, err)
84+
defer os.Remove(tmpFile)
85+
86+
// 5. Upload file with secondary wallet
87+
remotePath := "/upload_test.txt"
88+
uploadErr := alloc.StartChunkedUpload(tmpDir, tmpFile, remotePath, nil, false, false, "", false, false, sdk.WithWallet(key))
89+
if uploadErr != nil {
90+
t.Logf("Upload failed: %v (may be expected if wallets not funded)", uploadErr)
91+
return
92+
}
93+
t.Logf("Successfully uploaded file to %s", remotePath)
94+
95+
// 6. Download file to verify
96+
downloadPath := filepath.Join(tmpDir, "download_test.txt")
97+
defer os.Remove(downloadPath)
98+
99+
downloadErr := alloc.DownloadFile(downloadPath, remotePath, false, nil, false)
100+
if downloadErr != nil {
101+
t.Logf("Download failed: %v", downloadErr)
102+
return
103+
}
104+
105+
// Verify content
106+
downloadedContent, err := os.ReadFile(downloadPath)
107+
require.NoError(t, err)
108+
require.Equal(t, "Hello Multi-Wallet World", string(downloadedContent),
109+
"Downloaded content should match uploaded content")
110+
111+
t.Logf("Successfully verified full storage lifecycle with secondary wallet")
112+
})
113+
}

0 commit comments

Comments
 (0)