github.com/number571/tendermint@v0.34.11-gost/state/indexer/indexer_service_test.go (about)

     1  package indexer_test
     2  
     3  import (
     4  	"database/sql"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"os"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/adlio/schema"
    12  	_ "github.com/lib/pq"
    13  	dockertest "github.com/ory/dockertest"
    14  	"github.com/ory/dockertest/docker"
    15  	"github.com/stretchr/testify/assert"
    16  	"github.com/stretchr/testify/require"
    17  
    18  	abci "github.com/number571/tendermint/abci/types"
    19  	tmlog "github.com/number571/tendermint/libs/log"
    20  	indexer "github.com/number571/tendermint/state/indexer"
    21  	kv "github.com/number571/tendermint/state/indexer/sink/kv"
    22  	psql "github.com/number571/tendermint/state/indexer/sink/psql"
    23  	"github.com/number571/tendermint/types"
    24  	db "github.com/tendermint/tm-db"
    25  )
    26  
    27  var psqldb *sql.DB
    28  var resource *dockertest.Resource
    29  var pSink indexer.EventSink
    30  
    31  var (
    32  	user     = "postgres"
    33  	password = "secret"
    34  	port     = "5432"
    35  	dsn      = "postgres://%s:%s@localhost:%s/%s?sslmode=disable"
    36  	dbName   = "postgres"
    37  )
    38  
    39  func TestIndexerServiceIndexesBlocks(t *testing.T) {
    40  	// event bus
    41  	eventBus := types.NewEventBus()
    42  	eventBus.SetLogger(tmlog.TestingLogger())
    43  	err := eventBus.Start()
    44  	require.NoError(t, err)
    45  	t.Cleanup(func() {
    46  		if err := eventBus.Stop(); err != nil {
    47  			t.Error(err)
    48  		}
    49  	})
    50  
    51  	assert.False(t, indexer.KVSinkEnabled([]indexer.EventSink{}))
    52  	assert.False(t, indexer.IndexingEnabled([]indexer.EventSink{}))
    53  
    54  	// event sink setup
    55  	pool, err := setupDB(t)
    56  	assert.Nil(t, err)
    57  
    58  	store := db.NewMemDB()
    59  	eventSinks := []indexer.EventSink{kv.NewEventSink(store), pSink}
    60  	assert.True(t, indexer.KVSinkEnabled(eventSinks))
    61  	assert.True(t, indexer.IndexingEnabled(eventSinks))
    62  
    63  	service := indexer.NewIndexerService(eventSinks, eventBus)
    64  	service.SetLogger(tmlog.TestingLogger())
    65  	err = service.Start()
    66  	require.NoError(t, err)
    67  	t.Cleanup(func() {
    68  		if err := service.Stop(); err != nil {
    69  			t.Error(err)
    70  		}
    71  	})
    72  
    73  	// publish block with txs
    74  	err = eventBus.PublishEventNewBlockHeader(types.EventDataNewBlockHeader{
    75  		Header: types.Header{Height: 1},
    76  		NumTxs: int64(2),
    77  	})
    78  	require.NoError(t, err)
    79  	txResult1 := &abci.TxResult{
    80  		Height: 1,
    81  		Index:  uint32(0),
    82  		Tx:     types.Tx("foo"),
    83  		Result: abci.ResponseDeliverTx{Code: 0},
    84  	}
    85  	err = eventBus.PublishEventTx(types.EventDataTx{TxResult: *txResult1})
    86  	require.NoError(t, err)
    87  	txResult2 := &abci.TxResult{
    88  		Height: 1,
    89  		Index:  uint32(1),
    90  		Tx:     types.Tx("bar"),
    91  		Result: abci.ResponseDeliverTx{Code: 0},
    92  	}
    93  	err = eventBus.PublishEventTx(types.EventDataTx{TxResult: *txResult2})
    94  	require.NoError(t, err)
    95  
    96  	time.Sleep(100 * time.Millisecond)
    97  
    98  	res, err := eventSinks[0].GetTxByHash(types.Tx("foo").Hash())
    99  	require.NoError(t, err)
   100  	require.Equal(t, txResult1, res)
   101  
   102  	ok, err := eventSinks[0].HasBlock(1)
   103  	require.NoError(t, err)
   104  	require.True(t, ok)
   105  
   106  	res, err = eventSinks[0].GetTxByHash(types.Tx("bar").Hash())
   107  	require.NoError(t, err)
   108  	require.Equal(t, txResult2, res)
   109  
   110  	assert.Nil(t, teardown(t, pool))
   111  }
   112  
   113  func readSchema() ([]*schema.Migration, error) {
   114  	filename := "./sink/psql/schema.sql"
   115  	contents, err := ioutil.ReadFile(filename)
   116  	if err != nil {
   117  		return nil, fmt.Errorf("failed to read sql file from '%s': %w", filename, err)
   118  	}
   119  
   120  	mg := &schema.Migration{}
   121  	mg.ID = time.Now().Local().String() + " db schema"
   122  	mg.Script = string(contents)
   123  	return append([]*schema.Migration{}, mg), nil
   124  }
   125  
   126  func resetDB(t *testing.T) {
   127  	q := "DROP TABLE IF EXISTS block_events,tx_events,tx_results"
   128  	_, err := psqldb.Exec(q)
   129  	assert.Nil(t, err)
   130  
   131  	q = "DROP TYPE IF EXISTS block_event_type"
   132  	_, err = psqldb.Exec(q)
   133  	assert.Nil(t, err)
   134  }
   135  
   136  func setupDB(t *testing.T) (*dockertest.Pool, error) {
   137  	t.Helper()
   138  	pool, err := dockertest.NewPool(os.Getenv("DOCKER_URL"))
   139  	assert.Nil(t, err)
   140  
   141  	resource, err = pool.RunWithOptions(&dockertest.RunOptions{
   142  		Repository: psql.DriverName,
   143  		Tag:        "13",
   144  		Env: []string{
   145  			"POSTGRES_USER=" + user,
   146  			"POSTGRES_PASSWORD=" + password,
   147  			"POSTGRES_DB=" + dbName,
   148  			"listen_addresses = '*'",
   149  		},
   150  		ExposedPorts: []string{port},
   151  	}, func(config *docker.HostConfig) {
   152  		// set AutoRemove to true so that stopped container goes away by itself
   153  		config.AutoRemove = true
   154  		config.RestartPolicy = docker.RestartPolicy{
   155  			Name: "no",
   156  		}
   157  	})
   158  
   159  	assert.Nil(t, err)
   160  
   161  	// Set the container to expire in a minute to avoid orphaned containers
   162  	// hanging around
   163  	_ = resource.Expire(60)
   164  
   165  	conn := fmt.Sprintf(dsn, user, password, resource.GetPort(port+"/tcp"), dbName)
   166  
   167  	if err = pool.Retry(func() error {
   168  		var err error
   169  
   170  		pSink, psqldb, err = psql.NewEventSink(conn, "test-chainID")
   171  
   172  		if err != nil {
   173  			return err
   174  		}
   175  
   176  		return psqldb.Ping()
   177  	}); err != nil {
   178  		assert.Error(t, err)
   179  	}
   180  
   181  	resetDB(t)
   182  
   183  	sm, err := readSchema()
   184  	assert.Nil(t, err)
   185  
   186  	err = schema.NewMigrator().Apply(psqldb, sm)
   187  	assert.Nil(t, err)
   188  
   189  	return pool, nil
   190  }
   191  
   192  func teardown(t *testing.T, pool *dockertest.Pool) error {
   193  	t.Helper()
   194  	// When you're done, kill and remove the container
   195  	assert.Nil(t, pool.Purge(resource))
   196  	return psqldb.Close()
   197  }