1// Copyright (c) 2012, 2013 Ugorji Nwoke. All rights reserved. 2// Use of this source code is governed by a BSD-style license found in the LICENSE file. 3 4package codec 5 6// Test works by using a slice of interfaces. 7// It can test for encoding/decoding into/from a nil interface{} 8// or passing the object to encode/decode into. 9// 10// There are basically 2 main tests here. 11// First test internally encodes and decodes things and verifies that 12// the artifact was as expected. 13// Second test will use python msgpack to create a bunch of golden files, 14// read those files, and compare them to what it should be. It then 15// writes those files back out and compares the byte streams. 16// 17// Taken together, the tests are pretty extensive. 18 19import ( 20 "bytes" 21 "encoding/gob" 22 "flag" 23 "fmt" 24 "io/ioutil" 25 "math" 26 "net" 27 "net/rpc" 28 "os" 29 "os/exec" 30 "path/filepath" 31 "reflect" 32 "runtime" 33 "strconv" 34 "sync/atomic" 35 "testing" 36 "time" 37) 38 39type testVerifyArg int 40 41const ( 42 testVerifyMapTypeSame testVerifyArg = iota 43 testVerifyMapTypeStrIntf 44 testVerifyMapTypeIntfIntf 45 // testVerifySliceIntf 46 testVerifyForPython 47) 48 49var ( 50 testInitDebug bool 51 testUseIoEncDec bool 52 testStructToArray bool 53 testWriteNoSymbols bool 54 55 _ = fmt.Printf 56 skipVerifyVal interface{} = &(struct{}{}) 57 58 // For Go Time, do not use a descriptive timezone. 59 // It's unnecessary, and makes it harder to do a reflect.DeepEqual. 60 // The Offset already tells what the offset should be, if not on UTC and unknown zone name. 61 timeLoc = time.FixedZone("", -8*60*60) // UTC-08:00 //time.UTC-8 62 timeToCompare1 = time.Date(2012, 2, 2, 2, 2, 2, 2000, timeLoc) 63 timeToCompare2 = time.Date(1900, 2, 2, 2, 2, 2, 2000, timeLoc) 64 timeToCompare3 = time.Unix(0, 0).UTC() 65 timeToCompare4 = time.Time{}.UTC() 66 67 table []interface{} // main items we encode 68 tableVerify []interface{} // we verify encoded things against this after decode 69 tableTestNilVerify []interface{} // for nil interface, use this to verify (rules are different) 70 tablePythonVerify []interface{} // for verifying for python, since Python sometimes 71 // will encode a float32 as float64, or large int as uint 72 testRpcInt = new(TestRpcInt) 73 testMsgpackH = &MsgpackHandle{} 74 testBincH = &BincHandle{} 75 testSimpleH = &SimpleHandle{} 76) 77 78func testInitFlags() { 79 // delete(testDecOpts.ExtFuncs, timeTyp) 80 flag.BoolVar(&testInitDebug, "tg", false, "Test Debug") 81 flag.BoolVar(&testUseIoEncDec, "ti", false, "Use IO Reader/Writer for Marshal/Unmarshal") 82 flag.BoolVar(&testStructToArray, "ts", false, "Set StructToArray option") 83 flag.BoolVar(&testWriteNoSymbols, "tn", false, "Set NoSymbols option") 84} 85 86type AnonInTestStruc struct { 87 AS string 88 AI64 int64 89 AI16 int16 90 AUi64 uint64 91 ASslice []string 92 AI64slice []int64 93} 94 95type TestStruc struct { 96 S string 97 I64 int64 98 I16 int16 99 Ui64 uint64 100 Ui8 uint8 101 B bool 102 By byte 103 104 Sslice []string 105 I64slice []int64 106 I16slice []int16 107 Ui64slice []uint64 108 Ui8slice []uint8 109 Bslice []bool 110 Byslice []byte 111 112 Islice []interface{} 113 Iptrslice []*int64 114 115 AnonInTestStruc 116 117 //M map[interface{}]interface{} `json:"-",bson:"-"` 118 Ms map[string]interface{} 119 Msi64 map[string]int64 120 121 Nintf interface{} //don't set this, so we can test for nil 122 T time.Time 123 Nmap map[string]bool //don't set this, so we can test for nil 124 Nslice []byte //don't set this, so we can test for nil 125 Nint64 *int64 //don't set this, so we can test for nil 126 Mtsptr map[string]*TestStruc 127 Mts map[string]TestStruc 128 Its []*TestStruc 129 Nteststruc *TestStruc 130} 131 132type TestABC struct { 133 A, B, C string 134} 135 136type TestRpcInt struct { 137 i int 138} 139 140func (r *TestRpcInt) Update(n int, res *int) error { r.i = n; *res = r.i; return nil } 141func (r *TestRpcInt) Square(ignore int, res *int) error { *res = r.i * r.i; return nil } 142func (r *TestRpcInt) Mult(n int, res *int) error { *res = r.i * n; return nil } 143func (r *TestRpcInt) EchoStruct(arg TestABC, res *string) error { 144 *res = fmt.Sprintf("%#v", arg) 145 return nil 146} 147func (r *TestRpcInt) Echo123(args []string, res *string) error { 148 *res = fmt.Sprintf("%#v", args) 149 return nil 150} 151 152func testVerifyVal(v interface{}, arg testVerifyArg) (v2 interface{}) { 153 //for python msgpack, 154 // - all positive integers are unsigned 64-bit ints 155 // - all floats are float64 156 switch iv := v.(type) { 157 case int8: 158 if iv > 0 { 159 v2 = uint64(iv) 160 } else { 161 v2 = int64(iv) 162 } 163 case int16: 164 if iv > 0 { 165 v2 = uint64(iv) 166 } else { 167 v2 = int64(iv) 168 } 169 case int32: 170 if iv > 0 { 171 v2 = uint64(iv) 172 } else { 173 v2 = int64(iv) 174 } 175 case int64: 176 if iv > 0 { 177 v2 = uint64(iv) 178 } else { 179 v2 = int64(iv) 180 } 181 case uint8: 182 v2 = uint64(iv) 183 case uint16: 184 v2 = uint64(iv) 185 case uint32: 186 v2 = uint64(iv) 187 case uint64: 188 v2 = uint64(iv) 189 case float32: 190 v2 = float64(iv) 191 case float64: 192 v2 = float64(iv) 193 case []interface{}: 194 m2 := make([]interface{}, len(iv)) 195 for j, vj := range iv { 196 m2[j] = testVerifyVal(vj, arg) 197 } 198 v2 = m2 199 case map[string]bool: 200 switch arg { 201 case testVerifyMapTypeSame: 202 m2 := make(map[string]bool) 203 for kj, kv := range iv { 204 m2[kj] = kv 205 } 206 v2 = m2 207 case testVerifyMapTypeStrIntf, testVerifyForPython: 208 m2 := make(map[string]interface{}) 209 for kj, kv := range iv { 210 m2[kj] = kv 211 } 212 v2 = m2 213 case testVerifyMapTypeIntfIntf: 214 m2 := make(map[interface{}]interface{}) 215 for kj, kv := range iv { 216 m2[kj] = kv 217 } 218 v2 = m2 219 } 220 case map[string]interface{}: 221 switch arg { 222 case testVerifyMapTypeSame: 223 m2 := make(map[string]interface{}) 224 for kj, kv := range iv { 225 m2[kj] = testVerifyVal(kv, arg) 226 } 227 v2 = m2 228 case testVerifyMapTypeStrIntf, testVerifyForPython: 229 m2 := make(map[string]interface{}) 230 for kj, kv := range iv { 231 m2[kj] = testVerifyVal(kv, arg) 232 } 233 v2 = m2 234 case testVerifyMapTypeIntfIntf: 235 m2 := make(map[interface{}]interface{}) 236 for kj, kv := range iv { 237 m2[kj] = testVerifyVal(kv, arg) 238 } 239 v2 = m2 240 } 241 case map[interface{}]interface{}: 242 m2 := make(map[interface{}]interface{}) 243 for kj, kv := range iv { 244 m2[testVerifyVal(kj, arg)] = testVerifyVal(kv, arg) 245 } 246 v2 = m2 247 case time.Time: 248 switch arg { 249 case testVerifyForPython: 250 if iv2 := iv.UnixNano(); iv2 > 0 { 251 v2 = uint64(iv2) 252 } else { 253 v2 = int64(iv2) 254 } 255 default: 256 v2 = v 257 } 258 default: 259 v2 = v 260 } 261 return 262} 263 264func testInit() { 265 gob.Register(new(TestStruc)) 266 if testInitDebug { 267 ts0 := newTestStruc(2, false) 268 fmt.Printf("====> depth: %v, ts: %#v\n", 2, ts0) 269 } 270 271 testBincH.StructToArray = testStructToArray 272 if testWriteNoSymbols { 273 testBincH.AsSymbols = AsSymbolNone 274 } else { 275 testBincH.AsSymbols = AsSymbolAll 276 } 277 testMsgpackH.StructToArray = testStructToArray 278 testMsgpackH.RawToString = true 279 // testMsgpackH.AddExt(byteSliceTyp, 0, testMsgpackH.BinaryEncodeExt, testMsgpackH.BinaryDecodeExt) 280 // testMsgpackH.AddExt(timeTyp, 1, testMsgpackH.TimeEncodeExt, testMsgpackH.TimeDecodeExt) 281 timeEncExt := func(rv reflect.Value) ([]byte, error) { 282 return encodeTime(rv.Interface().(time.Time)), nil 283 } 284 timeDecExt := func(rv reflect.Value, bs []byte) error { 285 tt, err := decodeTime(bs) 286 if err == nil { 287 rv.Set(reflect.ValueOf(tt)) 288 } 289 return err 290 } 291 292 // add extensions for msgpack, simple for time.Time, so we can encode/decode same way. 293 testMsgpackH.AddExt(timeTyp, 1, timeEncExt, timeDecExt) 294 testSimpleH.AddExt(timeTyp, 1, timeEncExt, timeDecExt) 295 296 primitives := []interface{}{ 297 int8(-8), 298 int16(-1616), 299 int32(-32323232), 300 int64(-6464646464646464), 301 uint8(192), 302 uint16(1616), 303 uint32(32323232), 304 uint64(6464646464646464), 305 byte(192), 306 float32(-3232.0), 307 float64(-6464646464.0), 308 float32(3232.0), 309 float64(6464646464.0), 310 false, 311 true, 312 nil, 313 "someday", 314 "", 315 "bytestring", 316 timeToCompare1, 317 timeToCompare2, 318 timeToCompare3, 319 timeToCompare4, 320 } 321 mapsAndStrucs := []interface{}{ 322 map[string]bool{ 323 "true": true, 324 "false": false, 325 }, 326 map[string]interface{}{ 327 "true": "True", 328 "false": false, 329 "uint16(1616)": uint16(1616), 330 }, 331 //add a complex combo map in here. (map has list which has map) 332 //note that after the first thing, everything else should be generic. 333 map[string]interface{}{ 334 "list": []interface{}{ 335 int16(1616), 336 int32(32323232), 337 true, 338 float32(-3232.0), 339 map[string]interface{}{ 340 "TRUE": true, 341 "FALSE": false, 342 }, 343 []interface{}{true, false}, 344 }, 345 "int32": int32(32323232), 346 "bool": true, 347 "LONG STRING": "123456789012345678901234567890123456789012345678901234567890", 348 "SHORT STRING": "1234567890", 349 }, 350 map[interface{}]interface{}{ 351 true: "true", 352 uint8(138): false, 353 "false": uint8(200), 354 }, 355 newTestStruc(0, false), 356 } 357 358 table = []interface{}{} 359 table = append(table, primitives...) //0-19 are primitives 360 table = append(table, primitives) //20 is a list of primitives 361 table = append(table, mapsAndStrucs...) //21-24 are maps. 25 is a *struct 362 363 tableVerify = make([]interface{}, len(table)) 364 tableTestNilVerify = make([]interface{}, len(table)) 365 tablePythonVerify = make([]interface{}, len(table)) 366 367 lp := len(primitives) 368 av := tableVerify 369 for i, v := range table { 370 if i == lp+3 { 371 av[i] = skipVerifyVal 372 continue 373 } 374 //av[i] = testVerifyVal(v, testVerifyMapTypeSame) 375 switch v.(type) { 376 case []interface{}: 377 av[i] = testVerifyVal(v, testVerifyMapTypeSame) 378 case map[string]interface{}: 379 av[i] = testVerifyVal(v, testVerifyMapTypeSame) 380 case map[interface{}]interface{}: 381 av[i] = testVerifyVal(v, testVerifyMapTypeSame) 382 default: 383 av[i] = v 384 } 385 } 386 387 av = tableTestNilVerify 388 for i, v := range table { 389 if i > lp+3 { 390 av[i] = skipVerifyVal 391 continue 392 } 393 av[i] = testVerifyVal(v, testVerifyMapTypeStrIntf) 394 } 395 396 av = tablePythonVerify 397 for i, v := range table { 398 if i > lp+3 { 399 av[i] = skipVerifyVal 400 continue 401 } 402 av[i] = testVerifyVal(v, testVerifyForPython) 403 } 404 405 tablePythonVerify = tablePythonVerify[:24] 406} 407 408func testUnmarshal(v interface{}, data []byte, h Handle) error { 409 if testUseIoEncDec { 410 return NewDecoder(bytes.NewBuffer(data), h).Decode(v) 411 } 412 return NewDecoderBytes(data, h).Decode(v) 413} 414 415func testMarshal(v interface{}, h Handle) (bs []byte, err error) { 416 if testUseIoEncDec { 417 var buf bytes.Buffer 418 err = NewEncoder(&buf, h).Encode(v) 419 bs = buf.Bytes() 420 return 421 } 422 err = NewEncoderBytes(&bs, h).Encode(v) 423 return 424} 425 426func testMarshalErr(v interface{}, h Handle, t *testing.T, name string) (bs []byte, err error) { 427 if bs, err = testMarshal(v, h); err != nil { 428 logT(t, "Error encoding %s: %v, Err: %v", name, v, err) 429 t.FailNow() 430 } 431 return 432} 433 434func testUnmarshalErr(v interface{}, data []byte, h Handle, t *testing.T, name string) (err error) { 435 if err = testUnmarshal(v, data, h); err != nil { 436 logT(t, "Error Decoding into %s: %v, Err: %v", name, v, err) 437 t.FailNow() 438 } 439 return 440} 441 442func newTestStruc(depth int, bench bool) (ts *TestStruc) { 443 var i64a, i64b, i64c, i64d int64 = 64, 6464, 646464, 64646464 444 445 ts = &TestStruc{ 446 S: "some string", 447 I64: math.MaxInt64 * 2 / 3, // 64, 448 I16: 16, 449 Ui64: uint64(int64(math.MaxInt64 * 2 / 3)), // 64, //don't use MaxUint64, as bson can't write it 450 Ui8: 160, 451 B: true, 452 By: 5, 453 454 Sslice: []string{"one", "two", "three"}, 455 I64slice: []int64{1, 2, 3}, 456 I16slice: []int16{4, 5, 6}, 457 Ui64slice: []uint64{137, 138, 139}, 458 Ui8slice: []uint8{210, 211, 212}, 459 Bslice: []bool{true, false, true, false}, 460 Byslice: []byte{13, 14, 15}, 461 462 Islice: []interface{}{"true", true, "no", false, uint64(288), float64(0.4)}, 463 464 Ms: map[string]interface{}{ 465 "true": "true", 466 "int64(9)": false, 467 }, 468 Msi64: map[string]int64{ 469 "one": 1, 470 "two": 2, 471 }, 472 T: timeToCompare1, 473 AnonInTestStruc: AnonInTestStruc{ 474 AS: "A-String", 475 AI64: 64, 476 AI16: 16, 477 AUi64: 64, 478 ASslice: []string{"Aone", "Atwo", "Athree"}, 479 AI64slice: []int64{1, 2, 3}, 480 }, 481 } 482 //For benchmarks, some things will not work. 483 if !bench { 484 //json and bson require string keys in maps 485 //ts.M = map[interface{}]interface{}{ 486 // true: "true", 487 // int8(9): false, 488 //} 489 //gob cannot encode nil in element in array (encodeArray: nil element) 490 ts.Iptrslice = []*int64{nil, &i64a, nil, &i64b, nil, &i64c, nil, &i64d, nil} 491 // ts.Iptrslice = nil 492 } 493 if depth > 0 { 494 depth-- 495 if ts.Mtsptr == nil { 496 ts.Mtsptr = make(map[string]*TestStruc) 497 } 498 if ts.Mts == nil { 499 ts.Mts = make(map[string]TestStruc) 500 } 501 ts.Mtsptr["0"] = newTestStruc(depth, bench) 502 ts.Mts["0"] = *(ts.Mtsptr["0"]) 503 ts.Its = append(ts.Its, ts.Mtsptr["0"]) 504 } 505 return 506} 507 508// doTestCodecTableOne allows us test for different variations based on arguments passed. 509func doTestCodecTableOne(t *testing.T, testNil bool, h Handle, 510 vs []interface{}, vsVerify []interface{}) { 511 //if testNil, then just test for when a pointer to a nil interface{} is passed. It should work. 512 //Current setup allows us test (at least manually) the nil interface or typed interface. 513 logT(t, "================ TestNil: %v ================\n", testNil) 514 for i, v0 := range vs { 515 logT(t, "..............................................") 516 logT(t, " Testing: #%d:, %T, %#v\n", i, v0, v0) 517 b0, err := testMarshalErr(v0, h, t, "v0") 518 if err != nil { 519 continue 520 } 521 logT(t, " Encoded bytes: len: %v, %v\n", len(b0), b0) 522 523 var v1 interface{} 524 525 if testNil { 526 err = testUnmarshal(&v1, b0, h) 527 } else { 528 if v0 != nil { 529 v0rt := reflect.TypeOf(v0) // ptr 530 rv1 := reflect.New(v0rt) 531 err = testUnmarshal(rv1.Interface(), b0, h) 532 v1 = rv1.Elem().Interface() 533 // v1 = reflect.Indirect(reflect.ValueOf(v1)).Interface() 534 } 535 } 536 537 logT(t, " v1 returned: %T, %#v", v1, v1) 538 // if v1 != nil { 539 // logT(t, " v1 returned: %T, %#v", v1, v1) 540 // //we always indirect, because ptr to typed value may be passed (if not testNil) 541 // v1 = reflect.Indirect(reflect.ValueOf(v1)).Interface() 542 // } 543 if err != nil { 544 logT(t, "-------- Error: %v. Partial return: %v", err, v1) 545 failT(t) 546 continue 547 } 548 v0check := vsVerify[i] 549 if v0check == skipVerifyVal { 550 logT(t, " Nil Check skipped: Decoded: %T, %#v\n", v1, v1) 551 continue 552 } 553 554 if err = deepEqual(v0check, v1); err == nil { 555 logT(t, "++++++++ Before and After marshal matched\n") 556 } else { 557 logT(t, "-------- Before and After marshal do not match: Error: %v"+ 558 " ====> GOLDEN: (%T) %#v, DECODED: (%T) %#v\n", err, v0check, v0check, v1, v1) 559 failT(t) 560 } 561 } 562} 563 564func testCodecTableOne(t *testing.T, h Handle) { 565 // func TestMsgpackAllExperimental(t *testing.T) { 566 // dopts := testDecOpts(nil, nil, false, true, true), 567 568 switch v := h.(type) { 569 case *MsgpackHandle: 570 var oldWriteExt, oldRawToString bool 571 oldWriteExt, v.WriteExt = v.WriteExt, true 572 oldRawToString, v.RawToString = v.RawToString, true 573 doTestCodecTableOne(t, false, h, table, tableVerify) 574 v.WriteExt, v.RawToString = oldWriteExt, oldRawToString 575 default: 576 doTestCodecTableOne(t, false, h, table, tableVerify) 577 } 578 // func TestMsgpackAll(t *testing.T) { 579 idxTime, numPrim, numMap := 19, 23, 4 580 581 //skip []interface{} containing time.Time 582 doTestCodecTableOne(t, false, h, table[:numPrim], tableVerify[:numPrim]) 583 doTestCodecTableOne(t, false, h, table[numPrim+1:], tableVerify[numPrim+1:]) 584 // func TestMsgpackNilStringMap(t *testing.T) { 585 var oldMapType reflect.Type 586 v := h.getBasicHandle() 587 oldMapType, v.MapType = v.MapType, mapStrIntfTyp 588 589 //skip time.Time, []interface{} containing time.Time, last map, and newStruc 590 doTestCodecTableOne(t, true, h, table[:idxTime], tableTestNilVerify[:idxTime]) 591 doTestCodecTableOne(t, true, h, table[numPrim+1:numPrim+numMap], tableTestNilVerify[numPrim+1:numPrim+numMap]) 592 593 v.MapType = oldMapType 594 595 // func TestMsgpackNilIntf(t *testing.T) { 596 597 //do newTestStruc and last element of map 598 doTestCodecTableOne(t, true, h, table[numPrim+numMap:], tableTestNilVerify[numPrim+numMap:]) 599 //TODO? What is this one? 600 //doTestCodecTableOne(t, true, h, table[17:18], tableTestNilVerify[17:18]) 601} 602 603func testCodecMiscOne(t *testing.T, h Handle) { 604 b, err := testMarshalErr(32, h, t, "32") 605 // Cannot do this nil one, because faster type assertion decoding will panic 606 // var i *int32 607 // if err = testUnmarshal(b, i, nil); err == nil { 608 // logT(t, "------- Expecting error because we cannot unmarshal to int32 nil ptr") 609 // t.FailNow() 610 // } 611 var i2 int32 = 0 612 err = testUnmarshalErr(&i2, b, h, t, "int32-ptr") 613 if i2 != int32(32) { 614 logT(t, "------- didn't unmarshal to 32: Received: %d", i2) 615 t.FailNow() 616 } 617 618 // func TestMsgpackDecodePtr(t *testing.T) { 619 ts := newTestStruc(0, false) 620 b, err = testMarshalErr(ts, h, t, "pointer-to-struct") 621 if len(b) < 40 { 622 logT(t, "------- Size must be > 40. Size: %d", len(b)) 623 t.FailNow() 624 } 625 logT(t, "------- b: %v", b) 626 ts2 := new(TestStruc) 627 err = testUnmarshalErr(ts2, b, h, t, "pointer-to-struct") 628 if ts2.I64 != math.MaxInt64*2/3 { 629 logT(t, "------- Unmarshal wrong. Expect I64 = 64. Got: %v", ts2.I64) 630 t.FailNow() 631 } 632 633 // func TestMsgpackIntfDecode(t *testing.T) { 634 m := map[string]int{"A": 2, "B": 3} 635 p := []interface{}{m} 636 bs, err := testMarshalErr(p, h, t, "p") 637 638 m2 := map[string]int{} 639 p2 := []interface{}{m2} 640 err = testUnmarshalErr(&p2, bs, h, t, "&p2") 641 642 if m2["A"] != 2 || m2["B"] != 3 { 643 logT(t, "m2 not as expected: expecting: %v, got: %v", m, m2) 644 t.FailNow() 645 } 646 // log("m: %v, m2: %v, p: %v, p2: %v", m, m2, p, p2) 647 checkEqualT(t, p, p2, "p=p2") 648 checkEqualT(t, m, m2, "m=m2") 649 if err = deepEqual(p, p2); err == nil { 650 logT(t, "p and p2 match") 651 } else { 652 logT(t, "Not Equal: %v. p: %v, p2: %v", err, p, p2) 653 t.FailNow() 654 } 655 if err = deepEqual(m, m2); err == nil { 656 logT(t, "m and m2 match") 657 } else { 658 logT(t, "Not Equal: %v. m: %v, m2: %v", err, m, m2) 659 t.FailNow() 660 } 661 662 // func TestMsgpackDecodeStructSubset(t *testing.T) { 663 // test that we can decode a subset of the stream 664 mm := map[string]interface{}{"A": 5, "B": 99, "C": 333} 665 bs, err = testMarshalErr(mm, h, t, "mm") 666 type ttt struct { 667 A uint8 668 C int32 669 } 670 var t2 ttt 671 testUnmarshalErr(&t2, bs, h, t, "t2") 672 t3 := ttt{5, 333} 673 checkEqualT(t, t2, t3, "t2=t3") 674 675 // println(">>>>>") 676 // test simple arrays, non-addressable arrays, slices 677 type tarr struct { 678 A int64 679 B [3]int64 680 C []byte 681 D [3]byte 682 } 683 var tarr0 = tarr{1, [3]int64{2, 3, 4}, []byte{4, 5, 6}, [3]byte{7, 8, 9}} 684 // test both pointer and non-pointer (value) 685 for _, tarr1 := range []interface{}{tarr0, &tarr0} { 686 bs, err = testMarshalErr(tarr1, h, t, "tarr1") 687 var tarr2 tarr 688 testUnmarshalErr(&tarr2, bs, h, t, "tarr2") 689 checkEqualT(t, tarr0, tarr2, "tarr0=tarr2") 690 // fmt.Printf(">>>> err: %v. tarr1: %v, tarr2: %v\n", err, tarr0, tarr2) 691 } 692 693 // test byte array, even if empty (msgpack only) 694 if h == testMsgpackH { 695 type ystruct struct { 696 Anarray []byte 697 } 698 var ya = ystruct{} 699 testUnmarshalErr(&ya, []byte{0x91, 0x90}, h, t, "ya") 700 } 701 702 // test omitempty and nested structs 703 type omitN struct { 704 A *bool 705 } 706 type omitS struct { 707 N *omitN `codec:",omitempty"` 708 } 709 trueV, falseV := true, false 710 var omits = []omitS{ 711 {}, 712 {&omitN{A: &trueV}}, 713 {&omitN{A: &falseV}}, 714 } 715 for _, omitA := range omits { 716 bs, err := testMarshalErr(omitA, h, t, "omitA") 717 if err != nil { 718 logT(t, "error marshalling omitA: %v", err) 719 t.FailNow() 720 } 721 var omit2 omitS 722 err = testUnmarshalErr(&omit2, bs, h, t, "omit2") 723 if err != nil { 724 logT(t, "error unmarshalling omit2: %v", err) 725 t.FailNow() 726 } 727 checkEqualT(t, omitA, omit2, "omitA=omit2") 728 } 729} 730 731func testCodecEmbeddedPointer(t *testing.T, h Handle) { 732 type Z int 733 type A struct { 734 AnInt int 735 } 736 type B struct { 737 *Z 738 *A 739 MoreInt int 740 } 741 var z Z = 4 742 x1 := &B{&z, &A{5}, 6} 743 bs, err := testMarshalErr(x1, h, t, "x1") 744 // fmt.Printf("buf: len(%v): %x\n", buf.Len(), buf.Bytes()) 745 var x2 = new(B) 746 err = testUnmarshalErr(x2, bs, h, t, "x2") 747 err = checkEqualT(t, x1, x2, "x1=x2") 748 _ = err 749} 750 751func doTestRpcOne(t *testing.T, rr Rpc, h Handle, doRequest bool, exitSleepMs time.Duration, 752) (port int) { 753 // rpc needs EOF, which is sent via a panic, and so must be recovered. 754 if !recoverPanicToErr { 755 logT(t, "EXPECTED. set recoverPanicToErr=true, since rpc needs EOF") 756 t.FailNow() 757 } 758 srv := rpc.NewServer() 759 srv.Register(testRpcInt) 760 ln, err := net.Listen("tcp", "127.0.0.1:0") 761 // log("listener: %v", ln.Addr()) 762 checkErrT(t, err) 763 port = (ln.Addr().(*net.TCPAddr)).Port 764 // var opts *DecoderOptions 765 // opts := testDecOpts 766 // opts.MapType = mapStrIntfTyp 767 // opts.RawToString = false 768 serverExitChan := make(chan bool, 1) 769 var serverExitFlag uint64 = 0 770 serverFn := func() { 771 for { 772 conn1, err1 := ln.Accept() 773 // if err1 != nil { 774 // //fmt.Printf("accept err1: %v\n", err1) 775 // continue 776 // } 777 if atomic.LoadUint64(&serverExitFlag) == 1 { 778 serverExitChan <- true 779 conn1.Close() 780 return // exit serverFn goroutine 781 } 782 if err1 == nil { 783 var sc rpc.ServerCodec = rr.ServerCodec(conn1, h) 784 srv.ServeCodec(sc) 785 } 786 } 787 } 788 789 clientFn := func(cc rpc.ClientCodec) { 790 cl := rpc.NewClientWithCodec(cc) 791 defer cl.Close() 792 var up, sq, mult int 793 var rstr string 794 // log("Calling client") 795 checkErrT(t, cl.Call("TestRpcInt.Update", 5, &up)) 796 // log("Called TestRpcInt.Update") 797 checkEqualT(t, testRpcInt.i, 5, "testRpcInt.i=5") 798 checkEqualT(t, up, 5, "up=5") 799 checkErrT(t, cl.Call("TestRpcInt.Square", 1, &sq)) 800 checkEqualT(t, sq, 25, "sq=25") 801 checkErrT(t, cl.Call("TestRpcInt.Mult", 20, &mult)) 802 checkEqualT(t, mult, 100, "mult=100") 803 checkErrT(t, cl.Call("TestRpcInt.EchoStruct", TestABC{"Aa", "Bb", "Cc"}, &rstr)) 804 checkEqualT(t, rstr, fmt.Sprintf("%#v", TestABC{"Aa", "Bb", "Cc"}), "rstr=") 805 checkErrT(t, cl.Call("TestRpcInt.Echo123", []string{"A1", "B2", "C3"}, &rstr)) 806 checkEqualT(t, rstr, fmt.Sprintf("%#v", []string{"A1", "B2", "C3"}), "rstr=") 807 } 808 809 connFn := func() (bs net.Conn) { 810 // log("calling f1") 811 bs, err2 := net.Dial(ln.Addr().Network(), ln.Addr().String()) 812 //fmt.Printf("f1. bs: %v, err2: %v\n", bs, err2) 813 checkErrT(t, err2) 814 return 815 } 816 817 exitFn := func() { 818 atomic.StoreUint64(&serverExitFlag, 1) 819 bs := connFn() 820 <-serverExitChan 821 bs.Close() 822 // serverExitChan <- true 823 } 824 825 go serverFn() 826 runtime.Gosched() 827 //time.Sleep(100 * time.Millisecond) 828 if exitSleepMs == 0 { 829 defer ln.Close() 830 defer exitFn() 831 } 832 if doRequest { 833 bs := connFn() 834 cc := rr.ClientCodec(bs, h) 835 clientFn(cc) 836 } 837 if exitSleepMs != 0 { 838 go func() { 839 defer ln.Close() 840 time.Sleep(exitSleepMs) 841 exitFn() 842 }() 843 } 844 return 845} 846 847// Comprehensive testing that generates data encoded from python msgpack, 848// and validates that our code can read and write it out accordingly. 849// We keep this unexported here, and put actual test in ext_dep_test.go. 850// This way, it can be excluded by excluding file completely. 851func doTestMsgpackPythonGenStreams(t *testing.T) { 852 logT(t, "TestPythonGenStreams") 853 tmpdir, err := ioutil.TempDir("", "golang-msgpack-test") 854 if err != nil { 855 logT(t, "-------- Unable to create temp directory\n") 856 t.FailNow() 857 } 858 defer os.RemoveAll(tmpdir) 859 logT(t, "tmpdir: %v", tmpdir) 860 cmd := exec.Command("python", "msgpack_test.py", "testdata", tmpdir) 861 //cmd.Stdin = strings.NewReader("some input") 862 //cmd.Stdout = &out 863 var cmdout []byte 864 if cmdout, err = cmd.CombinedOutput(); err != nil { 865 logT(t, "-------- Error running msgpack_test.py testdata. Err: %v", err) 866 logT(t, " %v", string(cmdout)) 867 t.FailNow() 868 } 869 870 oldMapType := testMsgpackH.MapType 871 for i, v := range tablePythonVerify { 872 testMsgpackH.MapType = oldMapType 873 //load up the golden file based on number 874 //decode it 875 //compare to in-mem object 876 //encode it again 877 //compare to output stream 878 logT(t, "..............................................") 879 logT(t, " Testing: #%d: %T, %#v\n", i, v, v) 880 var bss []byte 881 bss, err = ioutil.ReadFile(filepath.Join(tmpdir, strconv.Itoa(i)+".golden")) 882 if err != nil { 883 logT(t, "-------- Error reading golden file: %d. Err: %v", i, err) 884 failT(t) 885 continue 886 } 887 testMsgpackH.MapType = mapStrIntfTyp 888 889 var v1 interface{} 890 if err = testUnmarshal(&v1, bss, testMsgpackH); err != nil { 891 logT(t, "-------- Error decoding stream: %d: Err: %v", i, err) 892 failT(t) 893 continue 894 } 895 if v == skipVerifyVal { 896 continue 897 } 898 //no need to indirect, because we pass a nil ptr, so we already have the value 899 //if v1 != nil { v1 = reflect.Indirect(reflect.ValueOf(v1)).Interface() } 900 if err = deepEqual(v, v1); err == nil { 901 logT(t, "++++++++ Objects match") 902 } else { 903 logT(t, "-------- Objects do not match: %v. Source: %T. Decoded: %T", err, v, v1) 904 logT(t, "-------- AGAINST: %#v", v) 905 logT(t, "-------- DECODED: %#v <====> %#v", v1, reflect.Indirect(reflect.ValueOf(v1)).Interface()) 906 failT(t) 907 } 908 bsb, err := testMarshal(v1, testMsgpackH) 909 if err != nil { 910 logT(t, "Error encoding to stream: %d: Err: %v", i, err) 911 failT(t) 912 continue 913 } 914 if err = deepEqual(bsb, bss); err == nil { 915 logT(t, "++++++++ Bytes match") 916 } else { 917 logT(t, "???????? Bytes do not match. %v.", err) 918 xs := "--------" 919 if reflect.ValueOf(v).Kind() == reflect.Map { 920 xs = " " 921 logT(t, "%s It's a map. Ok that they don't match (dependent on ordering).", xs) 922 } else { 923 logT(t, "%s It's not a map. They should match.", xs) 924 failT(t) 925 } 926 logT(t, "%s FROM_FILE: %4d] %v", xs, len(bss), bss) 927 logT(t, "%s ENCODED: %4d] %v", xs, len(bsb), bsb) 928 } 929 } 930 testMsgpackH.MapType = oldMapType 931} 932 933// To test MsgpackSpecRpc, we test 3 scenarios: 934// - Go Client to Go RPC Service (contained within TestMsgpackRpcSpec) 935// - Go client to Python RPC Service (contained within doTestMsgpackRpcSpecGoClientToPythonSvc) 936// - Python Client to Go RPC Service (contained within doTestMsgpackRpcSpecPythonClientToGoSvc) 937// 938// This allows us test the different calling conventions 939// - Go Service requires only one argument 940// - Python Service allows multiple arguments 941 942func doTestMsgpackRpcSpecGoClientToPythonSvc(t *testing.T) { 943 openPort := "6789" 944 cmd := exec.Command("python", "msgpack_test.py", "rpc-server", openPort, "2") 945 checkErrT(t, cmd.Start()) 946 time.Sleep(100 * time.Millisecond) // time for python rpc server to start 947 bs, err2 := net.Dial("tcp", ":"+openPort) 948 checkErrT(t, err2) 949 cc := MsgpackSpecRpc.ClientCodec(bs, testMsgpackH) 950 cl := rpc.NewClientWithCodec(cc) 951 defer cl.Close() 952 var rstr string 953 checkErrT(t, cl.Call("EchoStruct", TestABC{"Aa", "Bb", "Cc"}, &rstr)) 954 //checkEqualT(t, rstr, "{'A': 'Aa', 'B': 'Bb', 'C': 'Cc'}") 955 var mArgs MsgpackSpecRpcMultiArgs = []interface{}{"A1", "B2", "C3"} 956 checkErrT(t, cl.Call("Echo123", mArgs, &rstr)) 957 checkEqualT(t, rstr, "1:A1 2:B2 3:C3", "rstr=") 958} 959 960func doTestMsgpackRpcSpecPythonClientToGoSvc(t *testing.T) { 961 port := doTestRpcOne(t, MsgpackSpecRpc, testMsgpackH, false, 1*time.Second) 962 //time.Sleep(1000 * time.Millisecond) 963 cmd := exec.Command("python", "msgpack_test.py", "rpc-client-go-service", strconv.Itoa(port)) 964 var cmdout []byte 965 var err error 966 if cmdout, err = cmd.CombinedOutput(); err != nil { 967 logT(t, "-------- Error running msgpack_test.py rpc-client-go-service. Err: %v", err) 968 logT(t, " %v", string(cmdout)) 969 t.FailNow() 970 } 971 checkEqualT(t, string(cmdout), 972 fmt.Sprintf("%#v\n%#v\n", []string{"A1", "B2", "C3"}, TestABC{"Aa", "Bb", "Cc"}), "cmdout=") 973} 974 975func TestBincCodecsTable(t *testing.T) { 976 testCodecTableOne(t, testBincH) 977} 978 979func TestBincCodecsMisc(t *testing.T) { 980 testCodecMiscOne(t, testBincH) 981} 982 983func TestBincCodecsEmbeddedPointer(t *testing.T) { 984 testCodecEmbeddedPointer(t, testBincH) 985} 986 987func TestSimpleCodecsTable(t *testing.T) { 988 testCodecTableOne(t, testSimpleH) 989} 990 991func TestSimpleCodecsMisc(t *testing.T) { 992 testCodecMiscOne(t, testSimpleH) 993} 994 995func TestSimpleCodecsEmbeddedPointer(t *testing.T) { 996 testCodecEmbeddedPointer(t, testSimpleH) 997} 998 999func TestMsgpackCodecsTable(t *testing.T) { 1000 testCodecTableOne(t, testMsgpackH) 1001} 1002 1003func TestMsgpackCodecsMisc(t *testing.T) { 1004 testCodecMiscOne(t, testMsgpackH) 1005} 1006 1007func TestMsgpackCodecsEmbeddedPointer(t *testing.T) { 1008 testCodecEmbeddedPointer(t, testMsgpackH) 1009} 1010 1011func TestBincRpcGo(t *testing.T) { 1012 doTestRpcOne(t, GoRpc, testBincH, true, 0) 1013} 1014 1015func _TestSimpleRpcGo(t *testing.T) { 1016 doTestRpcOne(t, GoRpc, testSimpleH, true, 0) 1017} 1018 1019func TestMsgpackRpcGo(t *testing.T) { 1020 doTestRpcOne(t, GoRpc, testMsgpackH, true, 0) 1021} 1022 1023func TestMsgpackRpcSpec(t *testing.T) { 1024 doTestRpcOne(t, MsgpackSpecRpc, testMsgpackH, true, 0) 1025} 1026 1027// TODO: 1028// Add Tests for: 1029// - decoding empty list/map in stream into a nil slice/map 1030// - binary(M|Unm)arsher support for time.Time 1031