3 * Copyright (C) 2009-2022 SonarSource SA
4 * mailto:info AT sonarsource DOT com
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 3 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 package org.sonar.server.platform.db.migration.charset;
22 import java.sql.Connection;
23 import java.sql.SQLException;
24 import java.util.Arrays;
25 import java.util.List;
26 import org.junit.Test;
27 import org.sonar.api.utils.MessageException;
29 import static java.util.Arrays.asList;
30 import static org.assertj.core.api.Assertions.assertThatThrownBy;
31 import static org.mockito.ArgumentMatchers.any;
32 import static org.mockito.ArgumentMatchers.anyString;
33 import static org.mockito.ArgumentMatchers.same;
34 import static org.mockito.Mockito.mock;
35 import static org.mockito.Mockito.verify;
36 import static org.mockito.Mockito.verifyZeroInteractions;
37 import static org.mockito.Mockito.when;
39 public class PostgresCharsetHandlerTest {
41 private static final String TABLE_ISSUES = "issues";
42 private static final String TABLE_PROJECTS = "projects";
43 private static final String COLUMN_KEE = "kee";
44 private static final String COLUMN_NAME = "name";
47 private SqlExecutor sqlExecutor = mock(SqlExecutor.class);
48 private Connection connection = mock(Connection.class);
49 private PostgresMetadataReader metadata = mock(PostgresMetadataReader.class);
50 private PostgresCharsetHandler underTest = new PostgresCharsetHandler(sqlExecutor, metadata);
53 public void fresh_install_verifies_that_default_charset_is_utf8() throws SQLException {
54 answerDefaultCharset("utf8");
56 underTest.handle(connection, DatabaseCharsetChecker.State.FRESH_INSTALL);
57 // no errors, charset has been verified
58 verify(metadata).getDefaultCharset(same(connection));
59 verifyZeroInteractions(sqlExecutor);
63 public void upgrade_verifies_that_default_charset_and_columns_are_utf8() throws Exception {
64 answerDefaultCharset("utf8");
66 new String[] {TABLE_ISSUES, COLUMN_KEE, "utf8"},
67 new String[] {TABLE_PROJECTS, COLUMN_NAME, "utf8"}));
69 underTest.handle(connection, DatabaseCharsetChecker.State.UPGRADE);
70 // no errors, charsets have been verified
71 verify(metadata).getDefaultCharset(same(connection));
75 public void regular_startup_verifies_that_default_charset_and_columns_are_utf8() throws Exception {
76 answerDefaultCharset("utf8");
78 new String[] {TABLE_ISSUES, COLUMN_KEE, "utf8"},
79 new String[] {TABLE_PROJECTS, COLUMN_NAME, "utf8"}));
81 underTest.handle(connection, DatabaseCharsetChecker.State.STARTUP);
82 // no errors, charsets have been verified
83 verify(metadata).getDefaultCharset(same(connection));
87 public void column_charset_can_be_empty() throws Exception {
88 answerDefaultCharset("utf8");
90 new String[] {TABLE_ISSUES, COLUMN_KEE, "utf8"},
91 new String[] {TABLE_PROJECTS, COLUMN_NAME, "" /* unset -> uses db collation */}));
94 underTest.handle(connection, DatabaseCharsetChecker.State.UPGRADE);
98 public void upgrade_fails_if_non_utf8_column() throws Exception {
99 // default charset is ok but two columns are not
100 answerDefaultCharset("utf8");
101 answerColumns(asList(
102 new String[] {TABLE_ISSUES, COLUMN_KEE, "utf8"},
103 new String[] {TABLE_PROJECTS, COLUMN_KEE, "latin"},
104 new String[] {TABLE_PROJECTS, COLUMN_NAME, "latin"}));
106 assertThatThrownBy(() -> underTest.handle(connection, DatabaseCharsetChecker.State.UPGRADE))
107 .isInstanceOf(MessageException.class)
108 .hasMessage("Database columns [projects.kee, projects.name] must have UTF8 charset.");
112 public void upgrade_fails_if_default_charset_is_not_utf8() throws Exception {
113 answerDefaultCharset("latin");
115 Arrays.<String[]>asList(new String[] {TABLE_ISSUES, COLUMN_KEE, "utf8"}));
117 assertThatThrownBy(() -> underTest.handle(connection, DatabaseCharsetChecker.State.UPGRADE))
118 .isInstanceOf(MessageException.class)
119 .hasMessage("Database charset is latin. It must support UTF8.");
122 private void answerDefaultCharset(String defaultCollation) throws SQLException {
123 when(metadata.getDefaultCharset(same(connection))).thenReturn(defaultCollation);
126 private void answerColumns(List<String[]> firstRequest) throws SQLException {
127 when(sqlExecutor.select(same(connection), anyString(), any(SqlExecutor.StringsConverter.class))).thenReturn(firstRequest);