gitea源码

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. // Copyright 2023 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package integration
  4. import (
  5. "testing"
  6. "code.gitea.io/gitea/models/db"
  7. "code.gitea.io/gitea/models/unittest"
  8. "code.gitea.io/gitea/modules/setting"
  9. "code.gitea.io/gitea/modules/test"
  10. "github.com/stretchr/testify/assert"
  11. )
  12. type TestCollationTbl struct {
  13. ID int64
  14. Txt string `xorm:"VARCHAR(10) UNIQUE"`
  15. }
  16. func TestDatabaseCollation(t *testing.T) {
  17. x := unittest.GetXORMEngine()
  18. // all created tables should use case-sensitive collation by default
  19. _, _ = x.Exec("DROP TABLE IF EXISTS test_collation_tbl")
  20. err := x.Sync(&TestCollationTbl{})
  21. assert.NoError(t, err)
  22. _, _ = x.Exec("INSERT INTO test_collation_tbl (txt) VALUES ('main')")
  23. _, _ = x.Exec("INSERT INTO test_collation_tbl (txt) VALUES ('Main')") // case-sensitive, so it inserts a new row
  24. _, _ = x.Exec("INSERT INTO test_collation_tbl (txt) VALUES ('main')") // duplicate, so it doesn't insert
  25. cnt, err := x.Count(&TestCollationTbl{})
  26. assert.NoError(t, err)
  27. assert.EqualValues(t, 2, cnt)
  28. _, _ = x.Exec("DROP TABLE IF EXISTS test_collation_tbl")
  29. // by default, SQLite3 and PostgreSQL are using case-sensitive collations, but MySQL and MSSQL are not
  30. // the following tests are only for MySQL and MSSQL
  31. if !setting.Database.Type.IsMySQL() && !setting.Database.Type.IsMSSQL() {
  32. t.Skip("only MySQL and MSSQL requires the case-sensitive collation check at the moment")
  33. return
  34. }
  35. t.Run("Default startup makes database collation case-sensitive", func(t *testing.T) {
  36. r, err := db.CheckCollations(x)
  37. assert.NoError(t, err)
  38. assert.True(t, r.IsCollationCaseSensitive(r.DatabaseCollation))
  39. assert.True(t, r.CollationEquals(r.ExpectedCollation, r.DatabaseCollation))
  40. assert.NotEmpty(t, r.AvailableCollation)
  41. assert.Empty(t, r.InconsistentCollationColumns)
  42. // and by the way test the helper functions
  43. if setting.Database.Type.IsMySQL() {
  44. assert.True(t, r.IsCollationCaseSensitive("utf8mb4_bin"))
  45. assert.True(t, r.IsCollationCaseSensitive("utf8mb4_xxx_as_cs"))
  46. assert.False(t, r.IsCollationCaseSensitive("utf8mb4_general_ci"))
  47. assert.True(t, r.CollationEquals("abc", "abc"))
  48. assert.True(t, r.CollationEquals("abc", "utf8mb4_abc"))
  49. assert.False(t, r.CollationEquals("utf8mb4_general_ci", "utf8mb4_unicode_ci"))
  50. } else if setting.Database.Type.IsMSSQL() {
  51. assert.True(t, r.IsCollationCaseSensitive("Latin1_General_CS_AS"))
  52. assert.False(t, r.IsCollationCaseSensitive("Latin1_General_CI_AS"))
  53. assert.True(t, r.CollationEquals("abc", "abc"))
  54. assert.False(t, r.CollationEquals("Latin1_General_CS_AS", "SQL_Latin1_General_CP1_CS_AS"))
  55. } else {
  56. assert.Fail(t, "unexpected database type")
  57. }
  58. })
  59. if setting.Database.Type.IsMSSQL() {
  60. return // skip table converting tests because MSSQL doesn't have a simple solution at the moment
  61. }
  62. t.Run("Convert tables to utf8mb4_bin", func(t *testing.T) {
  63. defer test.MockVariableValue(&setting.Database.CharsetCollation, "utf8mb4_bin")()
  64. r, err := db.CheckCollations(x)
  65. assert.NoError(t, err)
  66. assert.Equal(t, "utf8mb4_bin", r.ExpectedCollation)
  67. assert.NoError(t, db.ConvertDatabaseTable())
  68. r, err = db.CheckCollations(x)
  69. assert.NoError(t, err)
  70. assert.Equal(t, "utf8mb4_bin", r.DatabaseCollation)
  71. assert.True(t, r.CollationEquals(r.ExpectedCollation, r.DatabaseCollation))
  72. assert.Empty(t, r.InconsistentCollationColumns)
  73. _, _ = x.Exec("DROP TABLE IF EXISTS test_tbl")
  74. _, err = x.Exec("CREATE TABLE test_tbl (txt varchar(10) COLLATE utf8mb4_unicode_ci NOT NULL)")
  75. assert.NoError(t, err)
  76. r, err = db.CheckCollations(x)
  77. assert.NoError(t, err)
  78. assert.Contains(t, r.InconsistentCollationColumns, "test_tbl.txt")
  79. })
  80. t.Run("Convert tables to utf8mb4_general_ci", func(t *testing.T) {
  81. defer test.MockVariableValue(&setting.Database.CharsetCollation, "utf8mb4_general_ci")()
  82. assert.NoError(t, db.ConvertDatabaseTable())
  83. r, err := db.CheckCollations(x)
  84. assert.NoError(t, err)
  85. assert.Equal(t, "utf8mb4_general_ci", r.DatabaseCollation)
  86. assert.True(t, r.CollationEquals(r.ExpectedCollation, r.DatabaseCollation))
  87. assert.Empty(t, r.InconsistentCollationColumns)
  88. _, _ = x.Exec("DROP TABLE IF EXISTS test_tbl")
  89. _, err = x.Exec("CREATE TABLE test_tbl (txt varchar(10) COLLATE utf8mb4_bin NOT NULL)")
  90. assert.NoError(t, err)
  91. r, err = db.CheckCollations(x)
  92. assert.NoError(t, err)
  93. assert.Contains(t, r.InconsistentCollationColumns, "test_tbl.txt")
  94. })
  95. t.Run("Convert tables to default case-sensitive collation", func(t *testing.T) {
  96. defer test.MockVariableValue(&setting.Database.CharsetCollation, "")()
  97. assert.NoError(t, db.ConvertDatabaseTable())
  98. r, err := db.CheckCollations(x)
  99. assert.NoError(t, err)
  100. assert.True(t, r.IsCollationCaseSensitive(r.DatabaseCollation))
  101. assert.True(t, r.CollationEquals(r.ExpectedCollation, r.DatabaseCollation))
  102. assert.Empty(t, r.InconsistentCollationColumns)
  103. })
  104. }