github.com/hyperledger/burrow@v0.34.5-0.20220512172541-77f09336001d/vent/sqldb/sqldb_integration_test.go (about)

     1  // +build integration
     2  
     3  package sqldb_test
     4  
     5  import (
     6  	"database/sql"
     7  	"fmt"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/hyperledger/burrow/vent/config"
    12  	"github.com/hyperledger/burrow/vent/sqldb"
    13  	"github.com/hyperledger/burrow/vent/sqldb/adapters"
    14  	"github.com/hyperledger/burrow/vent/sqlsol"
    15  	"github.com/hyperledger/burrow/vent/test"
    16  	"github.com/hyperledger/burrow/vent/types"
    17  	"github.com/stretchr/testify/assert"
    18  	"github.com/stretchr/testify/require"
    19  )
    20  
    21  func testSynchronizeDB(t *testing.T, cfg *config.VentConfig) {
    22  	t.Run(fmt.Sprintf("%s: successfully creates database tables and synchronizes db", cfg.DBAdapter),
    23  		func(t *testing.T) {
    24  			goodJSON := test.GoodJSONConfFile(t)
    25  
    26  			byteValue := []byte(goodJSON)
    27  			tableStructure, err := sqlsol.NewProjectionFromBytes(byteValue)
    28  			require.NoError(t, err)
    29  
    30  			db, cleanUpDB := test.NewTestDB(t, cfg)
    31  			defer cleanUpDB()
    32  
    33  			err = db.Ping()
    34  			require.NoError(t, err)
    35  
    36  			err = db.SynchronizeDB(test.ChainID, tableStructure.Tables)
    37  			require.NoError(t, err)
    38  		})
    39  }
    40  
    41  func testCleanDB(t *testing.T, cfg *config.VentConfig) {
    42  	t.Run(fmt.Sprintf("%s: successfully creates tables, updates test.ChainID and drops all tables", cfg.DBAdapter),
    43  		func(t *testing.T) {
    44  			byteValue := []byte(test.GoodJSONConfFile(t))
    45  			tableStructure, err := sqlsol.NewProjectionFromBytes(byteValue)
    46  			require.NoError(t, err)
    47  
    48  			db, cleanUpDB := test.NewTestDB(t, cfg)
    49  			defer cleanUpDB()
    50  
    51  			err = db.Ping()
    52  			require.NoError(t, err)
    53  
    54  			err = db.SynchronizeDB(test.ChainID, tableStructure.Tables)
    55  			require.NoError(t, err)
    56  
    57  			err = db.CleanTables(test.ChainID, test.BurrowVersion)
    58  			require.NoError(t, err)
    59  		})
    60  }
    61  
    62  func testRestore(t *testing.T, cfg *config.VentConfig) {
    63  	t.Run(fmt.Sprintf("%s: can restore from vent logging", cfg.DBAdapter),
    64  		func(t *testing.T) {
    65  			db, closeDB := test.NewTestDB(t, cfg)
    66  			defer closeDB()
    67  
    68  			errp := db.Ping()
    69  			require.NoError(t, errp)
    70  
    71  			// new
    72  			str, dat := getBlock()
    73  			err := db.SetBlock(test.ChainID, str, dat)
    74  			require.NoError(t, err)
    75  
    76  			// restore to new table
    77  			prefix := "RESTORED"
    78  			err = db.RestoreDB(time.Time{}, prefix)
    79  			require.NoError(t, err)
    80  
    81  			for table := range dat.Tables {
    82  				assertTablesEqual(t, db, table, fmt.Sprintf("%s_%s", prefix, table))
    83  			}
    84  
    85  			for table := range dat.Tables {
    86  				dropQuery := db.DBAdapter.DropTableQuery(table)
    87  				_, err = db.DB.Exec(dropQuery)
    88  				require.NoError(t, err)
    89  			}
    90  
    91  			// restore in-place over original tables
    92  			err = db.RestoreDB(time.Time{}, "")
    93  			require.NoError(t, err)
    94  
    95  			for table := range dat.Tables {
    96  				assertTablesEqual(t, db, table, fmt.Sprintf("%s_%s", prefix, table))
    97  			}
    98  		})
    99  }
   100  
   101  func testSetBlock(t *testing.T, cfg *config.VentConfig) {
   102  	t.Run(fmt.Sprintf("%s: successfully inserts a block", cfg.DBAdapter),
   103  		func(t *testing.T) {
   104  			db, closeDB := test.NewTestDB(t, cfg)
   105  			defer closeDB()
   106  
   107  			err := db.Ping()
   108  			require.NoError(t, err)
   109  
   110  			// new
   111  			eventTables, eventData := getBlock()
   112  			err = db.SetBlock(test.ChainID, eventTables, eventData)
   113  			require.NoError(t, err)
   114  
   115  			// read
   116  			_, err = db.LastBlockHeight(test.ChainID)
   117  			require.NoError(t, err)
   118  
   119  			_, err = db.GetBlock(test.ChainID, eventData.BlockHeight)
   120  			require.NoError(t, err)
   121  
   122  			// alter
   123  			eventTables, eventData = getAlterBlock()
   124  			err = db.SetBlock(test.ChainID, eventTables, eventData)
   125  			require.NoError(t, err)
   126  
   127  			//restore
   128  			err = db.RestoreDB(time.Time{}, "RESTORED")
   129  			require.NoError(t, err)
   130  
   131  		})
   132  
   133  	t.Run(fmt.Sprintf("%s: successfully creates an empty table", cfg.DBAdapter), func(t *testing.T) {
   134  		db, closeDB := test.NewTestDB(t, cfg)
   135  		defer closeDB()
   136  
   137  		errp := db.Ping()
   138  		require.NoError(t, errp)
   139  
   140  		//table 1
   141  		tables := map[string]*types.SQLTable{
   142  			"AllDataTypesTable": {
   143  				Name: "AllDataTypesTable",
   144  				Columns: []*types.SQLTableColumn{
   145  					{Name: "test_id", Type: types.SQLColumnTypeSerial, Primary: true},
   146  					{Name: "col1", Type: types.SQLColumnTypeBool, Primary: false},
   147  					{Name: "col2", Type: types.SQLColumnTypeByteA, Primary: false},
   148  					{Name: "col3", Type: types.SQLColumnTypeInt, Primary: false},
   149  					{Name: "col4", Type: types.SQLColumnTypeText, Primary: false},
   150  					{Name: "col5", Type: types.SQLColumnTypeTimeStamp, Primary: false},
   151  					{Name: "col6", Type: types.SQLColumnTypeVarchar, Length: 100, Primary: false},
   152  				},
   153  			},
   154  		}
   155  
   156  		err := db.SynchronizeDB(test.ChainID, tables)
   157  		require.NoError(t, err)
   158  	})
   159  }
   160  
   161  func getBlock() (types.EventTables, types.EventData) {
   162  	longtext := "qwertyuiopasdfghjklzxcvbnm1234567890QWERTYUIOPASDFGHJKLZXCVBNM"
   163  	longtext = fmt.Sprintf("%s %s %s %s %s", longtext, longtext, longtext, longtext, longtext)
   164  
   165  	//table 1
   166  	table1 := &types.SQLTable{
   167  		Name: "test_table1",
   168  		Columns: []*types.SQLTableColumn{
   169  			{Name: "test_id", Type: types.SQLColumnTypeInt, Primary: true},
   170  			{Name: "col1", Type: types.SQLColumnTypeVarchar, Length: 100, Primary: false},
   171  			{Name: "col2", Type: types.SQLColumnTypeVarchar, Length: 100, Primary: false},
   172  			{Name: "_height", Type: types.SQLColumnTypeVarchar, Length: 100, Primary: false},
   173  			{Name: "col4", Type: types.SQLColumnTypeText, Primary: false},
   174  			{Name: "colV", Type: types.SQLColumnTypeVarchar, Length: 400, Primary: false},
   175  			{Name: "colT", Type: types.SQLColumnTypeText, Length: 0, Primary: false},
   176  		},
   177  	}
   178  
   179  	//table 2
   180  	table2 := &types.SQLTable{
   181  		Name: "test_table2",
   182  		Columns: []*types.SQLTableColumn{
   183  			{Name: "_height", Type: types.SQLColumnTypeVarchar, Length: 100, Primary: true},
   184  			{Name: "sid_id", Type: types.SQLColumnTypeInt, Primary: true},
   185  			{Name: "field_1", Type: types.SQLColumnTypeVarchar, Length: 100, Primary: false},
   186  			{Name: "field_2", Type: types.SQLColumnTypeVarchar, Length: 100, Primary: false},
   187  		},
   188  	}
   189  
   190  	//table 3
   191  	table3 := &types.SQLTable{
   192  		Name: "test_table3",
   193  		Columns: []*types.SQLTableColumn{
   194  			{Name: "_height", Type: types.SQLColumnTypeVarchar, Length: 100, Primary: true},
   195  			{Name: "val", Type: types.SQLColumnTypeInt, Primary: false},
   196  		},
   197  	}
   198  
   199  	//table 4
   200  	table4 := &types.SQLTable{
   201  		Name: "test_table4",
   202  		Columns: []*types.SQLTableColumn{
   203  			{Name: "index", Type: types.SQLColumnTypeInt, Primary: true},
   204  			{Name: "time", Type: types.SQLColumnTypeTimeStamp, Primary: false},
   205  			{Name: "_height", Type: types.SQLColumnTypeVarchar, Length: 100, Primary: false},
   206  		},
   207  	}
   208  
   209  	str := make(types.EventTables)
   210  	str["1"] = table1
   211  	str["2"] = table2
   212  	str["3"] = table3
   213  	str["4"] = table4
   214  
   215  	//---------------------------------------data-------------------------------------
   216  	var dat types.EventData
   217  	dat.BlockHeight = 2134234
   218  	dat.Tables = make(map[string]types.EventDataTable)
   219  
   220  	var rows1 []types.EventDataRow
   221  	rows1 = append(rows1, types.EventDataRow{Action: types.ActionUpsert, RowData: map[string]interface{}{"test_id": "1", "col1": "text11", "col2": "text12", "_height": dat.BlockHeight, "col4": "14", "colV": longtext, "colT": longtext}})
   222  	rows1 = append(rows1, types.EventDataRow{Action: types.ActionUpsert, RowData: map[string]interface{}{"test_id": "2", "col1": "text21", "col2": "text22", "_height": dat.BlockHeight, "col4": "24", "colV": longtext, "colT": longtext}})
   223  	rows1 = append(rows1, types.EventDataRow{Action: types.ActionUpsert, RowData: map[string]interface{}{"test_id": "3", "col1": "text31", "col2": "text32", "_height": dat.BlockHeight, "col4": "34", "colV": longtext, "colT": longtext}})
   224  	rows1 = append(rows1, types.EventDataRow{Action: types.ActionUpsert, RowData: map[string]interface{}{"test_id": "4", "col1": "text41", "col3": "text43", "_height": dat.BlockHeight, "colV": longtext, "colT": longtext}})
   225  	rows1 = append(rows1, types.EventDataRow{Action: types.ActionUpsert, RowData: map[string]interface{}{"test_id": "1", "col1": "upd", "col2": "upd", "_height": dat.BlockHeight, "col4": "upd", "colV": longtext, "colT": longtext}})
   226  	dat.Tables["test_table1"] = rows1
   227  
   228  	var rows2 []types.EventDataRow
   229  	rows2 = append(rows2, types.EventDataRow{Action: types.ActionUpsert, RowData: map[string]interface{}{"_height": dat.BlockHeight, "sid_id": "1", "field_1": "A", "field_2": "B"}})
   230  	rows2 = append(rows2, types.EventDataRow{Action: types.ActionUpsert, RowData: map[string]interface{}{"_height": dat.BlockHeight, "sid_id": "2", "field_1": "C", "field_2": ""}})
   231  	rows2 = append(rows2, types.EventDataRow{Action: types.ActionUpsert, RowData: map[string]interface{}{"_height": dat.BlockHeight, "sid_id": "3", "field_1": "D", "field_2": "E"}})
   232  	rows2 = append(rows2, types.EventDataRow{Action: types.ActionUpsert, RowData: map[string]interface{}{"_height": dat.BlockHeight, "sid_id": "1", "field_1": "F"}})
   233  	rows2 = append(rows2, types.EventDataRow{Action: types.ActionUpsert, RowData: map[string]interface{}{"_height": dat.BlockHeight, "sid_id": "1", "field_2": "U"}})
   234  	dat.Tables["test_table2"] = rows2
   235  
   236  	var rows3 []types.EventDataRow
   237  	rows3 = append(rows3, types.EventDataRow{Action: types.ActionUpsert, RowData: map[string]interface{}{"_height": "0123456789ABCDEF1", "val": "1"}})
   238  	rows3 = append(rows3, types.EventDataRow{Action: types.ActionUpsert, RowData: map[string]interface{}{"_height": "0123456789ABCDEF2", "val": "2"}})
   239  	rows3 = append(rows3, types.EventDataRow{Action: types.ActionUpsert, RowData: map[string]interface{}{"_height": "0123456789ABCDEFX", "val": "-1"}})
   240  	rows3 = append(rows3, types.EventDataRow{Action: types.ActionUpsert, RowData: map[string]interface{}{"_height": dat.BlockHeight}})
   241  	dat.Tables["test_table3"] = rows3
   242  
   243  	var rows4 []types.EventDataRow
   244  	rows4 = append(rows4, types.EventDataRow{Action: types.ActionUpsert, RowData: map[string]interface{}{"_height": dat.BlockHeight, "time": "2006-01-01 15:04:05", "index": "1"}})
   245  	rows4 = append(rows4, types.EventDataRow{Action: types.ActionUpsert, RowData: map[string]interface{}{"_height": dat.BlockHeight, "time": "2006-01-02 15:04:05", "index": "2"}})
   246  	rows4 = append(rows4, types.EventDataRow{Action: types.ActionUpsert, RowData: map[string]interface{}{"_height": dat.BlockHeight, "time": "2006-01-03 15:04:05", "index": "3"}})
   247  	rows4 = append(rows4, types.EventDataRow{Action: types.ActionUpsert, RowData: map[string]interface{}{"_height": dat.BlockHeight, "time": "2006-01-03 15:04:05", "index": "4"}})
   248  	rows4 = append(rows4, types.EventDataRow{Action: types.ActionDelete, RowData: map[string]interface{}{"_height": dat.BlockHeight, "time": "2006-01-03 15:04:05", "index": "3"}})
   249  	dat.Tables["test_table4"] = rows4
   250  
   251  	return str, dat
   252  }
   253  
   254  func getAlterBlock() (types.EventTables, types.EventData) {
   255  	//table 3
   256  	table3 := &types.SQLTable{
   257  		Name: "test_table3",
   258  		Columns: []*types.SQLTableColumn{
   259  			{Name: "_height", Type: types.SQLColumnTypeVarchar, Length: 100, Primary: true},
   260  			{Name: "val", Type: types.SQLColumnTypeInt, Primary: false},
   261  			{Name: "val_alter", Type: types.SQLColumnTypeInt, Primary: false},
   262  		},
   263  	}
   264  
   265  	str := make(types.EventTables)
   266  	str["3"] = table3
   267  
   268  	//---------------------------------------data-------------------------------------
   269  	var dat types.EventData
   270  	dat.BlockHeight = 23423423
   271  	dat.Tables = make(map[string]types.EventDataTable)
   272  
   273  	var rows5 []types.EventDataRow
   274  	rows5 = append(rows5, types.EventDataRow{Action: types.ActionUpsert, RowData: map[string]interface{}{"_height": dat.BlockHeight, "val": "1", "val_alter": "1"}})
   275  	dat.Tables["test_table3"] = rows5
   276  
   277  	return str, dat
   278  }
   279  
   280  func assertTablesEqual(t *testing.T, db *sqldb.SQLDB, table1, table2 string) {
   281  	cols1, rows1 := selectAll(t, db, table1)
   282  	cols2, rows2 := selectAll(t, db, table2)
   283  
   284  	assert.Equal(t, cols1, cols2, "columns should be equal")
   285  	for i, r1 := range rows1 {
   286  		r2 := rows2[i]
   287  		assert.Equal(t, r1, r2, "each row should be equal")
   288  	}
   289  }
   290  
   291  func selectAll(t *testing.T, db *sqldb.SQLDB, tablename string) (columns []string, rows []map[string]interface{}) {
   292  	// language=SQL
   293  	selectQuery := adapters.Cleanf("SELECT * FROM %s", db.DBAdapter.SchemaName(tablename))
   294  	sqlRows, err := db.DB.Query(selectQuery)
   295  	require.NoError(t, err)
   296  	defer sqlRows.Close()
   297  
   298  	cols, err := sqlRows.Columns()
   299  	require.NoError(t, err)
   300  	for sqlRows.Next() {
   301  		row := rowMap(t, cols, sqlRows)
   302  		rows = append(rows, row)
   303  	}
   304  	return cols, rows
   305  }
   306  
   307  func rowMap(t *testing.T, cols []string, rows *sql.Rows) map[string]interface{} {
   308  	vals := scanValues(len(cols))
   309  	err := rows.Scan(vals...)
   310  	require.NoError(t, err)
   311  	mp := make(map[string]interface{}, len(cols))
   312  
   313  	for i, v := range vals {
   314  		iface := v.(*interface{})
   315  		if iface != nil {
   316  			// truly go at its most beautiful
   317  			switch iv := (*iface).(type) {
   318  			case []byte:
   319  				str := string(iv)
   320  				mp[cols[i]] = str
   321  			default:
   322  				mp[cols[i]] = iv
   323  			}
   324  		}
   325  	}
   326  	return mp
   327  }
   328  
   329  func scanValues(n int) []interface{} {
   330  	vals := make([]interface{}, n)
   331  	for i := 0; i < n; i++ {
   332  		vals[i] = new(interface{})
   333  	}
   334  	return vals
   335  }