code.vegaprotocol.io/vega@v0.79.0/core/netparams/values_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 netparams_test
    17  
    18  import (
    19  	"encoding/json"
    20  	"errors"
    21  	"testing"
    22  
    23  	"code.vegaprotocol.io/vega/core/netparams"
    24  	"code.vegaprotocol.io/vega/libs/num"
    25  	"code.vegaprotocol.io/vega/protos/vega"
    26  
    27  	"github.com/stretchr/testify/assert"
    28  	"github.com/stretchr/testify/require"
    29  )
    30  
    31  type A struct {
    32  	S string
    33  	I int
    34  }
    35  
    36  func (a *A) Reset() { *a = A{} }
    37  
    38  type B struct {
    39  	F  float32
    40  	SS []string
    41  }
    42  
    43  func (b *B) Reset() { *b = B{} }
    44  
    45  func TestNegativeUint(t *testing.T) {
    46  	require.Error(t, errors.New("invalid uint"), netparams.NewUint().Mutable(true).Update("-30"))
    47  	require.Error(t, errors.New("invalid uint"), netparams.NewUint().Mutable(true).Update("- 30"))
    48  	require.Error(t, errors.New("invalid uint"), netparams.NewUint().Mutable(true).Update("    -     3 0"))
    49  	require.NoError(t, netparams.NewUint().Mutable(true).Update("30"))
    50  }
    51  
    52  func TestJSONValues(t *testing.T) {
    53  	validator := func(v interface{}, p interface{}) error {
    54  		a, ok := v.(*A)
    55  		if !ok {
    56  			return errors.New("invalid type")
    57  		}
    58  
    59  		if len(a.S) <= 0 {
    60  			return errors.New("empty string")
    61  		}
    62  		if a.I < 0 {
    63  			return errors.New("I negative")
    64  		}
    65  
    66  		b := &A{}
    67  		json.Unmarshal([]byte(p.(string)), b)
    68  
    69  		if !ok {
    70  			return errors.New("invalid type B")
    71  		}
    72  
    73  		if a.I < b.I {
    74  			return errors.New("cannot amended to lower value")
    75  		}
    76  
    77  		return nil
    78  	}
    79  
    80  	// happy case, all good
    81  	j := netparams.NewJSON(&A{}, validator).Mutable(true).MustUpdate(`{"s": "notempty", "i": 42}`)
    82  	assert.NotNil(t, j)
    83  	err := j.Validate(`{"s": "notempty", "i": 84}`)
    84  	assert.NoError(t, err)
    85  
    86  	err = j.Update(`{"s": "notempty", "i": 84}`)
    87  	assert.NoError(t, err)
    88  
    89  	a := &A{}
    90  	err = j.ToJSONStruct(a)
    91  	assert.NoError(t, err)
    92  
    93  	assert.Equal(t, a.I, 84)
    94  	assert.Equal(t, a.S, "notempty")
    95  
    96  	// errors cases now
    97  
    98  	// invalid field
    99  	err = j.Validate(`{"s": "notempty", "i": 84, "nope": 3.2}`)
   100  	assert.EqualError(t, err, "unable to unmarshal value, json: unknown field \"nope\"")
   101  
   102  	err = j.Update(`{"s": "notempty", "i": 84, "nope": 3.2}`)
   103  	assert.EqualError(t, err, "unable to unmarshal value, json: unknown field \"nope\"")
   104  
   105  	// invalid type
   106  	b := &B{}
   107  	err = j.ToJSONStruct(b)
   108  	assert.EqualError(t, err, "incompatible type")
   109  
   110  	// valid type, field validation failed
   111  	err = j.Update(`{"s": "", "i": 84}`)
   112  	assert.EqualError(t, err, "empty string")
   113  
   114  	// flex rule that prevents update to a lower value of i
   115  	err = j.Validate(`{"s": "notempty", "i": 1}`)
   116  	assert.EqualError(t, err, "cannot amended to lower value")
   117  }
   118  
   119  func TestJSONVPriceMonitoringParameters(t *testing.T) {
   120  	// happy case, populated parameters array
   121  	validPmJSONString := `{"triggers": [{"horizon": 60, "probability": "0.95", "auction_extension": 90},{"horizon": 120, "probability": "0.99", "auction_extension": 180}]}`
   122  	j := netparams.NewJSON(&vega.PriceMonitoringParameters{}, netparams.PriceMonitoringParametersValidation).Mutable(true).MustUpdate(validPmJSONString)
   123  	assert.NotNil(t, j)
   124  	err := j.Validate(validPmJSONString)
   125  	assert.NoError(t, err)
   126  
   127  	err = j.Update(validPmJSONString)
   128  	assert.NoError(t, err)
   129  
   130  	pm := &vega.PriceMonitoringParameters{}
   131  	err = j.ToJSONStruct(pm)
   132  	assert.NoError(t, err)
   133  
   134  	assert.Equal(t, 2, len(pm.Triggers))
   135  	assert.Equal(t, int64(60), pm.Triggers[0].Horizon)
   136  	assert.Equal(t, "0.95", pm.Triggers[0].Probability)
   137  	assert.Equal(t, int64(90), pm.Triggers[0].AuctionExtension)
   138  	assert.Equal(t, int64(120), pm.Triggers[1].Horizon)
   139  	assert.Equal(t, "0.99", pm.Triggers[1].Probability)
   140  	assert.Equal(t, int64(180), pm.Triggers[1].AuctionExtension)
   141  
   142  	// happy case, empty parameters array
   143  	validPmJSONString = `{"triggers": []}`
   144  	j = netparams.NewJSON(&vega.PriceMonitoringParameters{}, netparams.PriceMonitoringParametersValidation).Mutable(true).MustUpdate(validPmJSONString)
   145  	assert.NotNil(t, j)
   146  	err = j.Validate(validPmJSONString)
   147  	assert.NoError(t, err)
   148  
   149  	err = j.Update(validPmJSONString)
   150  	assert.NoError(t, err)
   151  
   152  	pm = &vega.PriceMonitoringParameters{}
   153  	err = j.ToJSONStruct(pm)
   154  	assert.NoError(t, err)
   155  
   156  	assert.Equal(t, 0, len(pm.Triggers))
   157  
   158  	// errors cases now
   159  
   160  	// invalid field
   161  	invalidPmJSONString := `{"triggers": [{"horizon": 60, "probability": "0.95", "auction_extension": 90},{"horizon": 120, "probability": "0.99", "auction_extension": 180, "nope": "abc"}]}`
   162  	expectedErrorMsg := "unable to unmarshal value, json: unknown field \"nope\""
   163  	err = j.Validate(invalidPmJSONString)
   164  	assert.EqualError(t, err, expectedErrorMsg)
   165  
   166  	err = j.Update(invalidPmJSONString)
   167  	assert.EqualError(t, err, expectedErrorMsg)
   168  
   169  	// invalid value
   170  
   171  	// horizon
   172  	invalidPmJSONString = `{"triggers": [{"horizon": 0, "probability": "0.95", "auction_extension": 90},{"horizon": 120, "probability": "0.99", "auction_extension": 180}]}`
   173  	expectedErrorMsg = "triggers.horizon must be greater than `0`, got `0`"
   174  	err = j.Validate(invalidPmJSONString)
   175  	assert.EqualError(t, err, expectedErrorMsg)
   176  
   177  	err = j.Update(invalidPmJSONString)
   178  	assert.EqualError(t, err, expectedErrorMsg)
   179  
   180  	// probability
   181  	invalidPmJSONString = `{"triggers": [{"horizon": 60, "probability": "0", "auction_extension": 90},{"horizon": 120, "probability": "0.99", "auction_extension": 180}]}`
   182  	expectedErrorMsg = "triggers.probability must be greater than `0`, got `0`"
   183  	err = j.Validate(invalidPmJSONString)
   184  	assert.EqualError(t, err, expectedErrorMsg)
   185  
   186  	err = j.Update(invalidPmJSONString)
   187  	assert.EqualError(t, err, expectedErrorMsg)
   188  
   189  	invalidPmJSONString = `{"triggers": [{"horizon": 60, "probability": "1", "auction_extension": 90},{"horizon": 120, "probability": "0.99", "auction_extension": 180}]}`
   190  	expectedErrorMsg = "triggers.probability must be lower than `1`, got `1`"
   191  	err = j.Validate(invalidPmJSONString)
   192  	assert.EqualError(t, err, expectedErrorMsg)
   193  
   194  	err = j.Update(invalidPmJSONString)
   195  	assert.EqualError(t, err, expectedErrorMsg)
   196  
   197  	// auctionExtension
   198  	invalidPmJSONString = `{"triggers": [{"horizon": 60, "probability": "0.95", "auction_extension": 0},{"horizon": 120, "probability": "0.99", "auction_extension": 180}]}`
   199  	expectedErrorMsg = "triggers.auction_extension must be greater than `0`, got `0`"
   200  	err = j.Validate(invalidPmJSONString)
   201  	assert.EqualError(t, err, expectedErrorMsg)
   202  }
   203  
   204  func TestDependent(t *testing.T) {
   205  	u1 := netparams.NewUint(netparams.UintGTE(num.NewUint(1)), netparams.UintLTE(num.NewUint(1000))).Mutable(true).MustUpdate("500")
   206  	u2 := netparams.NewUint(netparams.UintGTE(num.NewUint(1)), netparams.UintLTE(num.NewUint(1000))).Mutable(true).MustUpdate("100")
   207  	// we want to enforce u1 >= 2x u2
   208  	u1.AddRules(netparams.UintDependentGTE("u2", u2, num.MustDecimalFromString("2")))
   209  	u2.AddRules(netparams.UintDependentLTE("u1", u1, num.MustDecimalFromString("0.5")))
   210  
   211  	// try to update u1 to less than 2 * u2
   212  	require.Equal(t, "expect >= 200 (u2 * 2) got 100", u1.Update("100").Error())
   213  	require.NoError(t, u1.Update("200"))
   214  
   215  	// try to update u2 to more than 0.5 u1
   216  	require.Equal(t, "expect <= 100 (u1 * 0.5) got 101", u2.Update("101").Error())
   217  	require.NoError(t, u2.Update("99"))
   218  }