184 lines
4.9 KiB
Go
184 lines
4.9 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"testing"
|
|
"time"
|
|
|
|
appconfig "github.com/D36u99er/bc-netts-energy/internal/config"
|
|
"github.com/D36u99er/bc-netts-energy/internal/netts"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"log/slog"
|
|
)
|
|
|
|
func TestEnsureEnergyAddsAddressAndOrdersCycles(t *testing.T) {
|
|
mock := &mockNettsClient{
|
|
analyzeData: &netts.AnalyzeUSDTData{
|
|
TransferDetails: netts.TransferDetails{
|
|
RecommendedEnergy: 131000,
|
|
EnergyNeeded: 131000,
|
|
},
|
|
},
|
|
statusResponses: []statusResponse{
|
|
{err: netts.ErrAddressNotFound},
|
|
{status: &netts.AddressStatus{CyclesRemaining: 2}},
|
|
{status: &netts.AddressStatus{CyclesRemaining: 5}},
|
|
},
|
|
orderResult: &netts.OrderResult{
|
|
CyclesPurchased: 3,
|
|
TotalCycles: 5,
|
|
OrderID: "ORD-123",
|
|
Status: "confirmed",
|
|
TotalCost: 7.5,
|
|
},
|
|
}
|
|
|
|
cfg := appconfig.EnergyConfig{
|
|
AutoAddHost: true,
|
|
MinCycles: 3,
|
|
TargetCycles: 5,
|
|
PostOrderWait: appconfig.Duration(0),
|
|
DefaultAnalyzeValue: "100.00",
|
|
}
|
|
|
|
logger := slog.New(slog.NewTextHandler(ioDiscard{}, &slog.HandlerOptions{Level: slog.LevelDebug}))
|
|
svc := NewEnergyService(cfg, mock, logger)
|
|
|
|
resp, err := svc.EnsureEnergy(context.Background(), EnsureEnergyRequest{
|
|
FromAddress: "TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE",
|
|
ToAddress: "TUmyHQNzAkT6SrwThVvay7G4yfGZAyWhmy",
|
|
Amount: "50.0",
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
assert.True(t, resp.AddressAdded)
|
|
assert.Equal(t, 3, resp.CyclesPurchased)
|
|
assert.Equal(t, 5, resp.CyclesAfter)
|
|
assert.Equal(t, "ORD-123", resp.OrderID)
|
|
assert.Equal(t, 131000, resp.RecommendedEnergy)
|
|
assert.Equal(t, 131000, resp.EnergyNeeded)
|
|
|
|
assert.Equal(t, 1, mock.addCalls)
|
|
assert.Equal(t, []int{3}, mock.orderCalls)
|
|
assert.Equal(t, 0, len(mock.statusResponses))
|
|
}
|
|
|
|
func TestEnsureEnergyFailsWhenAutoAddDisabled(t *testing.T) {
|
|
mock := &mockNettsClient{
|
|
analyzeData: &netts.AnalyzeUSDTData{TransferDetails: netts.TransferDetails{RecommendedEnergy: 1000}},
|
|
statusResponses: []statusResponse{
|
|
{err: netts.ErrAddressNotFound},
|
|
},
|
|
}
|
|
|
|
cfg := appconfig.EnergyConfig{
|
|
AutoAddHost: false,
|
|
MinCycles: 2,
|
|
TargetCycles: 4,
|
|
}
|
|
|
|
logger := slog.New(slog.NewTextHandler(ioDiscard{}, nil))
|
|
svc := NewEnergyService(cfg, mock, logger)
|
|
|
|
_, err := svc.EnsureEnergy(context.Background(), EnsureEnergyRequest{
|
|
FromAddress: "TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE",
|
|
ToAddress: "TUmyHQNzAkT6SrwThVvay7G4yfGZAyWhmy",
|
|
})
|
|
require.Error(t, err)
|
|
assert.Equal(t, 0, mock.addCalls)
|
|
}
|
|
|
|
func TestEnsureEnergySkipsOrderWhenSufficientCycles(t *testing.T) {
|
|
mock := &mockNettsClient{
|
|
analyzeData: &netts.AnalyzeUSDTData{
|
|
TransferDetails: netts.TransferDetails{
|
|
RecommendedEnergy: 90000,
|
|
EnergyNeeded: 80000,
|
|
},
|
|
},
|
|
statusResponses: []statusResponse{
|
|
{status: &netts.AddressStatus{CyclesRemaining: 5}},
|
|
},
|
|
}
|
|
|
|
cfg := appconfig.EnergyConfig{
|
|
AutoAddHost: true,
|
|
MinCycles: 3,
|
|
TargetCycles: 6,
|
|
}
|
|
|
|
logger := slog.New(slog.NewTextHandler(ioDiscard{}, nil))
|
|
svc := NewEnergyService(cfg, mock, logger)
|
|
|
|
resp, err := svc.EnsureEnergy(context.Background(), EnsureEnergyRequest{
|
|
FromAddress: "TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE",
|
|
ToAddress: "TUmyHQNzAkT6SrwThVvay7G4yfGZAyWhmy",
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
assert.False(t, resp.AddressAdded)
|
|
assert.Equal(t, 0, resp.CyclesPurchased)
|
|
assert.Equal(t, 5, resp.CyclesAfter)
|
|
assert.Empty(t, mock.orderCalls)
|
|
}
|
|
|
|
type statusResponse struct {
|
|
status *netts.AddressStatus
|
|
err error
|
|
}
|
|
|
|
type mockNettsClient struct {
|
|
analyzeData *netts.AnalyzeUSDTData
|
|
statusResponses []statusResponse
|
|
orderResult *netts.OrderResult
|
|
|
|
addCalls int
|
|
orderCalls []int
|
|
}
|
|
|
|
func (m *mockNettsClient) AnalyzeUSDT(ctx context.Context, req netts.AnalyzeUSDTRequest) (*netts.AnalyzeUSDTData, error) {
|
|
if m.analyzeData == nil {
|
|
return nil, errors.New("no analysis data")
|
|
}
|
|
return m.analyzeData, nil
|
|
}
|
|
|
|
func (m *mockNettsClient) GetAddressStatus(ctx context.Context, address string) (*netts.AddressStatus, error) {
|
|
if len(m.statusResponses) == 0 {
|
|
return nil, errors.New("no status response")
|
|
}
|
|
resp := m.statusResponses[0]
|
|
m.statusResponses = m.statusResponses[1:]
|
|
return resp.status, resp.err
|
|
}
|
|
|
|
func (m *mockNettsClient) AddHostAddress(ctx context.Context, address, callback string) (*netts.AddAddressResult, error) {
|
|
m.addCalls++
|
|
return &netts.AddAddressResult{
|
|
Address: address,
|
|
CallbackURL: callback,
|
|
Timestamp: time.Now().UTC().Format(time.RFC3339),
|
|
}, nil
|
|
}
|
|
|
|
func (m *mockNettsClient) OrderCycles(ctx context.Context, address string, cycles int) (*netts.OrderResult, error) {
|
|
m.orderCalls = append(m.orderCalls, cycles)
|
|
if m.orderResult != nil {
|
|
return m.orderResult, nil
|
|
}
|
|
return &netts.OrderResult{
|
|
CyclesPurchased: cycles,
|
|
TotalCycles: cycles,
|
|
OrderID: "ORD",
|
|
Status: "confirmed",
|
|
}, nil
|
|
}
|
|
|
|
type ioDiscard struct{}
|
|
|
|
func (ioDiscard) Write(p []byte) (int, error) { return len(p), nil }
|