package mysqlserver import ( "bytes" "testing" "mysql-tunnel/internal/navicat" ) func TestLenencInt(t *testing.T) { cases := []uint64{0, 1, 250, 251, 0xffff, 0x10000, 1 << 32} for _, n := range cases { enc := appendLenencInt(nil, n) got, _, err := readLenencInt(enc, 0) if err != nil || got != n { t.Fatalf("n=%d got=%d err=%v", n, got, err) } } } func TestOKERRPackets(t *testing.T) { ok := encodeOK(3, 9, serverStatusAutocommit, 0) if ok[0] != markerOK { t.Fatal("ok header") } n, off, err := readLenencInt(ok, 1) if err != nil || n != 3 { t.Fatal(n, err) } id, _, err := readLenencInt(ok, off) if err != nil || id != 9 { t.Fatal(id, err) } er := encodeERR(1064, "syntax") if er[0] != markerERR || er[1] != 0x28 || er[2] != 0x04 { t.Fatalf("%x", er) } if !bytes.Contains(er, []byte("syntax")) { t.Fatal(string(er)) } } func TestNativePasswordRoundtrip(t *testing.T) { scramble := bytes.Repeat([]byte{3}, 20) tok := nativePasswordToken("123456", scramble) if !verifyNativePassword("123456", scramble, tok) { t.Fatal("should match") } if verifyNativePassword("wrong", scramble, tok) { t.Fatal("should fail") } if !verifyNativePassword("", scramble, nil) { t.Fatal("empty") } } func TestHandshakeBuildParseResponse(t *testing.T) { scramble := bytes.Repeat([]byte{7}, 20) hs := buildHandshake(42, scramble) if hs[0] != ProtocolVersion { t.Fatal("proto") } if !bytes.Contains(hs, []byte(ServerVersion)) { t.Fatal("version") } if !bytes.Contains(hs, []byte(AuthPluginNative)) { t.Fatal("plugin") } token := nativePasswordToken("p", scramble) resp := buildClientAuth("root", token, "app", clientProtocol41|clientSecureConnection|clientPluginAuth|clientConnectWithDB|clientPluginAuthLenencClientData) hr, err := parseHandshakeResponse(resp) if err != nil { t.Fatal(err) } if hr.Username != "root" || hr.Database != "app" || !bytes.Equal(hr.Auth, token) { t.Fatalf("%+v", hr) } } func TestTextRowNULLAndBigint(t *testing.T) { row := encodeTextRow([]navicat.Cell{ {Null: true}, {Bytes: []byte("18446744073709551615")}, {Bytes: []byte("1.50")}, {Bytes: []byte("你好")}, }) if row[0] != markerNull { t.Fatal("null marker") } off := 1 b, off, err := readLenencString(row, off) if err != nil || string(b) != "18446744073709551615" { t.Fatal(string(b), err) } b, off, err = readLenencString(row, off) if string(b) != "1.50" { t.Fatal(string(b)) } b, _, err = readLenencString(row, off) if string(b) != "你好" { t.Fatal(string(b)) } } func buildClientAuth(user string, token []byte, db string, caps uint32) []byte { b := appendU32(nil, caps) b = appendU32(b, MaxPacketSize) b = append(b, charsetUTF8MB4) b = append(b, make([]byte, 23)...) b = appendNUL(b, user) b = appendLenencInt(b, uint64(len(token))) b = append(b, token...) if caps&clientConnectWithDB != 0 { b = appendNUL(b, db) } if caps&clientPluginAuth != 0 { b = appendNUL(b, AuthPluginNative) } return b }