Skip to content
This repository has been archived by the owner on Oct 21, 2024. It is now read-only.

feat(BUX-120, BUX-148, BUX-150): broadcast, query subtasks #2

Merged
merged 16 commits into from
Aug 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 0 additions & 22 deletions broadcast/arc/arc_client.go

This file was deleted.

14 changes: 14 additions & 0 deletions broadcast/broadcast-client/arc_config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package broadcast_client

type ArcClientConfig struct {
APIUrl string
Token string
}

func (c *ArcClientConfig) GetApiUrl() string {
return c.APIUrl
}

func (c *ArcClientConfig) GetToken() string {
return c.Token
}
36 changes: 36 additions & 0 deletions broadcast/broadcast-client/client_builder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package broadcast_client

import (
broadcast_api "github.com/bitcoin-sv/go-broadcast-client/broadcast"
"github.com/bitcoin-sv/go-broadcast-client/broadcast/internal/arc"
"github.com/bitcoin-sv/go-broadcast-client/broadcast/internal/composite"
"github.com/bitcoin-sv/go-broadcast-client/broadcast/internal/httpclient"
)

type builder struct {
factories []composite.BroadcastFactory
client httpclient.HTTPInterface
}

func Builder() *builder {
return &builder{}
}

func (cb *builder) WithHttpClient(client httpclient.HTTPInterface) *builder {
cb.client = client
return cb
}

func (cb *builder) WithArc(config ArcClientConfig) *builder {
cb.factories = append(cb.factories, func() broadcast_api.Client {
return arc.NewArcClient(&config, cb.client)
})
return cb
}

func (cb *builder) Build() broadcast_api.Client {
if len(cb.factories) == 1 {
return cb.factories[0]()
}
return composite.NewBroadcasterWithDefaultStrategy(cb.factories...)
}
43 changes: 0 additions & 43 deletions broadcast/broadcast.go

This file was deleted.

17 changes: 17 additions & 0 deletions broadcast/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package broadcast

import (
"errors"
)

var ErrClientUndefined = errors.New("client is undefined")

var ErrAllBroadcastersFailed = errors.New("all broadcasters failed")

var ErrURLEmpty = errors.New("url is empty")

var ErrBroadcasterFailed = errors.New("broadcaster failed")

var ErrUnableToDecodeResponse = errors.New("unable to decode response")

var ErrMissingStatus = errors.New("missing tx status")
64 changes: 31 additions & 33 deletions broadcast/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,34 @@ import (
)

type BestQuoter interface {
// BestQuote(ctx context.Context, feeCategory, feeType string) (*FeeQuoteResponse, error)
BestQuote(ctx context.Context, feeCategory, feeType string) error
}

// type FastestQuoter interface {
// // FastestQuote(ctx context.Context, timeout time.Duration) (*FeeQuoteResponse, error)
// FastestQuote(ctx context.Context, timeout time.Duration) error
// }

// type FeeQuoter interface {
// // FeeQuote(ctx context.Context, miner *Miner) (*FeeQuoteResponse, error)
// FeeQuote(ctx context.Context) error
// }

// type PolicyQuoter interface {
// // PolicyQuote(ctx context.Context, miner *Miner) (*PolicyQuoteResponse, error)
// PolicyQuote(ctx context.Context) error
// }

// type TransactionQuerier interface {
// // // QueryTransaction(ctx context.Context, miner *Miner, txID string, opts ...QueryTransactionOptFunc) (*QueryTransactionResponse, error)
// QueryTransaction(ctx context.Context, txID string) error
// }

// type TransactionSubmitter interface {
// // SubmitTransaction(ctx context.Context, miner *Miner, tx *Transaction) (*SubmitTransactionResponse, error)
// SubmitTransaction(ctx context.Context) error
// }

// type TransactionsSubmitter interface {
// // SubmitTransactions(ctx context.Context, miner *Miner, txs []Transaction) (*SubmitTransactionsResponse, error)
// SubmitTransactions(ctx context.Context) error
// }
}

type FastestQuoter interface {
}

type FeeQuoter interface {
}

type PolicyQuoter interface {
}

type TransactionQuerier interface {
QueryTransaction(ctx context.Context, txID string) (*QueryTxResponse, error)
}

type TransactionSubmitter interface {
SubmitTransaction(ctx context.Context, tx *Transaction) (*SubmitTxResponse, error)
}

type TransactionsSubmitter interface {
}

type Client interface {
BestQuoter
FastestQuoter
FeeQuoter
PolicyQuoter
TransactionQuerier
TransactionSubmitter
TransactionsSubmitter
}
115 changes: 115 additions & 0 deletions broadcast/internal/acceptance_tests/arc_query_tx_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package acceptancetests

import (
"context"
"errors"
"io"
"net/http"
"strings"
"testing"

"github.com/bitcoin-sv/go-broadcast-client/broadcast"
broadcast_client "github.com/bitcoin-sv/go-broadcast-client/broadcast/broadcast-client"
"github.com/bitcoin-sv/go-broadcast-client/broadcast/internal/arc"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)

var firstSuccessfulResponse = `
{
"blockHash": "hash",
"txStatus": "MINED",
"txid": "abc123"
}
`

var secondSuccessfulResponse = `
{
"blockHash": "hash",
"txStatus": "CONFIRMED"
"txid": "abc123"
}
`

func TestQueryTransaction(t *testing.T) {
t.Run("Should successfully query from multiple ArcClients", func(t *testing.T) {
// given
httpClientMock := &arc.MockHttpClient{}
broadcaster := broadcast_client.Builder().
WithHttpClient(httpClientMock).
WithArc(broadcast_client.ArcClientConfig{APIUrl: "http://arc1-api-url", Token: "arc1-token"}).
WithArc(broadcast_client.ArcClientConfig{APIUrl: "http://arc2-api-url", Token: "arc2-token"}).
Build()

httpResponse1 := &http.Response{StatusCode: http.StatusOK, Body: io.NopCloser(strings.NewReader(firstSuccessfulResponse))}
httpResponse2 := &http.Response{StatusCode: http.StatusOK, Body: io.NopCloser(strings.NewReader(secondSuccessfulResponse))}
httpClientMock.On("DoRequest", mock.Anything, mock.Anything).Return(httpResponse1, nil).Once()
httpClientMock.On("DoRequest", mock.Anything, mock.Anything).Return(httpResponse2, nil).Once()

// when
result, err := broadcaster.QueryTransaction(context.Background(), "txID")

// then
assert.NoError(t, err)
assert.NotNil(t, result)
})

t.Run("Should return error if all ArcClients return errors", func(t *testing.T) {
// given
httpClientMock := &arc.MockHttpClient{}
broadcaster := broadcast_client.Builder().
WithHttpClient(httpClientMock).
WithArc(broadcast_client.ArcClientConfig{APIUrl: "http://arc1-api-url", Token: "arc1-token"}).
WithArc(broadcast_client.ArcClientConfig{APIUrl: "http://arc2-api-url", Token: "arc2-token"}).
Build()

httpResponse := &http.Response{}
httpClientMock.On("DoRequest", mock.Anything, mock.Anything).Return(httpResponse, errors.New("http error")).Twice()

// when
result, err := broadcaster.QueryTransaction(context.Background(), "txID")

// then
assert.Error(t, err)
assert.Nil(t, result)
assert.EqualError(t, err, broadcast.ErrAllBroadcastersFailed.Error())
})

t.Run("Should successfully query from single ArcClient", func(t *testing.T) {
// given
httpClientMock := &arc.MockHttpClient{}
broadcaster := broadcast_client.Builder().
WithHttpClient(httpClientMock).
WithArc(broadcast_client.ArcClientConfig{APIUrl: "http://arc1-api-url", Token: "arc1-token"}).
Build()

httpResponse1 := &http.Response{StatusCode: http.StatusOK, Body: io.NopCloser(strings.NewReader(firstSuccessfulResponse))}
httpClientMock.On("DoRequest", mock.Anything, mock.Anything).Return(httpResponse1, nil).Once()

// when
result, err := broadcaster.QueryTransaction(context.Background(), "txID")

// then
assert.NoError(t, err)
assert.NotNil(t, result)
})

t.Run("Should return error if single ArcClient returns error", func(t *testing.T) {
// given
httpClientMock := &arc.MockHttpClient{}
httpResponse := &http.Response{}
broadcaster := broadcast_client.Builder().
WithHttpClient(httpClientMock).
WithArc(broadcast_client.ArcClientConfig{APIUrl: "http://arc1-api-url", Token: "arc1-token"}).
Build()

httpClientMock.On("DoRequest", mock.Anything, mock.Anything).Return(httpResponse, errors.New("http error")).Once()

// when
result, err := broadcaster.QueryTransaction(context.Background(), "txID")

// then
assert.Error(t, err)
assert.Nil(t, result)
})
}
Loading