go-hep.org/x/hep@v0.38.1/xrootd/xrdproto/xrdproto_test.go (about) 1 // Copyright ©2018 The go-hep Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package xrdproto // import "go-hep.org/x/hep/xrootd/xrdproto" 6 7 import ( 8 "bytes" 9 "crypto/rand" 10 "encoding/binary" 11 "fmt" 12 "io" 13 "reflect" 14 "testing" 15 "time" 16 17 "go-hep.org/x/hep/xrootd/internal/xrdenc" 18 ) 19 20 func TestReadRequest(t *testing.T) { 21 header := make([]byte, RequestHeaderLength+16+4) 22 data := make([]byte, 10) 23 _, _ = rand.Read(data) 24 binary.BigEndian.PutUint32(header[RequestHeaderLength+16:], 10) 25 26 for _, tc := range []struct { 27 name string 28 data []byte 29 want []byte 30 err error 31 }{ 32 { 33 name: "EOF", 34 err: io.EOF, 35 data: []byte{}, 36 }, 37 { 38 name: "Without data", 39 data: make([]byte, RequestHeaderLength+16+4), 40 want: make([]byte, RequestHeaderLength+16+4), 41 }, 42 { 43 name: "With data", 44 data: append(header, data...), 45 want: append(header, data...), 46 }, 47 { 48 name: "Header with non-zero length but without data", 49 err: io.EOF, 50 data: header, 51 }, 52 } { 53 t.Run(tc.name, func(t *testing.T) { 54 reader := bytes.NewBuffer(tc.data) 55 got, err := ReadRequest(reader) 56 if err != tc.err { 57 t.Errorf("error doesn't match:\ngot = %v\nwant = %v", err, tc.err) 58 } 59 if !reflect.DeepEqual(got, tc.want) { 60 t.Errorf("data doesn't match:\ngot = %v\nwant = %v", got, tc.want) 61 } 62 if reader.Len() != 0 { 63 t.Errorf("reader was not read to the end: %v", reader.Bytes()) 64 } 65 }) 66 } 67 } 68 69 func TestReadResponse(t *testing.T) { 70 header := make([]byte, RequestHeaderLength+16+4) 71 data := make([]byte, 10) 72 _, _ = rand.Read(data) 73 binary.BigEndian.PutUint32(header[RequestHeaderLength+16:], 10) 74 75 for _, tc := range []struct { 76 name string 77 data []byte 78 wantHeader ResponseHeader 79 wantData []byte 80 err error 81 }{ 82 { 83 name: "EOF", 84 err: io.EOF, 85 data: []byte{}, 86 }, 87 { 88 name: "Without data", 89 data: []byte{1, 2, 0, 0, 0, 0, 0, 0}, 90 wantHeader: ResponseHeader{StreamID: StreamID{1, 2}}, 91 }, 92 { 93 name: "With data", 94 data: []byte{1, 2, 0, 0, 0, 0, 0, 5, 1, 2, 3, 4, 5}, 95 wantHeader: ResponseHeader{StreamID: StreamID{1, 2}, DataLength: 5}, 96 wantData: []byte{1, 2, 3, 4, 5}, 97 }, 98 { 99 name: "Header with non-zero length but without data", 100 err: io.EOF, 101 data: []byte{1, 2, 0, 0, 0, 0, 0, 5}, 102 wantHeader: ResponseHeader{StreamID: StreamID{1, 2}, DataLength: 5}, 103 }, 104 } { 105 t.Run(tc.name, func(t *testing.T) { 106 reader := bytes.NewBuffer(tc.data) 107 gotHeader, gotData, err := ReadResponse(reader) 108 if err != tc.err { 109 t.Errorf("error doesn't match:\ngot = %v\nwant = %v", err, tc.err) 110 } 111 if !reflect.DeepEqual(gotHeader, tc.wantHeader) { 112 t.Errorf("header doesn't match:\ngot = %v\nwant = %v", gotHeader, tc.wantHeader) 113 } 114 if !reflect.DeepEqual(gotData, tc.wantData) { 115 t.Errorf("data doesn't match:\ngot = %v\nwant = %v", gotData, tc.wantData) 116 } 117 if reader.Len() != 0 { 118 t.Errorf("reader was not read to the end: %v", reader.Bytes()) 119 } 120 }) 121 } 122 } 123 124 func TestWriteResponse(t *testing.T) { 125 header := make([]byte, RequestHeaderLength+16+4) 126 data := make([]byte, 10) 127 _, _ = rand.Read(data) 128 binary.BigEndian.PutUint32(header[RequestHeaderLength+16:], 10) 129 130 for _, tc := range []struct { 131 name string 132 wantData []byte 133 header ResponseHeader 134 err error 135 streamID StreamID 136 status ResponseStatus 137 resp Marshaler 138 }{ 139 { 140 name: "With data", 141 wantData: []byte{1, 2, 15, 163, 0, 0, 0, 5, 0, 0, 0, 12, 0}, 142 status: Error, 143 streamID: StreamID{1, 2}, 144 resp: &ServerError{Code: 12}, 145 }, 146 { 147 name: "Without data", 148 wantData: []byte{1, 2, 0, 0, 0, 0, 0, 0}, 149 status: Ok, 150 streamID: StreamID{1, 2}, 151 }, 152 } { 153 t.Run(tc.name, func(t *testing.T) { 154 var writer bytes.Buffer 155 err := WriteResponse(&writer, tc.streamID, tc.status, tc.resp) 156 if err != tc.err { 157 t.Errorf("error doesn't match:\ngot = %v\nwant = %v", err, tc.err) 158 } 159 if !reflect.DeepEqual(writer.Bytes(), tc.wantData) { 160 t.Errorf("data doesn't match:\ngot = %v\nwant = %v", writer.Bytes(), tc.wantData) 161 } 162 }) 163 } 164 } 165 166 func TestWaitResponse(t *testing.T) { 167 for _, want := range []WaitResponse{ 168 {Duration: 0}, 169 {Duration: 42 * time.Second}, 170 {Duration: 42 * time.Hour}, 171 } { 172 t.Run("", func(t *testing.T) { 173 var ( 174 err error 175 w = new(xrdenc.WBuffer) 176 got WaitResponse 177 ) 178 179 err = want.MarshalXrd(w) 180 if err != nil { 181 t.Fatalf("could not marshal response: %v", err) 182 } 183 184 r := xrdenc.NewRBuffer(w.Bytes()) 185 err = got.UnmarshalXrd(r) 186 if err != nil { 187 t.Fatalf("could not unmarshal response: %v", err) 188 } 189 190 if !reflect.DeepEqual(got, want) { 191 t.Fatalf("round trip failed\ngot = %#v\nwant= %#v\n", got, want) 192 } 193 }) 194 } 195 } 196 197 func TestServerError(t *testing.T) { 198 for _, want := range []ServerError{ 199 {Code: IOError, Message: ""}, 200 {Code: NotAuthorized, Message: "not authorized"}, 201 {Code: NotFound, Message: "not\nfound"}, 202 } { 203 t.Run("", func(t *testing.T) { 204 var ( 205 err error 206 w = new(xrdenc.WBuffer) 207 got ServerError 208 ) 209 210 err = want.MarshalXrd(w) 211 if err != nil { 212 t.Fatalf("could not marshal server error: %v", err) 213 } 214 215 r := xrdenc.NewRBuffer(w.Bytes()) 216 err = got.UnmarshalXrd(r) 217 if err != nil { 218 t.Fatalf("could not unmarshal server error: %v", err) 219 } 220 221 if !reflect.DeepEqual(got, want) { 222 t.Fatalf("round trip failed\ngot = %#v\nwant= %#v\n", got, want) 223 } 224 225 if got, want := got.Error(), want.Error(); got != want { 226 t.Fatalf("error messages differ: got=%q, want=%q", got, want) 227 } 228 }) 229 } 230 } 231 232 func TestRequestHeader(t *testing.T) { 233 for _, want := range []RequestHeader{ 234 {StreamID: StreamID{1, 2}, RequestID: 2}, 235 } { 236 t.Run("", func(t *testing.T) { 237 var ( 238 err error 239 w = new(xrdenc.WBuffer) 240 got RequestHeader 241 ) 242 243 err = want.MarshalXrd(w) 244 if err != nil { 245 t.Fatalf("could not marshal: %v", err) 246 } 247 248 r := xrdenc.NewRBuffer(w.Bytes()) 249 err = got.UnmarshalXrd(r) 250 if err != nil { 251 t.Fatalf("could not unmarshal: %v", err) 252 } 253 254 if !reflect.DeepEqual(got, want) { 255 t.Fatalf("round trip failed\ngot = %#v\nwant= %#v\n", got, want) 256 } 257 }) 258 } 259 } 260 261 func TestResponseHeaderError(t *testing.T) { 262 get := func(err error) string { 263 if err != nil { 264 return err.Error() 265 } 266 return "" 267 } 268 269 for _, tc := range []struct { 270 hdr ResponseHeader 271 data []byte 272 err error 273 }{ 274 { 275 hdr: ResponseHeader{Status: Ok}, 276 data: nil, 277 err: nil, 278 }, 279 { 280 hdr: ResponseHeader{Status: OkSoFar}, 281 data: nil, 282 err: nil, 283 }, 284 { 285 hdr: ResponseHeader{Status: Error}, 286 data: func() []byte { 287 w := new(xrdenc.WBuffer) 288 err := ServerError{Code: IOError, Message: "boo"}.MarshalXrd(w) 289 if err != nil { 290 t.Fatal(err) 291 } 292 return w.Bytes() 293 }(), 294 err: ServerError{Code: IOError, Message: "boo"}, 295 }, 296 { 297 hdr: ResponseHeader{Status: Error}, 298 data: []byte{1, 2, 3}, 299 err: fmt.Errorf("xrootd: invalid ResponseHeader error: %w", io.ErrShortBuffer), 300 }, 301 { 302 hdr: ResponseHeader{Status: Error}, 303 data: []byte{1, 2, 3, 4}, 304 err: fmt.Errorf("xrootd: error occurred during unmarshaling of a server error: xrootd: missing error message in server response"), 305 }, 306 } { 307 t.Run("", func(t *testing.T) { 308 err := tc.hdr.Error(tc.data) 309 if get(err) != get(tc.err) { 310 t.Fatalf("got=%#v, want=%#v", err, tc.err) 311 } 312 }) 313 } 314 } 315 316 func TestSecurityOverride(t *testing.T) { 317 for _, want := range []SecurityOverride{ 318 {RequestIndex: 1, RequestLevel: SignNone}, 319 {RequestIndex: 2, RequestLevel: SignLikely}, 320 {RequestIndex: 3, RequestLevel: SignNeeded}, 321 } { 322 t.Run("", func(t *testing.T) { 323 var ( 324 err error 325 w = new(xrdenc.WBuffer) 326 got SecurityOverride 327 ) 328 329 err = want.MarshalXrd(w) 330 if err != nil { 331 t.Fatalf("could not marshal: %v", err) 332 } 333 334 r := xrdenc.NewRBuffer(w.Bytes()) 335 err = got.UnmarshalXrd(r) 336 if err != nil { 337 t.Fatalf("could not unmarshal: %v", err) 338 } 339 340 if !reflect.DeepEqual(got, want) { 341 t.Fatalf("round trip failed\ngot = %#v\nwant= %#v\n", got, want) 342 } 343 }) 344 } 345 } 346 347 func TestOpaque(t *testing.T) { 348 for _, tc := range []struct { 349 path string 350 want string 351 }{ 352 {"hello", "hello"}, 353 {"hello?", ""}, 354 {"hello?boo", "boo"}, 355 {"?boo", "boo"}, 356 } { 357 t.Run(tc.path, func(t *testing.T) { 358 got := Opaque(tc.path) 359 if got != tc.want { 360 t.Fatalf("got=%q, want=%q", got, tc.want) 361 } 362 }) 363 } 364 } 365 366 func TestSetOpaque(t *testing.T) { 367 for _, tc := range []struct { 368 path string 369 opaq string 370 want string 371 }{ 372 {"", "v", "?v"}, 373 {"hello", "v", "hello?v"}, 374 {"hello?", "v", "hello?v"}, 375 {"hello?boo", "v", "hello?v"}, 376 {"?boo", "v", "?v"}, 377 {"hello?boo?", "v", "hello?boo?v"}, 378 {"hello?boo?bar", "v", "hello?boo?v"}, 379 {"hello?boo=value?bar=33", "v", "hello?boo=value?v"}, 380 } { 381 t.Run(tc.path, func(t *testing.T) { 382 got := tc.path 383 SetOpaque(&got, tc.opaq) 384 if got != tc.want { 385 t.Fatalf("got=%q, want=%q", got, tc.want) 386 } 387 }) 388 } 389 }