package netts import ( "context" "io" "net/http" "net/http/httptest" "testing" "time" appconfig "github.com/D36u99er/bc-netts-energy/internal/config" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "log/slog" ) func TestClientAnalyzeUSDT(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { switch r.URL.Path { case "/apiv2/usdt/analyze": assert.Equal(t, http.MethodPost, r.Method) assert.Equal(t, "test-key", r.Header.Get("X-API-KEY")) _, err := io.ReadAll(r.Body) require.NoError(t, err) w.Header().Set("Content-Type", "application/json") _, _ = w.Write([]byte(`{ "code": 0, "msg": "ok", "data": { "transfer_details": { "sender_address": "TFrom", "receiver_address": "TTo", "usdt_amount": "10.00", "recommended_energy": 131000, "energy_needed": 131000, "bandwidth_needed": 350, "cost_breakdown": { "energy_cost": "3.5", "bandwidth_cost": "1.0", "total_cost_trx": "4.5" }, "savings_analysis": { "vs_direct_burn": "20.0", "vs_staking": "5.0", "savings_percentage": 80.5 } } } }`)) default: w.WriteHeader(http.StatusNotFound) } })) defer server.Close() client := newTestClient(server, t) resp, err := client.AnalyzeUSDT(context.Background(), AnalyzeUSDTRequest{ Sender: "TFrom", Receiver: "TTo", Amount: "10.00", }) require.NoError(t, err) assert.Equal(t, 131000, resp.TransferDetails.RecommendedEnergy) assert.Equal(t, 131000, resp.TransferDetails.EnergyNeeded) assert.InDelta(t, 80.5, resp.TransferDetails.SavingsAnalysis.SavingsPercentage, 0.01) } func TestClientGetAddressStatus(t *testing.T) { calls := 0 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { switch r.URL.Path { case "/apiv2/time/status/TExists": if calls == 0 { w.Header().Set("Content-Type", "application/json") _, _ = w.Write([]byte(`{ "code": 0, "msg": "ok", "data": { "address": "TExists", "mode": "normal", "status": "active", "cycles_remaining": 2, "open_orders": 0, "expiry_time": 1700000000 } }`)) } calls++ case "/apiv2/time/status/TMissing": w.Header().Set("Content-Type", "application/json") _, _ = w.Write([]byte(`{ "code": -1, "msg": "Address not found in Host Mode", "data": null }`)) default: t.Fatalf("unexpected path %s", r.URL.Path) } })) defer server.Close() client := newTestClient(server, t) status, err := client.GetAddressStatus(context.Background(), "TExists") require.NoError(t, err) assert.Equal(t, 2, status.CyclesRemaining) _, err = client.GetAddressStatus(context.Background(), "TMissing") require.Error(t, err) assert.ErrorIs(t, err, ErrAddressNotFound) } func TestClientMutations(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { switch r.URL.Path { case "/apiv2/time/add": w.Header().Set("Content-Type", "application/json") _, _ = w.Write([]byte(`{ "code": 0, "msg": "Address added", "data": { "address": "TAdded", "callback_url": "https://callback", "timestamp": "2024-01-01T00:00:00Z" } }`)) case "/apiv2/time/order": w.Header().Set("Content-Type", "application/json") _, _ = w.Write([]byte(`{ "code": 0, "msg": "ok", "data": { "address": "TAdded", "cycles_purchased": 5, "total_cycles": 8, "previous_cycles": 3, "total_cost": 10.5, "price_per_cycle": 2.1, "order_id": "ORD-1", "transaction_hash": "hash", "payment_method": "account_balance", "balance_after": 100.5, "next_delegation_time": 1700000000, "expiry_time": 1700100000, "status": "confirmed" } }`)) default: w.WriteHeader(http.StatusNotFound) } })) defer server.Close() client := newTestClient(server, t) addResp, err := client.AddHostAddress(context.Background(), "TAdded", "https://callback") require.NoError(t, err) assert.Equal(t, "TAdded", addResp.Address) orderResp, err := client.OrderCycles(context.Background(), "TAdded", 5) require.NoError(t, err) assert.Equal(t, 5, orderResp.CyclesPurchased) assert.Equal(t, "ORD-1", orderResp.OrderID) } func newTestClient(server *httptest.Server, t *testing.T) *Client { t.Helper() cfg := appconfig.NettsConfig{ APIKey: "test-key", BaseURL: server.URL, HTTPTimeout: appconfig.Duration(5 * time.Second), Retry: appconfig.Retry{ MaxAttempts: 1, }, } logger := slog.New(slog.NewTextHandler(io.Discard, &slog.HandlerOptions{Level: slog.LevelDebug})) httpClient := server.Client() return New(cfg, logger, httpClient) }