3 * Copyright (C) 2009-2024 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.v2.api.system.controller;
22 import java.util.Date;
23 import java.util.Optional;
24 import org.junit.jupiter.api.BeforeEach;
25 import org.junit.jupiter.api.Test;
26 import org.mockito.Mockito;
27 import org.sonar.db.Database;
28 import org.sonar.db.dialect.Dialect;
29 import org.sonar.server.platform.db.migration.DatabaseMigrationState;
30 import org.sonar.server.platform.db.migration.version.DatabaseVersion;
31 import org.sonar.server.v2.api.ControllerTester;
32 import org.springframework.test.web.servlet.MockMvc;
34 import static org.mockito.Mockito.mock;
35 import static org.mockito.Mockito.when;
36 import static org.sonar.server.platform.db.migration.DatabaseMigrationState.Status.FAILED;
37 import static org.sonar.server.platform.db.migration.DatabaseMigrationState.Status.NONE;
38 import static org.sonar.server.platform.db.migration.DatabaseMigrationState.Status.RUNNING;
39 import static org.sonar.server.v2.WebApiEndpoints.DATABASE_MIGRATIONS_ENDPOINT;
40 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
41 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
42 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
44 class DatabaseMigrationsControllerTest {
46 private static final Date SOME_DATE = new Date();
47 private final DatabaseVersion databaseVersion = mock();
48 private final DatabaseMigrationState migrationState = mock();
49 private final Dialect dialect = mock(Dialect.class);
50 private final Database database = mock();
51 private final MockMvc mockMvc = ControllerTester.getMockMvc(new DatabaseMigrationsController(databaseVersion, migrationState, database));
54 public void before() {
55 when(database.getDialect()).thenReturn(dialect);
56 when(databaseVersion.getVersion()).thenReturn(Optional.of(1L));
60 void getStatus_whenDatabaseHasNoVersion_return500() throws Exception {
61 Mockito.reset(databaseVersion);
62 when(databaseVersion.getVersion()).thenReturn(Optional.empty());
64 mockMvc.perform(get(DATABASE_MIGRATIONS_ENDPOINT)).andExpectAll(status().is5xxServerError(),
65 content().json("{\"message\":\"Cannot connect to Database.\"}"));
69 void getStatus_migrationNotNeeded_returnUpToDateStatus() throws Exception {
70 when(databaseVersion.getStatus()).thenReturn(DatabaseVersion.Status.UP_TO_DATE);
71 when(migrationState.getStatus()).thenReturn(NONE);
73 mockMvc.perform(get(DATABASE_MIGRATIONS_ENDPOINT)).andExpectAll(status().isOk(),
74 content().json("{\"status\":\"NO_MIGRATION\",\"message\":\"Database is up-to-date, no migration needed.\"}"));
78 void getStatus_whenDowngradeRequired_returnNone() throws Exception {
79 when(databaseVersion.getStatus()).thenReturn(DatabaseVersion.Status.REQUIRES_DOWNGRADE);
80 when(migrationState.getStatus()).thenReturn(NONE);
82 mockMvc.perform(get(DATABASE_MIGRATIONS_ENDPOINT)).andExpectAll(status().isOk(),
83 content().json("{\"status\":\"NO_MIGRATION\",\"message\":\"Database is up-to-date, no migration needed.\"}"));
87 void getStatus_whenDbRequiresUpgradeButDialectIsNotSupported_returnNotSupported() throws Exception {
88 when(databaseVersion.getStatus()).thenReturn(DatabaseVersion.Status.FRESH_INSTALL);
89 when(dialect.supportsMigration()).thenReturn(false);
91 mockMvc.perform(get(DATABASE_MIGRATIONS_ENDPOINT)).andExpectAll(status().isOk(),
92 content().json("{\"status\":\"NOT_SUPPORTED\",\"message\":\"Upgrade is not supported on embedded database.\"}"));
96 void getStatus_whenDbMigrationsRunning_returnRunning() throws Exception {
97 when(databaseVersion.getStatus()).thenReturn(DatabaseVersion.Status.REQUIRES_UPGRADE);
98 when(dialect.supportsMigration()).thenReturn(true);
99 when(migrationState.getStatus()).thenReturn(RUNNING);
100 when(migrationState.getStartedAt()).thenReturn(SOME_DATE);
102 mockMvc.perform(get(DATABASE_MIGRATIONS_ENDPOINT)).andExpectAll(status().isOk(),
103 content().json("{\"status\":\"MIGRATION_RUNNING\",\"message\":\"Database migration is running.\"}"));
107 void getStatus_whenDbMigrationsFailed_returnFailed() throws Exception {
108 when(databaseVersion.getStatus()).thenReturn(DatabaseVersion.Status.REQUIRES_UPGRADE);
109 when(dialect.supportsMigration()).thenReturn(true);
110 when(migrationState.getStatus()).thenReturn(DatabaseMigrationState.Status.FAILED);
111 when(migrationState.getStartedAt()).thenReturn(SOME_DATE);
113 mockMvc.perform(get(DATABASE_MIGRATIONS_ENDPOINT)).andExpectAll(status().isOk(),
114 content().json("{\"status\":\"MIGRATION_FAILED\",\"message\":\"Migration failed: %s.<br/> Please check logs.\"}"));
118 void getStatus_whenDbMigrationsSucceeded_returnSucceeded() throws Exception {
119 when(databaseVersion.getStatus()).thenReturn(DatabaseVersion.Status.REQUIRES_UPGRADE);
120 when(dialect.supportsMigration()).thenReturn(true);
121 when(migrationState.getStatus()).thenReturn(DatabaseMigrationState.Status.SUCCEEDED);
122 when(migrationState.getStartedAt()).thenReturn(SOME_DATE);
124 mockMvc.perform(get(DATABASE_MIGRATIONS_ENDPOINT)).andExpectAll(status().isOk(),
125 content().json("{\"status\":\"MIGRATION_SUCCEEDED\",\"message\":\"Migration succeeded.\"}"));
130 void getStatus_whenMigrationRequired_returnMigrationRequired() throws Exception {
131 when(databaseVersion.getStatus()).thenReturn(DatabaseVersion.Status.REQUIRES_UPGRADE);
132 when(dialect.supportsMigration()).thenReturn(true);
133 when(migrationState.getStatus()).thenReturn(NONE);
134 when(migrationState.getStartedAt()).thenReturn(SOME_DATE);
136 mockMvc.perform(get(DATABASE_MIGRATIONS_ENDPOINT)).andExpectAll(status().isOk(),
137 content().json("{\"status\":\"MIGRATION_REQUIRED\",\"message\":\"Database migration is required. DB migration " +
138 "can be started using WS /api/system/migrate_db.\"}"));
142 void getStatus_whenMigrationFailedWithError_IncludeErrorInResponse() throws Exception {
143 when(databaseVersion.getStatus()).thenReturn(DatabaseVersion.Status.FRESH_INSTALL);
144 when(dialect.supportsMigration()).thenReturn(true);
145 when(migrationState.getStatus()).thenReturn(FAILED);
146 when(migrationState.getStartedAt()).thenReturn(SOME_DATE);
147 when(migrationState.getError()).thenReturn(new UnsupportedOperationException("error message"));
149 mockMvc.perform(get(DATABASE_MIGRATIONS_ENDPOINT)).andExpectAll(status().isOk(),
150 content().json("{\"status\":\"MIGRATION_FAILED\",\"message\":\"error message\"}"));