github.com/Tri-stone/burrow@v0.25.0/vent/sqlsol/projection_test.go (about)

     1  package sqlsol_test
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/hyperledger/burrow/vent/sqlsol"
     7  	"github.com/hyperledger/burrow/vent/test"
     8  	"github.com/hyperledger/burrow/vent/types"
     9  	"github.com/stretchr/testify/require"
    10  )
    11  
    12  func TestNewProjection(t *testing.T) {
    13  	t.Run("returns an error if the json is malformed", func(t *testing.T) {
    14  		badJSON := test.BadJSONConfFile(t)
    15  
    16  		byteValue := []byte(badJSON)
    17  		_, err := sqlsol.NewProjectionFromBytes(byteValue)
    18  		require.Error(t, err)
    19  	})
    20  
    21  	t.Run("returns an error if needed json fields are missing", func(t *testing.T) {
    22  		missingFields := test.MissingFieldsJSONConfFile(t)
    23  
    24  		byteValue := []byte(missingFields)
    25  		_, err := sqlsol.NewProjectionFromBytes(byteValue)
    26  		require.Error(t, err)
    27  	})
    28  
    29  	t.Run("successfully builds table structure based on json events config", func(t *testing.T) {
    30  		tableStruct, err := sqlsol.NewProjectionFromBytes([]byte(test.GoodJSONConfFile(t)))
    31  		require.NoError(t, err)
    32  
    33  		// columns map
    34  		tableName := "UserAccounts"
    35  		col, err := tableStruct.GetColumn(tableName, "username")
    36  		require.NoError(t, err)
    37  		require.Equal(t, false, col.Primary)
    38  		require.Equal(t, types.SQLColumnTypeText, col.Type)
    39  		require.Equal(t, "username", col.Name)
    40  
    41  		col, err = tableStruct.GetColumn(tableName, "address")
    42  		require.NoError(t, err)
    43  		require.Equal(t, true, col.Primary)
    44  		require.Equal(t, types.SQLColumnTypeVarchar, col.Type)
    45  		require.Equal(t, "address", col.Name)
    46  
    47  		col, err = tableStruct.GetColumn(tableName, types.SQLColumnLabelTxHash)
    48  		require.NoError(t, err)
    49  		require.Equal(t, false, col.Primary)
    50  		require.Equal(t, types.SQLColumnTypeText, col.Type)
    51  
    52  		col, err = tableStruct.GetColumn(tableName, types.SQLColumnLabelEventName)
    53  		require.NoError(t, err)
    54  		require.Equal(t, false, col.Primary)
    55  		require.Equal(t, types.SQLColumnTypeText, col.Type)
    56  	})
    57  
    58  	t.Run("returns an error if the event type of a given column is unknown", func(t *testing.T) {
    59  		typeUnknownJSON := test.UnknownTypeJSONConfFile(t)
    60  
    61  		byteValue := []byte(typeUnknownJSON)
    62  		_, err := sqlsol.NewProjectionFromBytes(byteValue)
    63  		require.Error(t, err)
    64  	})
    65  
    66  	t.Run("returns an error if there are duplicated column names for a given table in json file", func(t *testing.T) {
    67  		duplicatedColNameJSON := test.DuplicatedColNameJSONConfFile(t)
    68  
    69  		byteValue := []byte(duplicatedColNameJSON)
    70  		_, err := sqlsol.NewProjectionFromBytes(byteValue)
    71  		require.Error(t, err)
    72  	})
    73  
    74  }
    75  
    76  func TestGetColumn(t *testing.T) {
    77  	projection, err := sqlsol.NewProjectionFromBytes([]byte(test.GoodJSONConfFile(t)))
    78  	require.NoError(t, err)
    79  
    80  	t.Run("successfully gets the mapping column info for a given table & column name", func(t *testing.T) {
    81  		column, err := projection.GetColumn("TEST_TABLE", "Block")
    82  		require.NoError(t, err)
    83  		require.Equal(t, "Block", column.Name)
    84  		require.Equal(t, types.SQLColumnTypeBigInt, column.Type)
    85  		require.Equal(t, false, column.Primary)
    86  
    87  		column, err = projection.GetColumn("TEST_TABLE", "Instance")
    88  		require.NoError(t, err)
    89  		require.Equal(t, "Instance", column.Name)
    90  		require.Equal(t, types.SQLColumnTypeBigInt, column.Type)
    91  		require.Equal(t, false, column.Primary)
    92  
    93  	})
    94  
    95  	t.Run("unsuccessfully gets the mapping column info for a non existent table name", func(t *testing.T) {
    96  		_, err := projection.GetColumn("NOT_EXISTS", "userName")
    97  		require.Error(t, err)
    98  	})
    99  
   100  	t.Run("unsuccessfully gets the mapping column info for a non existent column name", func(t *testing.T) {
   101  		_, err := projection.GetColumn("UpdateUserAccount", "NOT_EXISTS")
   102  		require.Error(t, err)
   103  	})
   104  }
   105  
   106  func TestGetTables(t *testing.T) {
   107  	goodJSON := test.GoodJSONConfFile(t)
   108  
   109  	byteValue := []byte(goodJSON)
   110  	tableStruct, _ := sqlsol.NewProjectionFromBytes(byteValue)
   111  
   112  	t.Run("successfully returns event tables structures", func(t *testing.T) {
   113  		tables := tableStruct.Tables
   114  		require.Equal(t, 2, len(tables))
   115  		require.Equal(t, "UserAccounts", tables["UserAccounts"].Name)
   116  
   117  	})
   118  }
   119  
   120  func TestGetEventSpec(t *testing.T) {
   121  	goodJSON := test.GoodJSONConfFile(t)
   122  
   123  	byteValue := []byte(goodJSON)
   124  	tableStruct, _ := sqlsol.NewProjectionFromBytes(byteValue)
   125  
   126  	t.Run("successfully returns event specification structures", func(t *testing.T) {
   127  		eventSpec := tableStruct.EventSpec
   128  		require.Equal(t, 2, len(eventSpec))
   129  		require.Equal(t, "LOG0 = 'UserAccounts'", eventSpec[0].Filter)
   130  		require.Equal(t, "UserAccounts", eventSpec[0].TableName)
   131  
   132  		require.Equal(t, "Log1Text = 'EVENT_TEST'", eventSpec[1].Filter)
   133  		require.Equal(t, "TEST_TABLE", eventSpec[1].TableName)
   134  	})
   135  }
   136  
   137  func TestNewProjectionFromEventSpec(t *testing.T) {
   138  	tableName := "BurnNotices"
   139  	eventSpec := types.EventSpec{
   140  		{
   141  			TableName: tableName,
   142  			Filter:    "LOG1Text = 'CIA/burn'",
   143  			FieldMappings: []*types.EventFieldMapping{
   144  				{
   145  					Field:      "codename",
   146  					Type:       types.EventFieldTypeString,
   147  					ColumnName: "name",
   148  					Notify:     []string{"burn"},
   149  				},
   150  				{
   151  					Field:      "burn",
   152  					Type:       types.EventFieldTypeBool,
   153  					ColumnName: "burnt",
   154  					Notify:     []string{"burn"},
   155  				},
   156  				{
   157  					Field:      "dairy",
   158  					Type:       types.EventFieldTypeString,
   159  					ColumnName: "coffee_milk",
   160  					Notify:     []string{"mrs_doyle"},
   161  				},
   162  				{
   163  					Field:      "datetime",
   164  					Type:       types.EventFieldTypeInt,
   165  					ColumnName: "time_changed",
   166  					Notify:     []string{"last_heard", "mrs_doyle"},
   167  				},
   168  			},
   169  		},
   170  		{
   171  			TableName: tableName,
   172  			Filter:    "LOG1Text = 'MI5/burn'",
   173  			FieldMappings: []*types.EventFieldMapping{
   174  				{
   175  					Field:      "codename",
   176  					Type:       types.EventFieldTypeString,
   177  					ColumnName: "name",
   178  					Notify:     []string{"burn"},
   179  				},
   180  				{
   181  					Field:      "unreliable",
   182  					Type:       types.EventFieldTypeBool,
   183  					ColumnName: "burnt",
   184  					Notify:     []string{"burn"},
   185  				},
   186  				{
   187  					Field:      "sugars",
   188  					Type:       types.EventFieldTypeInt,
   189  					ColumnName: "tea_sugars",
   190  					Notify:     []string{"mrs_doyle"},
   191  				},
   192  				{
   193  					Field:      "milk",
   194  					Type:       types.EventFieldTypeBool,
   195  					ColumnName: "tea_milk",
   196  					Notify:     []string{"mrs_doyle"},
   197  				},
   198  				{
   199  					Field:      "datetime",
   200  					Type:       types.EventFieldTypeInt,
   201  					ColumnName: "time_changed",
   202  					Notify:     []string{"last_heard", "mrs_doyle"},
   203  				},
   204  			},
   205  		},
   206  	}
   207  	projection, err := sqlsol.NewProjectionFromEventSpec(eventSpec)
   208  	require.NoError(t, err, "burn and unreliable field mappings should unify to single column")
   209  
   210  	require.Equal(t, []string{"burnt", "name"}, projection.Tables[tableName].NotifyChannels["burn"])
   211  
   212  	// Notify sugars on the burn channel
   213  	field := eventSpec[1].GetFieldMapping("sugars")
   214  	field.Notify = append(field.Notify, "burn")
   215  
   216  	projection, err = sqlsol.NewProjectionFromEventSpec(eventSpec)
   217  	require.NoError(t, err)
   218  	require.Equal(t, []string{"burnt", "name", "tea_sugars"}, projection.Tables[tableName].NotifyChannels["burn"])
   219  
   220  	// Create a column conflict between burn and unreliable fields (both map to burnt so the SQL column def must be identical)
   221  	field = eventSpec[1].GetFieldMapping("unreliable")
   222  	field.Primary = !field.Primary
   223  	projection, err = sqlsol.NewProjectionFromEventSpec(eventSpec)
   224  	require.Error(t, err)
   225  }