diff --git a/api/subscriptions/subscriptions_test.go b/api/subscriptions/subscriptions_test.go index fb308d3bc..cce2fd8f2 100644 --- a/api/subscriptions/subscriptions_test.go +++ b/api/subscriptions/subscriptions_test.go @@ -8,23 +8,28 @@ package subscriptions import ( "encoding/json" "fmt" + "io" "net/http" "net/http/httptest" "net/url" "strings" "testing" + "time" "github.com/gorilla/mux" "github.com/gorilla/websocket" "github.com/stretchr/testify/assert" "github.com/vechain/thor/v2/block" "github.com/vechain/thor/v2/chain" + "github.com/vechain/thor/v2/genesis" + "github.com/vechain/thor/v2/muxdb" + "github.com/vechain/thor/v2/packer" + "github.com/vechain/thor/v2/state" "github.com/vechain/thor/v2/thor" "github.com/vechain/thor/v2/txpool" ) var ts *httptest.Server -var client *http.Client var sub *Subscriptions var txPool *txpool.TxPool var repo *chain.Repository @@ -220,5 +225,83 @@ func initSubscriptionsServer(t *testing.T) { sub = New(repo, []string{}, 5, txPool) sub.Mount(router, "/subscriptions") ts = httptest.NewServer(router) - client = &http.Client{} +} + +func TestSubscriptionsBacktrace(t *testing.T) { + r, generatedBlocks, pool := initChainMultipleBlocks(t, 10) + repo = r + txPool = pool + blocks = generatedBlocks + router := mux.NewRouter() + sub = New(repo, []string{}, 5, txPool) + sub.Mount(router, "/subscriptions") + ts = httptest.NewServer(router) + defer ts.Close() + + t.Run("testHandleSubjectWithTransferBacktraceLimit", testHandleSubjectWithTransferBacktraceLimit) +} +func testHandleSubjectWithTransferBacktraceLimit(t *testing.T) { + genesisBlock := blocks[0] + queryArg := fmt.Sprintf("pos=%s", genesisBlock.Header().ID().String()) + u := url.URL{Scheme: "ws", Host: strings.TrimPrefix(ts.URL, "http://"), Path: "/subscriptions/transfer", RawQuery: queryArg} + + conn, resp, err := websocket.DefaultDialer.Dial(u.String(), nil) + assert.Error(t, err) + assert.Equal(t, "websocket: bad handshake", err.Error()) + defer resp.Body.Close() // Ensure body is closed after reading + + // Read the response body + body, err := io.ReadAll(resp.Body) + if err != nil { + t.Fatalf("failed to read response body: %v", err) + } + assert.Equal(t, body, []byte("pos: backtrace limit exceeded\n")) + assert.Nil(t, conn) +} + +func initChainMultipleBlocks(t *testing.T, blockCount int) (*chain.Repository, []*block.Block, *txpool.TxPool) { + db := muxdb.NewMem() + stater := state.NewStater(db) + gene := genesis.NewDevnet() + + b, _, _, err := gene.Build(stater) + if err != nil { + t.Fatal(err) + } + repo, _ := chain.NewRepository(db, b) + + txPool := txpool.New(repo, stater, txpool.Options{ + Limit: 100, + LimitPerAccount: 16, + MaxLifetime: time.Hour, + }) + + packer := packer.New(repo, stater, genesis.DevAccounts()[0].Address, &genesis.DevAccounts()[0].Address, thor.NoFork) + + tmpBlock := b + createdBlocks := []*block.Block{b} + for i := 0; i < blockCount; i++ { + sum, _ := repo.GetBlockSummary(tmpBlock.Header().ID()) + flow, err := packer.Schedule(sum, uint64(time.Now().Unix())) + if err != nil { + t.Fatal(err) + } + blk, stage, receipts, err := flow.Pack(genesis.DevAccounts()[0].PrivateKey, 0, false) + if err != nil { + t.Fatal(err) + } + if _, err := stage.Commit(); err != nil { + t.Fatal(err) + } + if err := repo.AddBlock(blk, receipts, 0); err != nil { + t.Fatal(err) + } + if err := repo.SetBestBlockID(blk.Header().ID()); err != nil { + t.Fatal(err) + } + createdBlocks = append(createdBlocks, blk) + tmpBlock = blk + } + + return repo, createdBlocks, txPool }