/*
* This file is part of DNPMHelper
*
* Copyright (C) 2023-2026 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
package dev.dnpm.oshelper.migration;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.jdbc.core.JdbcTemplate;
@ExtendWith(MockitoExtension.class)
class DatabaseMigrationServiceTest {
JdbcTemplate jdbcTemplate;
ResourcePatternResolver resourcePatternResolver;
DatabaseMigrationService databaseMigration;
@BeforeEach
void setUp(
@Mock JdbcTemplate jdbcTemplate, @Mock ResourcePatternResolver resourcePatternResolver) {
this.jdbcTemplate = jdbcTemplate;
this.resourcePatternResolver = resourcePatternResolver;
databaseMigration = new DatabaseMigrationService(jdbcTemplate, resourcePatternResolver);
}
@Test
void shouldGetNewMigrationFiles() throws Exception {
try (MockedStatic databaseUtils = Mockito.mockStatic(MigrationUtils.class)) {
databaseUtils
.when(
() -> MigrationUtils.getDatabaseMigrationScripts(any(ResourcePatternResolver.class)))
.thenReturn(List.of("updatednpm_001.sql", "updatednpm_002.sql", "updatednpm_003.sql"));
databaseUtils
.when(() -> MigrationUtils.getExecutedDatabaseMigrations(any(JdbcTemplate.class)))
.thenReturn(List.of("updatednpm_001.sql", "updatednpm_002.sql"));
var actual = databaseMigration.getNewMigrationIds();
assertThat(actual).containsExactly("updatednpm_003.sql");
}
}
@Test
void shouldIgnoreOldMigrationFiles() throws Exception {
try (MockedStatic databaseUtils = Mockito.mockStatic(MigrationUtils.class)) {
databaseUtils
.when(
() -> MigrationUtils.getDatabaseMigrationScripts(any(ResourcePatternResolver.class)))
.thenReturn(List.of("updatednpm_001.sql", "updatednpm_002.sql"));
databaseUtils
.when(() -> MigrationUtils.getExecutedDatabaseMigrations(any(JdbcTemplate.class)))
.thenReturn(List.of("updatednpm_001.sql", "updatednpm_002.sql"));
var actual = databaseMigration.getNewMigrationIds();
assertThat(actual).isEmpty();
}
}
@Test
void shouldExecuteMigrationFile() throws Exception {
try (MockedStatic databaseUtils = Mockito.mockStatic(MigrationUtils.class)) {
databaseUtils
.when(
() -> MigrationUtils.getDatabaseMigrationScripts(any(ResourcePatternResolver.class)))
.thenReturn(List.of("updatednpm_001.sql", "updatednpm_002.sql"));
databaseUtils
.when(() -> MigrationUtils.getExecutedDatabaseMigrations(any(JdbcTemplate.class)))
.thenReturn(List.of("updatednpm_001.sql"));
databaseUtils
.when(() -> MigrationUtils.getSqlQuery(any(ResourcePatternResolver.class), anyString()))
.thenReturn("UPDATE TABLE test;");
databaseMigration.migrate();
var argumentCaptor = ArgumentCaptor.forClass(String.class);
verify(jdbcTemplate, times(1)).execute(argumentCaptor.capture());
assertThat(argumentCaptor.getValue()).isEqualTo("UPDATE TABLE test;");
}
}
@ParameterizedTest
@ValueSource(booleans = {false, true})
void shouldIgnoreMigrationFileDueToMissingFormRev(boolean formRevisionAvailable) {
try (MockedStatic databaseUtils = Mockito.mockStatic(MigrationUtils.class)) {
databaseUtils
.when(
() -> MigrationUtils.getDatabaseMigrationScripts(any(ResourcePatternResolver.class)))
.thenReturn(List.of("updatednpm_001.sql", "updatednpm_002.sql"));
databaseUtils
.when(() -> MigrationUtils.getExecutedDatabaseMigrations(any(JdbcTemplate.class)))
.thenReturn(List.of("updatednpm_001.sql"));
databaseUtils
.when(
() ->
MigrationUtils.requiredFormRevisionAvailable(
any(JdbcTemplate.class), anyString(), anyString(), anyString()))
.thenReturn(formRevisionAvailable);
databaseUtils
.when(() -> MigrationUtils.getSqlQuery(any(ResourcePatternResolver.class), anyString()))
.thenReturn("-- form: DNPM Test\n-- min-rev: 1\n-- max-rev: 2\nUPDATE TABLE test;");
databaseMigration.migrate();
if (formRevisionAvailable) {
verify(jdbcTemplate, times(1)).execute(anyString());
} else {
verify(jdbcTemplate, times(0)).execute(anyString());
}
}
}
@Test
void shouldNotCheckRequiredRevsionRange() {
try (MockedStatic databaseUtils = Mockito.mockStatic(MigrationUtils.class)) {
databaseUtils
.when(
() -> MigrationUtils.getDatabaseMigrationScripts(any(ResourcePatternResolver.class)))
.thenReturn(List.of("updatednpm_001.sql", "updatednpm_002.sql"));
databaseUtils
.when(() -> MigrationUtils.getExecutedDatabaseMigrations(any(JdbcTemplate.class)))
.thenReturn(List.of("updatednpm_001.sql"));
databaseUtils
.when(
() ->
MigrationUtils.requiredFormRevisionAvailable(
any(JdbcTemplate.class), anyString(), anyString(), anyString()))
.thenReturn(false);
databaseUtils
.when(() -> MigrationUtils.getSqlQuery(any(ResourcePatternResolver.class), anyString()))
.thenReturn("UPDATE TABLE test;");
databaseMigration.migrate();
databaseUtils.verify(
() -> {
MigrationUtils.requiredFormRevisionAvailable(
any(JdbcTemplate.class), anyString(), anyString(), anyString());
},
never());
}
}
@Test
void shouldUseDefaultRequiredRevsionRange() {
try (MockedStatic databaseUtils = Mockito.mockStatic(MigrationUtils.class)) {
databaseUtils
.when(
() -> MigrationUtils.getDatabaseMigrationScripts(any(ResourcePatternResolver.class)))
.thenReturn(List.of("updatednpm_001.sql", "updatednpm_002.sql"));
databaseUtils
.when(() -> MigrationUtils.getExecutedDatabaseMigrations(any(JdbcTemplate.class)))
.thenReturn(List.of("updatednpm_001.sql"));
databaseUtils
.when(
() ->
MigrationUtils.requiredFormRevisionAvailable(
any(JdbcTemplate.class), anyString(), anyString(), anyString()))
.thenReturn(false);
databaseUtils
.when(() -> MigrationUtils.getSqlQuery(any(ResourcePatternResolver.class), anyString()))
.thenReturn("-- form: DNPM Test\nUPDATE TABLE test;");
databaseMigration.migrate();
var formNameCaptor = ArgumentCaptor.forClass(String.class);
var minRevCaptor = ArgumentCaptor.forClass(String.class);
var maxRevCaptor = ArgumentCaptor.forClass(String.class);
databaseUtils.verify(
() -> {
MigrationUtils.requiredFormRevisionAvailable(
any(JdbcTemplate.class),
formNameCaptor.capture(),
minRevCaptor.capture(),
maxRevCaptor.capture());
},
times(1));
assertThat(formNameCaptor.getValue()).isEqualTo("DNPM Test");
assertThat(minRevCaptor.getValue()).isEqualTo("0");
assertThat(maxRevCaptor.getValue()).isEqualTo("99999999999999");
}
}
}