code.vegaprotocol.io/vega@v0.79.0/core/datasource/spec/adaptors/adaptors_test.go (about)

     1  // Copyright (C) 2023 Gobalsky Labs Limited
     2  //
     3  // This program is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU Affero General Public License as
     5  // published by the Free Software Foundation, either version 3 of the
     6  // License, or (at your option) any later version.
     7  //
     8  // This program is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  // GNU Affero General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU Affero General Public License
    14  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    15  
    16  package adaptors_test
    17  
    18  import (
    19  	"encoding/hex"
    20  	"encoding/json"
    21  	"fmt"
    22  	"testing"
    23  	"time"
    24  
    25  	"code.vegaprotocol.io/vega/core/datasource/common"
    26  	"code.vegaprotocol.io/vega/core/datasource/spec"
    27  	"code.vegaprotocol.io/vega/core/datasource/spec/adaptors"
    28  	"code.vegaprotocol.io/vega/libs/crypto"
    29  	commandspb "code.vegaprotocol.io/vega/protos/vega/commands/v1"
    30  
    31  	"github.com/stretchr/testify/assert"
    32  	"github.com/stretchr/testify/require"
    33  )
    34  
    35  func TestAdaptors(t *testing.T) {
    36  	t.Run("Creating adaptors succeeds", testCreatingAdaptorsSucceeds)
    37  	t.Run("Normalising data from unknown oracle fails", testAdaptorsNormalisingDataFromUnknownOracleFails)
    38  	t.Run("Normalising data from known oracle succeeds", testAdaptorsNormalisingDataFromKnownOracleSucceeds)
    39  	t.Run("Validating data should pass if validators return no errors", testAdaptorValidationSuccess)
    40  	t.Run("Validating data should fail if any validator returns an error", testAdaptorValidationFails)
    41  }
    42  
    43  func testCreatingAdaptorsSucceeds(t *testing.T) {
    44  	// when
    45  	as := adaptors.New()
    46  
    47  	// then
    48  	assert.NotNil(t, as)
    49  }
    50  
    51  func testAdaptorsNormalisingDataFromUnknownOracleFails(t *testing.T) {
    52  	// given
    53  	pubKeyB := []byte("0xdeadbeef")
    54  	pubKey := crypto.NewPublicKey(hex.EncodeToString(pubKeyB), pubKeyB)
    55  	rawData := commandspb.OracleDataSubmission{
    56  		Source:  commandspb.OracleDataSubmission_ORACLE_SOURCE_UNSPECIFIED,
    57  		Payload: dummyOraclePayload(t),
    58  	}
    59  
    60  	// when
    61  	normalisedData, err := stubbedAdaptors().Normalise(pubKey, rawData)
    62  
    63  	// then
    64  	require.Error(t, err)
    65  	assert.EqualError(t, err, adaptors.ErrUnknownOracleSource.Error())
    66  	assert.Nil(t, normalisedData)
    67  }
    68  
    69  func testAdaptorsNormalisingDataFromKnownOracleSucceeds(t *testing.T) {
    70  	tcs := []struct {
    71  		name   string
    72  		source commandspb.OracleDataSubmission_OracleSource
    73  	}{
    74  		{
    75  			name:   "with Open Oracle source",
    76  			source: commandspb.OracleDataSubmission_ORACLE_SOURCE_OPEN_ORACLE,
    77  		}, {
    78  			name:   "with JSON source",
    79  			source: commandspb.OracleDataSubmission_ORACLE_SOURCE_JSON,
    80  		},
    81  	}
    82  
    83  	for _, tc := range tcs {
    84  		t.Run(tc.name, func(tt *testing.T) {
    85  			// given
    86  			pubKeyB := []byte("0xdeadbeef")
    87  			pubKey := crypto.NewPublicKey(hex.EncodeToString(pubKeyB), pubKeyB)
    88  			rawData := commandspb.OracleDataSubmission{
    89  				Source:  tc.source,
    90  				Payload: dummyOraclePayload(t),
    91  			}
    92  
    93  			// when
    94  			normalisedData, err := stubbedAdaptors().Normalise(pubKey, rawData)
    95  
    96  			// then
    97  			require.NoError(t, err)
    98  			assert.NotNil(t, normalisedData)
    99  		})
   100  	}
   101  }
   102  
   103  func stubbedAdaptors() *adaptors.Adaptors {
   104  	return &adaptors.Adaptors{
   105  		Adaptors: map[commandspb.OracleDataSubmission_OracleSource]adaptors.Adaptor{
   106  			commandspb.OracleDataSubmission_ORACLE_SOURCE_OPEN_ORACLE: &dummyOracleAdaptor{},
   107  			commandspb.OracleDataSubmission_ORACLE_SOURCE_JSON:        &dummyOracleAdaptor{},
   108  		},
   109  	}
   110  }
   111  
   112  func dummyOraclePayload(t *testing.T) []byte {
   113  	t.Helper()
   114  	payload, err := json.Marshal(map[string]string{
   115  		"field_1": "value_1",
   116  		"field_2": "value_2",
   117  	})
   118  	if err != nil {
   119  		t.Fatalf("failed to generate random oracle payload in tests: %s", err)
   120  	}
   121  
   122  	return payload
   123  }
   124  
   125  func internalOraclePayload(t *testing.T) []byte {
   126  	t.Helper()
   127  	payload, err := json.Marshal(map[string]string{
   128  		spec.BuiltinTimestamp: fmt.Sprintf("%d", time.Now().UnixNano()),
   129  	})
   130  	if err != nil {
   131  		t.Fatalf("failed to generate internal oracle payload in tests: %s", err)
   132  	}
   133  
   134  	return payload
   135  }
   136  
   137  type dummyOracleAdaptor struct{}
   138  
   139  func (d *dummyOracleAdaptor) Normalise(pk crypto.PublicKey, payload []byte) (*common.Data, error) {
   140  	var data map[string]string
   141  	if err := json.Unmarshal(payload, &data); err != nil {
   142  		return nil, err
   143  	}
   144  
   145  	return &common.Data{
   146  		Signers: []*common.Signer{
   147  			common.CreateSignerFromString(pk.Hex(), common.SignerTypePubKey),
   148  		},
   149  		Data: data,
   150  	}, nil
   151  }
   152  
   153  func testAdaptorValidationSuccess(t *testing.T) {
   154  	tcs := []struct {
   155  		name   string
   156  		source commandspb.OracleDataSubmission_OracleSource
   157  	}{
   158  		{
   159  			name:   "with Open Oracle source",
   160  			source: commandspb.OracleDataSubmission_ORACLE_SOURCE_OPEN_ORACLE,
   161  		}, {
   162  			name:   "with JSON source",
   163  			source: commandspb.OracleDataSubmission_ORACLE_SOURCE_JSON,
   164  		},
   165  	}
   166  
   167  	for _, tc := range tcs {
   168  		t.Run(tc.name, func(tt *testing.T) {
   169  			// given
   170  			pubKeyB := []byte("0xdeadbeef")
   171  			pubKey := crypto.NewPublicKey(hex.EncodeToString(pubKeyB), pubKeyB)
   172  			rawData := commandspb.OracleDataSubmission{
   173  				Source:  tc.source,
   174  				Payload: dummyOraclePayload(t),
   175  			}
   176  
   177  			// when
   178  			adaptor := stubbedAdaptors()
   179  			normalisedData, err := adaptor.Normalise(pubKey, rawData)
   180  
   181  			// then
   182  			require.NoError(tt, err)
   183  			assert.NotNil(tt, normalisedData)
   184  		})
   185  	}
   186  }
   187  
   188  func testAdaptorValidationFails(t *testing.T) {
   189  	tcs := []struct {
   190  		name   string
   191  		source commandspb.OracleDataSubmission_OracleSource
   192  	}{
   193  		{
   194  			name:   "with Open Oracle source",
   195  			source: commandspb.OracleDataSubmission_ORACLE_SOURCE_OPEN_ORACLE,
   196  		}, {
   197  			name:   "with JSON source",
   198  			source: commandspb.OracleDataSubmission_ORACLE_SOURCE_JSON,
   199  		},
   200  	}
   201  
   202  	for _, tc := range tcs {
   203  		t.Run(tc.name, func(tt *testing.T) {
   204  			// given
   205  			pubKeyB := []byte("0xdeadbeef")
   206  			pubKey := crypto.NewPublicKey(hex.EncodeToString(pubKeyB), pubKeyB)
   207  			rawData := commandspb.OracleDataSubmission{
   208  				Source:  tc.source,
   209  				Payload: internalOraclePayload(tt),
   210  			}
   211  
   212  			// when
   213  			adaptor := stubbedAdaptors()
   214  			normalisedData, err := adaptor.Normalise(pubKey, rawData)
   215  
   216  			// then
   217  			require.Error(tt, err)
   218  			assert.Nil(tt, normalisedData)
   219  		})
   220  	}
   221  }