git.gammaspectra.live/P2Pool/consensus/v3@v3.8.0/monero/client/levin/levin_test.go (about) 1 package levin_test 2 3 import ( 4 "fmt" 5 "reflect" 6 "strings" 7 "testing" 8 9 "git.gammaspectra.live/P2Pool/consensus/v3/monero/client/levin" 10 ) 11 12 func assertNoError(t *testing.T, err error, msgAndArgs ...any) { 13 if err != nil { 14 message := "" 15 if len(msgAndArgs) > 0 { 16 message = fmt.Sprint(msgAndArgs...) + ": " 17 } 18 t.Errorf("%sunexpected err: %s", message, err) 19 } 20 } 21 22 func assertError(t *testing.T, err error, msgAndArgs ...any) { 23 if err == nil { 24 message := "" 25 if len(msgAndArgs) > 0 { 26 message = fmt.Sprint(msgAndArgs...) + ": " 27 } 28 t.Errorf("%sexpected err", message) 29 } 30 } 31 32 func assertContains(t *testing.T, actual, expected string, msgAndArgs ...any) { 33 if !strings.Contains(actual, expected) { 34 message := "" 35 if len(msgAndArgs) > 0 { 36 message = fmt.Sprint(msgAndArgs...) + ": " 37 } 38 t.Errorf("%sactual: %v expected: %v", message, actual, expected) 39 } 40 } 41 42 func assertEqual(t *testing.T, actual, expected any, msgAndArgs ...any) { 43 if !reflect.DeepEqual(actual, expected) { 44 message := "" 45 if len(msgAndArgs) > 0 { 46 message = fmt.Sprint(msgAndArgs...) + ": " 47 } 48 t.Errorf("%sactual: %v expected: %v", message, actual, expected) 49 } 50 } 51 52 func it(t *testing.T, msg string, f func(t *testing.T)) { 53 t.Run(msg, func(t *testing.T) { 54 f(t) 55 }) 56 } 57 58 func TestLevin(t *testing.T) { 59 t.Parallel() 60 t.Run("NewHeaderFromBytes", func(t *testing.T) { 61 it(t, "fails w/ wrong size", func(t *testing.T) { 62 bytes := []byte{ 63 0xff, 64 } 65 66 _, err := levin.NewHeaderFromBytesBytes(bytes) 67 assertError(t, err) 68 }) 69 70 it(t, "fails w/ wrong signature", func(t *testing.T) { 71 bytes := []byte{ 72 0xff, 0xff, 0xff, 0xff, // signature 73 0xff, 0xff, 0xff, 0xff, 74 0x00, 0x00, 0x00, 0x00, // length 75 0x00, 0x00, 0x00, 0x00, // 76 0x00, // expects response 77 0x00, 0x00, 0x00, 0x00, // command 78 0x00, 0x00, 0x00, 0x00, // return code 79 0x00, 0x00, 0x00, 0x00, // flags 80 0x00, 0x00, 0x00, 0x00, // version 81 } 82 83 _, err := levin.NewHeaderFromBytesBytes(bytes) 84 assertError(t, err) 85 assertContains(t, err.Error(), "signature mismatch") 86 }) 87 88 it(t, "fails w/ invalid command", func(t *testing.T) { 89 bytes := []byte{ 90 0x01, 0x21, 0x01, 0x01, // signature 91 0x01, 0x01, 0x01, 0x01, 92 0x01, 0x00, 0x00, 0x00, // length 93 0x00, 0x00, 0x00, 0x00, // 94 0x01, // expects response 95 0xff, 0xff, 0xff, 0xff, // command 96 0x00, 0x00, 0x00, 0x00, // return code 97 0x00, 0x00, 0x00, 0x00, // flags 98 0x00, 0x00, 0x00, 0x00, // version 99 } 100 101 _, err := levin.NewHeaderFromBytesBytes(bytes) 102 assertError(t, err) 103 assertContains(t, err.Error(), "invalid command") 104 }) 105 106 it(t, "fails w/ invalid return code", func(t *testing.T) { 107 bytes := []byte{ 108 0x01, 0x21, 0x01, 0x01, // signature 109 0x01, 0x01, 0x01, 0x01, 110 0x01, 0x00, 0x00, 0x00, // length 111 0x00, 0x00, 0x00, 0x00, // 112 0x01, // expects response 113 0xe9, 0x03, 0x00, 0x00, // command 114 0xaa, 0xaa, 0xaa, 0xaa, // return code 115 0x00, 0x00, 0x00, 0x00, // flags 116 0x00, 0x00, 0x00, 0x00, // version 117 } 118 119 _, err := levin.NewHeaderFromBytesBytes(bytes) 120 assertError(t, err) 121 assertContains(t, err.Error(), "invalid return code") 122 }) 123 124 it(t, "fails w/ invalid version", func(t *testing.T) { 125 bytes := []byte{ 126 0x01, 0x21, 0x01, 0x01, // signature 127 0x01, 0x01, 0x01, 0x01, 128 0x01, 0x00, 0x00, 0x00, // length 129 0x00, 0x00, 0x00, 0x00, // 130 0x01, // expects response 131 0xe9, 0x03, 0x00, 0x00, // command 132 0x00, 0x00, 0x00, 0x00, // return code 133 0x02, 0x00, 0x00, 0x00, // flags 134 0x00, 0x00, 0x00, 0x00, // version 135 } 136 137 _, err := levin.NewHeaderFromBytesBytes(bytes) 138 assertError(t, err) 139 assertContains(t, err.Error(), "invalid version") 140 }) 141 142 it(t, "assembles properly from pong", func(t *testing.T) { 143 bytes := []byte{ 144 0x01, 0x21, 0x01, 0x01, // signature 145 0x01, 0x01, 0x01, 0x01, 146 0x01, 0x00, 0x00, 0x00, // length 147 0x00, 0x00, 0x00, 0x00, // 148 0x01, // expects response 149 0xeb, 0x03, 0x00, 0x00, // command 150 0x00, 0x00, 0x00, 0x00, // return code 151 0x02, 0x00, 0x00, 0x00, // flags 152 0x01, 0x00, 0x00, 0x00, // version 153 } 154 155 header, err := levin.NewHeaderFromBytesBytes(bytes) 156 assertNoError(t, err) 157 assertEqual(t, header.Command, levin.CommandPing) 158 assertEqual(t, header.ReturnCode, levin.LevinOk) 159 assertEqual(t, header.Flags, levin.LevinPacketReponse) 160 assertEqual(t, header.Version, levin.LevinProtocolVersion) 161 }) 162 }) 163 164 t.Run("NewRequestHeader", func(t *testing.T) { 165 it(t, "assembles properly w/ ping", func(t *testing.T) { 166 bytes := levin.NewRequestHeader(levin.CommandPing, 1).Bytes() 167 168 assertEqual(t, bytes, []byte{ 169 0x01, 0x21, 0x01, 0x01, // signature 170 0x01, 0x01, 0x01, 0x01, 171 0x01, 0x00, 0x00, 0x00, // length -- 0 for a ping msg 172 0x00, 0x00, 0x00, 0x00, 173 0x01, // expects response -- `true` bool 174 0xeb, 0x03, 0x00, 0x00, // command -- 1003 for ping 175 0x00, 0x00, 0x00, 0x00, // return code -- 0 for requests 176 0x01, 0x00, 0x00, 0x00, // flags -- Q(1st lsb) set for req 177 0x01, 0x00, 0x00, 0x00, // version 178 }) 179 }) 180 181 it(t, "assembles properly w/ handshake", func(t *testing.T) { 182 bytes := levin.NewRequestHeader(levin.CommandHandshake, 4).Bytes() 183 184 assertEqual(t, bytes, []byte{ 185 0x01, 0x21, 0x01, 0x01, // signature 186 0x01, 0x01, 0x01, 0x01, 187 0x04, 0x00, 0x00, 0x00, // length -- 0 for a ping msg 188 0x00, 0x00, 0x00, 0x00, 189 0x01, // expects response -- `true` bool 190 0xe9, 0x03, 0x00, 0x00, 191 0x00, 0x00, 0x00, 0x00, // return code -- 0 for requests 192 0x01, 0x00, 0x00, 0x00, // flags -- Q(1st lsb) set for req 193 0x01, 0x00, 0x00, 0x00, // version 194 }) 195 }) 196 }) 197 }