dsn_test.go 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. // Go MySQL Driver - A MySQL-Driver for Go's database/sql package
  2. //
  3. // Copyright 2016 The Go-MySQL-Driver Authors. All rights reserved.
  4. //
  5. // This Source Code Form is subject to the terms of the Mozilla Public
  6. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  7. // You can obtain one at http://mozilla.org/MPL/2.0/.
  8. package mysql
  9. import (
  10. "crypto/tls"
  11. "fmt"
  12. "net/url"
  13. "testing"
  14. )
  15. var testDSNs = []struct {
  16. in string
  17. out string
  18. }{
  19. {"username:password@protocol(address)/dbname?param=value", "&{User:username Passwd:password Net:protocol Addr:address DBName:dbname Params:map[param:value] Loc:UTC TLS:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 Collation:33 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:false InterpolateParams:false ParseTime:false Strict:false}"},
  20. {"username:password@protocol(address)/dbname?param=value&columnsWithAlias=true", "&{User:username Passwd:password Net:protocol Addr:address DBName:dbname Params:map[param:value] Loc:UTC TLS:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 Collation:33 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:true InterpolateParams:false ParseTime:false Strict:false}"},
  21. {"user@unix(/path/to/socket)/dbname?charset=utf8", "&{User:user Passwd: Net:unix Addr:/path/to/socket DBName:dbname Params:map[charset:utf8] Loc:UTC TLS:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 Collation:33 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:false InterpolateParams:false ParseTime:false Strict:false}"},
  22. {"user:password@tcp(localhost:5555)/dbname?charset=utf8&tls=true", "&{User:user Passwd:password Net:tcp Addr:localhost:5555 DBName:dbname Params:map[charset:utf8] Loc:UTC TLS:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 Collation:33 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:false InterpolateParams:false ParseTime:false Strict:false}"},
  23. {"user:password@tcp(localhost:5555)/dbname?charset=utf8mb4,utf8&tls=skip-verify", "&{User:user Passwd:password Net:tcp Addr:localhost:5555 DBName:dbname Params:map[charset:utf8mb4,utf8] Loc:UTC TLS:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 Collation:33 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:false InterpolateParams:false ParseTime:false Strict:false}"},
  24. {"user:password@/dbname?loc=UTC&timeout=30s&readTimeout=1s&writeTimeout=1s&allowAllFiles=1&clientFoundRows=true&allowOldPasswords=TRUE&collation=utf8mb4_unicode_ci", "&{User:user Passwd:password Net:tcp Addr:127.0.0.1:3306 DBName:dbname Params:map[] Loc:UTC TLS:<nil> Timeout:30s ReadTimeout:1s WriteTimeout:1s Collation:224 AllowAllFiles:true AllowCleartextPasswords:false AllowOldPasswords:true ClientFoundRows:true ColumnsWithAlias:false InterpolateParams:false ParseTime:false Strict:false}"},
  25. {"user:p@ss(word)@tcp([de:ad:be:ef::ca:fe]:80)/dbname?loc=Local", "&{User:user Passwd:p@ss(word) Net:tcp Addr:[de:ad:be:ef::ca:fe]:80 DBName:dbname Params:map[] Loc:Local TLS:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 Collation:33 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:false InterpolateParams:false ParseTime:false Strict:false}"},
  26. {"/dbname", "&{User: Passwd: Net:tcp Addr:127.0.0.1:3306 DBName:dbname Params:map[] Loc:UTC TLS:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 Collation:33 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:false InterpolateParams:false ParseTime:false Strict:false}"},
  27. {"@/", "&{User: Passwd: Net:tcp Addr:127.0.0.1:3306 DBName: Params:map[] Loc:UTC TLS:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 Collation:33 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:false InterpolateParams:false ParseTime:false Strict:false}"},
  28. {"/", "&{User: Passwd: Net:tcp Addr:127.0.0.1:3306 DBName: Params:map[] Loc:UTC TLS:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 Collation:33 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:false InterpolateParams:false ParseTime:false Strict:false}"},
  29. {"", "&{User: Passwd: Net:tcp Addr:127.0.0.1:3306 DBName: Params:map[] Loc:UTC TLS:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 Collation:33 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:false InterpolateParams:false ParseTime:false Strict:false}"},
  30. {"user:p@/ssword@/", "&{User:user Passwd:p@/ssword Net:tcp Addr:127.0.0.1:3306 DBName: Params:map[] Loc:UTC TLS:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 Collation:33 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:false InterpolateParams:false ParseTime:false Strict:false}"},
  31. {"unix/?arg=%2Fsome%2Fpath.ext", "&{User: Passwd: Net:unix Addr:/tmp/mysql.sock DBName: Params:map[arg:/some/path.ext] Loc:UTC TLS:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 Collation:33 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:false InterpolateParams:false ParseTime:false Strict:false}"},
  32. }
  33. func TestDSNParser(t *testing.T) {
  34. var cfg *Config
  35. var err error
  36. var res string
  37. for i, tst := range testDSNs {
  38. cfg, err = ParseDSN(tst.in)
  39. if err != nil {
  40. t.Error(err.Error())
  41. }
  42. // pointer not static
  43. cfg.TLS = nil
  44. res = fmt.Sprintf("%+v", cfg)
  45. if res != tst.out {
  46. t.Errorf("%d. ParseDSN(%q) => %q, want %q", i, tst.in, res, tst.out)
  47. }
  48. }
  49. }
  50. func TestDSNParserInvalid(t *testing.T) {
  51. var invalidDSNs = []string{
  52. "@net(addr/", // no closing brace
  53. "@tcp(/", // no closing brace
  54. "tcp(/", // no closing brace
  55. "(/", // no closing brace
  56. "net(addr)//", // unescaped
  57. "User:pass@tcp(1.2.3.4:3306)", // no trailing slash
  58. //"/dbname?arg=/some/unescaped/path",
  59. }
  60. for i, tst := range invalidDSNs {
  61. if _, err := ParseDSN(tst); err == nil {
  62. t.Errorf("invalid DSN #%d. (%s) didn't error!", i, tst)
  63. }
  64. }
  65. }
  66. func TestDSNWithCustomTLS(t *testing.T) {
  67. baseDSN := "User:password@tcp(localhost:5555)/dbname?tls="
  68. tlsCfg := tls.Config{}
  69. RegisterTLSConfig("utils_test", &tlsCfg)
  70. // Custom TLS is missing
  71. tst := baseDSN + "invalid_tls"
  72. cfg, err := ParseDSN(tst)
  73. if err == nil {
  74. t.Errorf("invalid custom TLS in DSN (%s) but did not error. Got config: %#v", tst, cfg)
  75. }
  76. tst = baseDSN + "utils_test"
  77. // Custom TLS with a server name
  78. name := "foohost"
  79. tlsCfg.ServerName = name
  80. cfg, err = ParseDSN(tst)
  81. if err != nil {
  82. t.Error(err.Error())
  83. } else if cfg.TLS.ServerName != name {
  84. t.Errorf("did not get the correct TLS ServerName (%s) parsing DSN (%s).", name, tst)
  85. }
  86. // Custom TLS without a server name
  87. name = "localhost"
  88. tlsCfg.ServerName = ""
  89. cfg, err = ParseDSN(tst)
  90. if err != nil {
  91. t.Error(err.Error())
  92. } else if cfg.TLS.ServerName != name {
  93. t.Errorf("did not get the correct ServerName (%s) parsing DSN (%s).", name, tst)
  94. }
  95. DeregisterTLSConfig("utils_test")
  96. }
  97. func TestDSNWithCustomTLS_queryEscape(t *testing.T) {
  98. const configKey = "&%!:"
  99. dsn := "User:password@tcp(localhost:5555)/dbname?tls=" + url.QueryEscape(configKey)
  100. name := "foohost"
  101. tlsCfg := tls.Config{ServerName: name}
  102. RegisterTLSConfig(configKey, &tlsCfg)
  103. cfg, err := ParseDSN(dsn)
  104. if err != nil {
  105. t.Error(err.Error())
  106. } else if cfg.TLS.ServerName != name {
  107. t.Errorf("did not get the correct TLS ServerName (%s) parsing DSN (%s).", name, dsn)
  108. }
  109. }
  110. func TestDSNUnsafeCollation(t *testing.T) {
  111. _, err := ParseDSN("/dbname?collation=gbk_chinese_ci&interpolateParams=true")
  112. if err != errInvalidDSNUnsafeCollation {
  113. t.Errorf("expected %v, got %v", errInvalidDSNUnsafeCollation, err)
  114. }
  115. _, err = ParseDSN("/dbname?collation=gbk_chinese_ci&interpolateParams=false")
  116. if err != nil {
  117. t.Errorf("expected %v, got %v", nil, err)
  118. }
  119. _, err = ParseDSN("/dbname?collation=gbk_chinese_ci")
  120. if err != nil {
  121. t.Errorf("expected %v, got %v", nil, err)
  122. }
  123. _, err = ParseDSN("/dbname?collation=ascii_bin&interpolateParams=true")
  124. if err != nil {
  125. t.Errorf("expected %v, got %v", nil, err)
  126. }
  127. _, err = ParseDSN("/dbname?collation=latin1_german1_ci&interpolateParams=true")
  128. if err != nil {
  129. t.Errorf("expected %v, got %v", nil, err)
  130. }
  131. _, err = ParseDSN("/dbname?collation=utf8_general_ci&interpolateParams=true")
  132. if err != nil {
  133. t.Errorf("expected %v, got %v", nil, err)
  134. }
  135. _, err = ParseDSN("/dbname?collation=utf8mb4_general_ci&interpolateParams=true")
  136. if err != nil {
  137. t.Errorf("expected %v, got %v", nil, err)
  138. }
  139. }
  140. func BenchmarkParseDSN(b *testing.B) {
  141. b.ReportAllocs()
  142. for i := 0; i < b.N; i++ {
  143. for _, tst := range testDSNs {
  144. if _, err := ParseDSN(tst.in); err != nil {
  145. b.Error(err.Error())
  146. }
  147. }
  148. }
  149. }