You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: pool_test.go
    path of file: ./repos/chainlink/core/chains/evm/client
    
    the code of the file until where you have to start completion: package client_test

import (
	"context"
	"math/big"
	"net/http/httptest"
	"net/url"
	"sync"
	"testing"
	"time"

	"github.com/ethereum/go-ethereum/common/hexutil"
	"github.com/ethereum/go-ethereum/rpc"
	promtestutil "github.com/prometheus/client_golang/prometheus/testutil"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/mock"
	"github.com/stretchr/testify/require"
	"github.com/tidwall/gjson"
	"go.uber.org/zap"

	"github.com/smartcontractkit/chainlink-common/pkg/logger"
	evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
	evmmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/mocks"
	"github.com/smartcontractkit/chainlink/v2/core/internal/cltest"
	"github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
)

type poolConfig struct {
	selectionMode       string
	noNewHeadsThreshold time.Duration
	leaseDuration       time.Duration
}

func (c poolConfig) NodeSelectionMode() string {
	return c.selectionMode
}

func (c poolConfig) NodeNoNewHeadsThreshold() time.Duration {
	return c.noNewHeadsThreshold
}

func (c poolConfig) LeaseDuration() time.Duration {
	return c.leaseDuration
}

var defaultConfig evmclient.PoolConfig = &poolConfig{
	selectionMode:       evmclient.NodeSelectionMode_RoundRobin,
	noNewHeadsThreshold: 0,
	leaseDuration:       time.Second * 0,
}

func TestPool_Dial(t *testing.T) {
	t.Parallel()

	tests := []struct {
		name            string
		poolChainID     *big.Int
		nodeChainID     int64
		sendNodeChainID int64
		nodes           []chainIDResps
		sendNodes       []chainIDResp
		errStr          string
	}{
		{
			name:            "no nodes",
			poolChainID:     testutils.FixtureChainID,
			nodeChainID:     testutils.FixtureChainID.Int64(),
			sendNodeChainID: testutils.Fixtu
    
func TestUnit_Pool_RunLoop(t *testing.T) {
	t.Parallel()

	n1 := evmmocks.NewNode(t)
	n2 := evmmocks.NewNode(t)
	n3 := evmmocks.NewNode(t)
	nodes := []evmclient.Node{n1, n2, n3}

	lggr, observedLogs := logger.TestObserved(t, zap.ErrorLevel)
	p := evmclient.NewPool(lggr, defaultConfig.NodeSelectionMode(), defaultConfig.LeaseDuration(), time.Second*0, nodes, []evmclient.SendOnlyNode{}, &cltest.FixtureChainID, "")

	n1.On("String").Maybe().Return("n1")
	n2.On("String").Maybe().Return("n2")
	n3.On("String").Maybe().Return("n3")

	n1.On("Close").Maybe().Return(nil)
	n2.On("Close").Maybe().Return(nil)
	n3.On("Close").Maybe().Return(nil)

	// n1 is alive
	n1.On("Start", mock.Anything).Return(nil).Once()
	n1.On("State").Return(evmclient.NodeStateAlive)
	n1.On("ChainID").Return(testutils.FixtureChainID).Once()
	// n2 is unreachable
	n2.On("Start", mock.Anything).Return(nil).Once()
	n2.On("State").Return(evmclient.NodeStateUnreachable)
	n2.On("ChainID").Return(testutils.FixtureChainID).Once()
	// n3 is out of sync
	n3.On("Start", mock.Anything).Return(nil).Once()
	n3.On("State").Return(evmclient.NodeStateOutOfSync)
	n3.On("ChainID").Return(testutils.FixtureChainID).Once()

	require.NoError(t, p.Dial(testutils.Context(t)))
	t.Cleanup(func() { assert.NoError(t, p.Close()) })

	testutils.WaitForLogMessage(t, observedLogs, "At least one EVM primary node is dead")

	testutils.AssertEventually(t, func() bool {
		totalReported := promtestutil.CollectAndCount(evmclient.PromEVMPoolRPCNodeStates)
		if totalReported < 3 {
			return false
		}
		if promtestutil.ToFloat64(evmclient.PromEVMPoolRPCNodeStates.WithLabelValues("0", "Alive")) < 1.0 {
			return false
		}
		if promtestutil.ToFloat64(evmclient.PromEVMPoolRPCNodeStates.WithLabelValues("0", "Unreachable")) < 1.0 {
			return false
		}
		if promtestutil.ToFloat64(evmclient.PromEVMPoolRPCNodeStates.WithLabelValues("0", "OutOfSync")) < 1.0 {
			return false
		}
		return true
	})
}