github.com/evdatsion/aphelion-dpos-bft@v0.32.1/tools/tm-signer-harness/internal/test_harness_test.go (about)

     1  package internal
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"net"
     7  	"os"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/evdatsion/aphelion-dpos-bft/crypto"
    12  	"github.com/evdatsion/aphelion-dpos-bft/privval"
    13  	"github.com/evdatsion/aphelion-dpos-bft/types"
    14  
    15  	"github.com/stretchr/testify/assert"
    16  	"github.com/stretchr/testify/require"
    17  	"github.com/evdatsion/aphelion-dpos-bft/crypto/ed25519"
    18  	"github.com/evdatsion/aphelion-dpos-bft/libs/log"
    19  )
    20  
    21  const (
    22  	keyFileContents = `{
    23  	"address": "D08FCA3BA74CF17CBFC15E64F9505302BB0E2748",
    24  	"pub_key": {
    25  		"type": "tendermint/PubKeyEd25519",
    26  		"value": "ZCsuTjaczEyon70nmKxwvwu+jqrbq5OH3yQjcK0SFxc="
    27  	},
    28  	"priv_key": {
    29  		"type": "tendermint/PrivKeyEd25519",
    30  		"value": "8O39AkQsoe1sBQwud/Kdul8lg8K9SFsql9aZvwXQSt1kKy5ONpzMTKifvSeYrHC/C76Oqturk4ffJCNwrRIXFw=="
    31  	}
    32  }`
    33  
    34  	stateFileContents = `{
    35  	"height": "0",
    36  	"round": "0",
    37  	"step": 0
    38  }`
    39  
    40  	genesisFileContents = `{
    41  	"genesis_time": "2019-01-15T11:56:34.8963Z",
    42  	"chain_id": "test-chain-0XwP5E",
    43  	"consensus_params": {
    44  		"block": {
    45  			"max_bytes": "22020096",
    46  			"max_gas": "-1",
    47  			"time_iota_ms": "1000"
    48  		},
    49  		"evidence": {
    50  			"max_age": "100000"
    51  		},
    52  		"validator": {
    53  			"pub_key_types": [
    54  				"ed25519"
    55  			]
    56  		}
    57  	},
    58  	"validators": [
    59  		{
    60  		"address": "D08FCA3BA74CF17CBFC15E64F9505302BB0E2748",
    61  		"pub_key": {
    62  			"type": "tendermint/PubKeyEd25519",
    63  			"value": "ZCsuTjaczEyon70nmKxwvwu+jqrbq5OH3yQjcK0SFxc="
    64  		},
    65  		"power": "10",
    66  		"name": ""
    67  		}
    68  	],
    69  	"app_hash": ""
    70  }`
    71  
    72  	defaultConnDeadline = 100
    73  )
    74  
    75  func TestRemoteSignerTestHarnessMaxAcceptRetriesReached(t *testing.T) {
    76  	cfg := makeConfig(t, 1, 2)
    77  	defer cleanup(cfg)
    78  
    79  	th, err := NewTestHarness(log.TestingLogger(), cfg)
    80  	require.NoError(t, err)
    81  	th.Run()
    82  	assert.Equal(t, ErrMaxAcceptRetriesReached, th.exitCode)
    83  }
    84  
    85  func TestRemoteSignerTestHarnessSuccessfulRun(t *testing.T) {
    86  	harnessTest(
    87  		t,
    88  		func(th *TestHarness) *privval.SignerServiceEndpoint {
    89  			return newMockRemoteSigner(t, th, th.fpv.Key.PrivKey, false, false)
    90  		},
    91  		NoError,
    92  	)
    93  }
    94  
    95  func TestRemoteSignerPublicKeyCheckFailed(t *testing.T) {
    96  	harnessTest(
    97  		t,
    98  		func(th *TestHarness) *privval.SignerServiceEndpoint {
    99  			return newMockRemoteSigner(t, th, ed25519.GenPrivKey(), false, false)
   100  		},
   101  		ErrTestPublicKeyFailed,
   102  	)
   103  }
   104  
   105  func TestRemoteSignerProposalSigningFailed(t *testing.T) {
   106  	harnessTest(
   107  		t,
   108  		func(th *TestHarness) *privval.SignerServiceEndpoint {
   109  			return newMockRemoteSigner(t, th, th.fpv.Key.PrivKey, true, false)
   110  		},
   111  		ErrTestSignProposalFailed,
   112  	)
   113  }
   114  
   115  func TestRemoteSignerVoteSigningFailed(t *testing.T) {
   116  	harnessTest(
   117  		t,
   118  		func(th *TestHarness) *privval.SignerServiceEndpoint {
   119  			return newMockRemoteSigner(t, th, th.fpv.Key.PrivKey, false, true)
   120  		},
   121  		ErrTestSignVoteFailed,
   122  	)
   123  }
   124  
   125  func newMockRemoteSigner(t *testing.T, th *TestHarness, privKey crypto.PrivKey, breakProposalSigning bool, breakVoteSigning bool) *privval.SignerServiceEndpoint {
   126  	return privval.NewSignerServiceEndpoint(
   127  		th.logger,
   128  		th.chainID,
   129  		types.NewMockPVWithParams(privKey, breakProposalSigning, breakVoteSigning),
   130  		privval.DialTCPFn(
   131  			th.addr,
   132  			time.Duration(defaultConnDeadline)*time.Millisecond,
   133  			ed25519.GenPrivKey(),
   134  		),
   135  	)
   136  }
   137  
   138  // For running relatively standard tests.
   139  func harnessTest(t *testing.T, rsMaker func(th *TestHarness) *privval.SignerServiceEndpoint, expectedExitCode int) {
   140  	cfg := makeConfig(t, 100, 3)
   141  	defer cleanup(cfg)
   142  
   143  	th, err := NewTestHarness(log.TestingLogger(), cfg)
   144  	require.NoError(t, err)
   145  	donec := make(chan struct{})
   146  	go func() {
   147  		defer close(donec)
   148  		th.Run()
   149  	}()
   150  
   151  	rs := rsMaker(th)
   152  	require.NoError(t, rs.Start())
   153  	assert.True(t, rs.IsRunning())
   154  	defer rs.Stop()
   155  
   156  	<-donec
   157  	assert.Equal(t, expectedExitCode, th.exitCode)
   158  }
   159  
   160  func makeConfig(t *testing.T, acceptDeadline, acceptRetries int) TestHarnessConfig {
   161  	return TestHarnessConfig{
   162  		BindAddr:         testFreeTCPAddr(t),
   163  		KeyFile:          makeTempFile("tm-testharness-keyfile", keyFileContents),
   164  		StateFile:        makeTempFile("tm-testharness-statefile", stateFileContents),
   165  		GenesisFile:      makeTempFile("tm-testharness-genesisfile", genesisFileContents),
   166  		AcceptDeadline:   time.Duration(acceptDeadline) * time.Millisecond,
   167  		ConnDeadline:     time.Duration(defaultConnDeadline) * time.Millisecond,
   168  		AcceptRetries:    acceptRetries,
   169  		SecretConnKey:    ed25519.GenPrivKey(),
   170  		ExitWhenComplete: false,
   171  	}
   172  }
   173  
   174  func cleanup(cfg TestHarnessConfig) {
   175  	os.Remove(cfg.KeyFile)
   176  	os.Remove(cfg.StateFile)
   177  	os.Remove(cfg.GenesisFile)
   178  }
   179  
   180  func makeTempFile(name, content string) string {
   181  	tempFile, err := ioutil.TempFile("", fmt.Sprintf("%s-*", name))
   182  	if err != nil {
   183  		panic(err)
   184  	}
   185  	if _, err := tempFile.Write([]byte(content)); err != nil {
   186  		tempFile.Close()
   187  		panic(err)
   188  	}
   189  	if err := tempFile.Close(); err != nil {
   190  		panic(err)
   191  	}
   192  	return tempFile.Name()
   193  }
   194  
   195  // testFreeTCPAddr claims a free port so we don't block on listener being ready.
   196  func testFreeTCPAddr(t *testing.T) string {
   197  	ln, err := net.Listen("tcp", "127.0.0.1:0")
   198  	require.NoError(t, err)
   199  	defer ln.Close()
   200  
   201  	return fmt.Sprintf("127.0.0.1:%d", ln.Addr().(*net.TCPAddr).Port)
   202  }