From d4e00620ad026f65570c8726e5bfe714416b0654 Mon Sep 17 00:00:00 2001 From: Emil Georgiev Date: Wed, 28 Dec 2022 08:53:53 +0200 Subject: [PATCH] Additional unit tests to improve test coverage. 1. Added unit tests for "./client/chain_registry/cosmos_github_registry.go" by using library "github.com/migueleliasweb/go-github-mock/src/mock" to mock RPC requests. One minor change in the production code. 2. Added additional test cases for the functions broadcastTx and CheckTendermintError in the file "./client/broadcast.go". No production code changed. --- client/broadcast_test.go | 173 ++++++++++++++++-- client/chain_registry/chain_registry.go | 2 +- .../chain_registry/cosmos_github_registry.go | 22 +-- .../cosmos_github_registry_test.go | 166 +++++++++++++++++ cmd/chains_test.go | 11 ++ go.mod | 4 +- go.sum | 10 +- 7 files changed, 361 insertions(+), 27 deletions(-) create mode 100644 client/chain_registry/cosmos_github_registry_test.go diff --git a/client/broadcast_test.go b/client/broadcast_test.go index 1981d25..49fcd0a 100644 --- a/client/broadcast_test.go +++ b/client/broadcast_test.go @@ -3,12 +3,15 @@ package client import ( "context" "errors" + "fmt" "testing" "time" codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/stretchr/testify/assert" + "github.com/tendermint/tendermint/crypto/tmhash" ctypes "github.com/tendermint/tendermint/rpc/core/types" tmtypes "github.com/tendermint/tendermint/types" ) @@ -40,6 +43,15 @@ func (m myFakeTx) GetMsgs() (msgs []sdk.Msg) { func (m myFakeTx) ValidateBasic() error { return nil } func (m myFakeTx) AsAny() *codectypes.Any { return &codectypes.Any{} } +type fakeTx struct { +} + +func (fakeTx) GetMsgs() (msgs []sdk.Msg) { + return nil +} + +func (fakeTx) ValidateBasic() error { return nil } + type fakeBroadcaster struct { tx func(context.Context, []byte, bool) (*ctypes.ResultTx, error) broadcastSync func(context.Context, tmtypes.Tx) (*ctypes.ResultBroadcastTx, error) @@ -60,16 +72,15 @@ func (f fakeBroadcaster) BroadcastTxSync(ctx context.Context, tx tmtypes.Tx) (*c } func TestBroadcast(t *testing.T) { - ctx := context.Background() - for _, tt := range []struct { - name string - broadcaster fakeBroadcaster - txDecoder sdk.TxDecoder - txBytes []byte - waitTimeout time.Duration - expectedRes *sdk.TxResponse - expectedErr error + name string + broadcaster fakeBroadcaster + txDecoder sdk.TxDecoder + txBytes []byte + waitTimeout time.Duration + isContextCancelled bool + expectedRes *sdk.TxResponse + expectedErr error }{ { name: "simple success returns result", @@ -110,7 +121,7 @@ func TestBroadcast(t *testing.T) { return nil, nil }, }, - expectedErr: ErrTimeoutAfterWaitingForTxBroadcast, + expectedErr: fmt.Errorf("timed out after: %d; %w", time.Microsecond, ErrTimeoutAfterWaitingForTxBroadcast), }, { name: "broadcasting returns an error", @@ -121,12 +132,96 @@ func TestBroadcast(t *testing.T) { }, expectedErr: errExpected, }, + { + name: "broadcasting returns an error that Tx already exist", + broadcaster: fakeBroadcaster{ + broadcastSync: func(_ context.Context, _ tmtypes.Tx) (*ctypes.ResultBroadcastTx, error) { + return nil, errors.New("tx already exists in cache") + }, + }, + expectedErr: nil, + expectedRes: &sdk.TxResponse{ + Code: sdkerrors.ErrTxInMempoolCache.ABCICode(), + Codespace: sdkerrors.ErrTxInMempoolCache.Codespace(), + TxHash: fmt.Sprintf("%X", tmhash.Sum([]byte{1, 2, 3, 4})), + }, + txBytes: []byte{1, 2, 3, 4}, + }, + { + name: "request is canceled", + isContextCancelled: true, + broadcaster: fakeBroadcaster{ + broadcastSync: func(_ context.Context, _ tmtypes.Tx) (*ctypes.ResultBroadcastTx, error) { + return &ctypes.ResultBroadcastTx{ + Code: 1, + Hash: []byte(`123bob`), + }, nil + }, + tx: func(_ context.Context, hash []byte, _ bool) (*ctypes.ResultTx, error) { + assert.Equal(t, []byte(`123bob`), hash) + return &ctypes.ResultTx{}, nil + }, + }, + txDecoder: func(txBytes []byte) (sdk.Tx, error) { + return myFakeTx{ + []myFakeMsg{{"hello"}}, + }, nil + }, + expectedRes: nil, + expectedErr: context.Canceled, + }, + { + name: "tx decode failed", + broadcaster: fakeBroadcaster{ + broadcastSync: func(_ context.Context, _ tmtypes.Tx) (*ctypes.ResultBroadcastTx, error) { + return &ctypes.ResultBroadcastTx{ + Code: 1, + Hash: []byte(`123bob`), + }, nil + }, + tx: func(_ context.Context, hash []byte, _ bool) (*ctypes.ResultTx, error) { + assert.Equal(t, []byte(`123bob`), hash) + return &ctypes.ResultTx{}, nil + }, + }, + txDecoder: func(txBytes []byte) (sdk.Tx, error) { + return nil, sdkerrors.ErrTxDecode + }, + expectedRes: nil, + expectedErr: sdkerrors.ErrTxDecode, + }, + { + name: "result doesn't implement the interface intoAny", + broadcaster: fakeBroadcaster{ + broadcastSync: func(_ context.Context, _ tmtypes.Tx) (*ctypes.ResultBroadcastTx, error) { + return &ctypes.ResultBroadcastTx{ + Code: 1, + Hash: []byte(`123bob`), + }, nil + }, + tx: func(_ context.Context, hash []byte, _ bool) (*ctypes.ResultTx, error) { + assert.Equal(t, []byte(`123bob`), hash) + return &ctypes.ResultTx{}, nil + }, + }, + txDecoder: func(txBytes []byte) (sdk.Tx, error) { + return fakeTx{}, nil + }, + expectedRes: nil, + expectedErr: fmt.Errorf("expecting a type implementing intoAny, got: %T", fakeTx{}), + }, } { t.Run(tt.name, func(t *testing.T) { duration := 1 * time.Second if tt.waitTimeout > 0 { duration = tt.waitTimeout } + ctx := context.Background() + if tt.isContextCancelled { + var cancel context.CancelFunc + ctx, cancel = context.WithCancel(context.Background()) + cancel() + } gotRes, gotErr := broadcastTx( ctx, tt.broadcaster, @@ -139,8 +234,64 @@ func TestBroadcast(t *testing.T) { gotRes.Timestamp = "" } assert.Equal(t, tt.expectedRes, gotRes) - assert.ErrorIs(t, gotErr, tt.expectedErr) + assert.Equal(t, gotErr, tt.expectedErr) }) } +} +func TestCheckTendermintError(t *testing.T) { + for _, tt := range []struct { + name string + tx tmtypes.Tx + err error + expectedRes *sdk.TxResponse + }{ + { + name: "Error is nil", + tx: nil, + err: nil, + expectedRes: nil, + }, + { + name: "Tx already exist in the cache", + tx: tmtypes.Tx{1, 2, 3, 4}, + err: errors.New("tx already exists in cache"), + expectedRes: &sdk.TxResponse{ + Code: sdkerrors.ErrTxInMempoolCache.ABCICode(), + Codespace: sdkerrors.ErrTxInMempoolCache.Codespace(), + TxHash: fmt.Sprintf("%X", tmhash.Sum([]byte{1, 2, 3, 4})), + }, + }, + { + name: "mempool is full", + tx: tmtypes.Tx{5, 6, 7, 8}, + err: errors.New("mempool is full"), + expectedRes: &sdk.TxResponse{ + Code: sdkerrors.ErrMempoolIsFull.ABCICode(), + Codespace: sdkerrors.ErrMempoolIsFull.Codespace(), + TxHash: fmt.Sprintf("%X", tmhash.Sum([]byte{5, 6, 7, 8})), + }, + }, + { + name: "tx too large", + tx: tmtypes.Tx{9, 10, 11, 12}, + err: errors.New("tx too large"), + expectedRes: &sdk.TxResponse{ + Code: sdkerrors.ErrTxTooLarge.ABCICode(), + Codespace: sdkerrors.ErrTxTooLarge.Codespace(), + TxHash: fmt.Sprintf("%X", tmhash.Sum([]byte{9, 10, 11, 12})), + }, + }, + { + name: "Unknown error", + tx: tmtypes.Tx{13, 14, 15, 16}, + err: errors.New("unknown error"), + expectedRes: nil, + }, + } { + t.Run(tt.name, func(t *testing.T) { + actualRes := CheckTendermintError(tt.err, tt.tx) + assert.Equal(t, tt.expectedRes, actualRes) + }) + } } diff --git a/client/chain_registry/chain_registry.go b/client/chain_registry/chain_registry.go index 06825fd..beedefc 100644 --- a/client/chain_registry/chain_registry.go +++ b/client/chain_registry/chain_registry.go @@ -13,5 +13,5 @@ type ChainRegistry interface { } func DefaultChainRegistry(log *zap.Logger) ChainRegistry { - return NewCosmosGithubRegistry(log.With(zap.String("registry", "cosmos_github"))) + return NewCosmosGithubRegistry(log.With(zap.String("registry", "cosmos_github")), nil) } diff --git a/client/chain_registry/cosmos_github_registry.go b/client/chain_registry/cosmos_github_registry.go index 817883d..f490315 100644 --- a/client/chain_registry/cosmos_github_registry.go +++ b/client/chain_registry/cosmos_github_registry.go @@ -15,30 +15,32 @@ import ( ) type CosmosGithubRegistry struct { - log *zap.Logger + log *zap.Logger + client *github.Client } -func NewCosmosGithubRegistry(log *zap.Logger) CosmosGithubRegistry { - return CosmosGithubRegistry{log: log} +func NewCosmosGithubRegistry(log *zap.Logger, c *http.Client) CosmosGithubRegistry { + if c == nil { + c = http.DefaultClient + } + return CosmosGithubRegistry{log: log, client: github.NewClient(c)} } func (c CosmosGithubRegistry) ListChains(ctx context.Context) ([]string, error) { - client := github.NewClient(http.DefaultClient) - var chains []string - ctx, cancel := context.WithTimeout(ctx, time.Minute*5) defer cancel() - tree, res, err := client.Git.GetTree( + tree, res, err := c.client.Git.GetTree( ctx, "cosmos", "chain-registry", "master", false) if err != nil || res.StatusCode != 200 { - return chains, err + return nil, err } + var chains []string for _, entry := range tree.Entries { if *entry.Type == "tree" && !strings.HasPrefix(*entry.Path, ".") { chains = append(chains, *entry.Path) @@ -48,10 +50,8 @@ func (c CosmosGithubRegistry) ListChains(ctx context.Context) ([]string, error) } func (c CosmosGithubRegistry) GetChain(ctx context.Context, name string) (ChainInfo, error) { - client := github.NewClient(http.DefaultClient) - chainFileName := path.Join(name, "chain.json") - fileContent, _, res, err := client.Repositories.GetContents( + fileContent, _, res, err := c.client.Repositories.GetContents( ctx, "cosmos", "chain-registry", diff --git a/client/chain_registry/cosmos_github_registry_test.go b/client/chain_registry/cosmos_github_registry_test.go new file mode 100644 index 0000000..17bf771 --- /dev/null +++ b/client/chain_registry/cosmos_github_registry_test.go @@ -0,0 +1,166 @@ +package chain_registry_test + +import ( + "context" + "go.uber.org/zap" + "net/http" + "testing" + + "github.com/google/go-github/v43/github" + "github.com/migueleliasweb/go-github-mock/src/mock" + "github.com/stretchr/testify/require" + "github.com/volumefi/lens/client/chain_registry" + "go.uber.org/zap/zaptest" +) + +func TestListChains(t *testing.T) { + // Setup + mockedHTTPClient := mock.NewMockedHTTPClient( + mock.WithRequestMatch( + mock.GetReposGitTreesByOwnerByRepoByTreeSha, + github.Tree{ + Entries: []*github.TreeEntry{ + {Type: pointer("tree"), Path: pointer("_IBC")}, + {Type: pointer("tree"), Path: pointer("_non-cosmos")}, + {Type: pointer("tree"), Path: pointer("acrechain")}, + {Type: pointer("tree"), Path: pointer("agoric")}, + {Type: pointer("tree"), Path: pointer("aioz")}, + }, + }, + ), + ) + registry := chain_registry.NewCosmosGithubRegistry(zaptest.NewLogger(t), mockedHTTPClient) + + // Action + got, err := registry.ListChains(context.Background()) + + // Assert + require.Nil(t, err) + require.Equal(t, []string{"_IBC", "_non-cosmos", "acrechain", "agoric", "aioz"}, got) +} + +func TestListChains_Failed(t *testing.T) { + // Setup + mockedHTTPClient := mock.NewMockedHTTPClient( + mock.WithRequestMatchHandler( + mock.GetReposGitTreesByOwnerByRepoByTreeSha, + http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + mock.WriteError( + w, + http.StatusInternalServerError, + "github went belly up or something", + ) + }), + ), + ) + registry := chain_registry.NewCosmosGithubRegistry(zaptest.NewLogger(t), mockedHTTPClient) + + // Action + _, err := registry.ListChains(context.Background()) + + // Assert + require.Error(t, err) +} + +func TestGetChain(t *testing.T) { + // Setup + mockedHTTPClient := mock.NewMockedHTTPClient( + mock.WithRequestMatch( + mock.GetReposContentsByOwnerByRepoByPath, + github.RepositoryContent{ + Content: pointer(` + { + "chain_name":"agoric", + "status":"active", + "network_type":"network324", + "chain_id":"5674936249", + "daemon_name":"daemon564" + }`), + }, + ), + ) + log := zaptest.NewLogger(t) + registry := chain_registry.NewCosmosGithubRegistry(log, mockedHTTPClient) + + // Action + actual, err := registry.GetChain(context.Background(), "agoric") + + // Assert + expected := chain_registry.NewChainInfo(log.With(zap.String("chain_name", "agoric"))) + expected.ChainName = "agoric" + expected.Status = "active" + expected.NetworkType = "network324" + expected.ChainID = "5674936249" + expected.DaemonName = "daemon564" + require.Nil(t, err) + require.Equal(t, expected, actual) +} + +func TestGetChain_Failed(t *testing.T) { + // Setup + mockedHTTPClient := mock.NewMockedHTTPClient( + mock.WithRequestMatchHandler( + mock.GetReposContentsByOwnerByRepoByPath, + http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + mock.WriteError( + w, + http.StatusInternalServerError, + "github went belly up or something", + ) + }), + ), + ) + log := zaptest.NewLogger(t) + registry := chain_registry.NewCosmosGithubRegistry(log, mockedHTTPClient) + + // Action + _, err := registry.GetChain(context.Background(), "agoric") + + // Assert + require.Error(t, err) +} + +func TestGetChain_WithMalformedContend(t *testing.T) { + // Setup + mockedHTTPClient := mock.NewMockedHTTPClient( + mock.WithRequestMatch( + mock.GetReposContentsByOwnerByRepoByPath, + github.RepositoryContent{ + Content: pointer(`Malformed`), + }, + ), + ) + log := zaptest.NewLogger(t) + registry := chain_registry.NewCosmosGithubRegistry(log, mockedHTTPClient) + + // Action + _, err := registry.GetChain(context.Background(), "agoric") + + // Assert + require.Error(t, err) +} + +func TestGetChain_WithMalformedBase64Contend(t *testing.T) { + // Setup + mockedHTTPClient := mock.NewMockedHTTPClient( + mock.WithRequestMatch( + mock.GetReposContentsByOwnerByRepoByPath, + github.RepositoryContent{ + Encoding: pointer("base64"), + Content: pointer(`4af34ba3452`), + }, + ), + ) + log := zaptest.NewLogger(t) + registry := chain_registry.NewCosmosGithubRegistry(log, mockedHTTPClient) + + // Action + _, err := registry.GetChain(context.Background(), "agoric") + + // Assert + require.Contains(t, err.Error(), "illegal base64 data") +} + +func pointer(s string) *string { + return &s +} diff --git a/cmd/chains_test.go b/cmd/chains_test.go index 305a965..1575f12 100644 --- a/cmd/chains_test.go +++ b/cmd/chains_test.go @@ -22,6 +22,17 @@ func TestChainsShow_MissingArg(t *testing.T) { require.Empty(t, res.Stdout.String()) } +func TestChainsShow_NotFoundChain(t *testing.T) { + t.Parallel() + + sys := NewSystem(t) + + res := sys.Run(zaptest.NewLogger(t), "chains", "show", "missing") + require.Error(t, res.Err) + require.Contains(t, res.Stderr.String(), "chain missing not found") + require.Empty(t, res.Stdout.String()) +} + func TestChainsShowDefault(t *testing.T) { t.Parallel() diff --git a/go.mod b/go.mod index 5b19bc9..620e74d 100644 --- a/go.mod +++ b/go.mod @@ -11,6 +11,7 @@ require ( github.com/google/go-cmp v0.5.7 github.com/google/go-github/v43 v43.0.0 github.com/jsternberg/zap-logfmt v1.2.0 + github.com/migueleliasweb/go-github-mock v0.0.13 github.com/pkg/errors v0.9.1 github.com/spf13/cobra v1.4.0 github.com/spf13/pflag v1.0.5 @@ -50,7 +51,7 @@ require ( github.com/dvsekhvalnov/jose2go v0.0.0-20200901110807-248326c1351b // indirect github.com/fsnotify/fsnotify v1.5.1 // indirect github.com/go-kit/kit v0.10.0 // indirect - github.com/go-logfmt/logfmt v0.5.0 // indirect + github.com/go-logfmt/logfmt v0.5.1 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/golang/snappy v0.0.3 // indirect @@ -111,6 +112,7 @@ require ( require ( github.com/benbjohnson/clock v1.1.0 // indirect + github.com/google/go-github/v41 v41.0.0 // indirect github.com/google/go-querystring v1.1.0 // indirect go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.8.0 // indirect diff --git a/go.sum b/go.sum index 960cc96..38f9655 100644 --- a/go.sum +++ b/go.sum @@ -149,6 +149,7 @@ github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -201,8 +202,6 @@ github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXy github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/iavl v0.17.3 h1:s2N819a2olOmiauVa0WAhoIJq9EhSXE9HDBAoR9k+8Y= -github.com/cosmos/iavl v0.17.3 h1:s2N819a2olOmiauVa0WAhoIJq9EhSXE9HDBAoR9k+8Y= -github.com/cosmos/iavl v0.17.3/go.mod h1:prJoErZFABYZGDHka1R6Oay4z9PrNeFFiMKHDAMOi4w= github.com/cosmos/iavl v0.17.3/go.mod h1:prJoErZFABYZGDHka1R6Oay4z9PrNeFFiMKHDAMOi4w= github.com/cosmos/ibc-go/v3 v3.0.0 h1:XUNplHVS51Q2gMnTFsFsH9QJ7flsovMamnltKbEgPQ4= github.com/cosmos/ibc-go/v3 v3.0.0/go.mod h1:Mb+1NXiPOLd+CPFlOC6BKeAUaxXlhuWenMmRiUiSmwY= @@ -294,10 +293,12 @@ github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2 github.com/go-kit/kit v0.10.0 h1:dXFJfIHVvUcpSgDOV+Ne6t7jXri8Tfv2uOLHUZ2XNuo= github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= @@ -375,6 +376,7 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-github/v41 v41.0.0 h1:HseJrM2JFf2vfiZJ8anY2hqBjdfY1Vlj/K27ueww4gg= github.com/google/go-github/v41 v41.0.0/go.mod h1:XgmCA5H323A9rtgExdTcnDkcqp6S30AVACCBDOonIxg= github.com/google/go-github/v43 v43.0.0 h1:y+GL7LIsAIF2NZlJ46ZoC/D1W1ivZasT0lnWHMYPZ+U= github.com/google/go-github/v43 v43.0.0/go.mod h1:ZkTvvmCXBvsfPpTHXnH/d2hP9Y0cTbvN9kr5xqyXOIc= @@ -595,6 +597,8 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5 github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= +github.com/migueleliasweb/go-github-mock v0.0.13 h1:pV4yG4XlL/fEPE1Er6MzErAYFyiRSBYw1oo2OojTiCQ= +github.com/migueleliasweb/go-github-mock v0.0.13/go.mod h1:mD5w+9J3oBBMLr7uD6owEYlYBAL8tZd+BA7iGjI4EU8= github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643 h1:hLDRPB66XQT/8+wG9WsDpiCvZf1yKO7sz7scAjSlBa0= github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= github.com/minio/highwayhash v1.0.1 h1:dZ6IIu8Z14VlC0VpfKofAhCy74wu/Qb5gcn52yWoz/0=