import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
// skip migration if:
// - application only exists in xml and not in the db. It will be removed from the xml at later stage of the migration.
// - application contains no projects- it's already in a valid db state
- List<String> projects = app.getProjects();
- if (applicationUuid == null || projects.isEmpty()) {
+ Set<String> uniqueProjects = new HashSet<>(app.getProjects());
+ if (applicationUuid == null || uniqueProjects.isEmpty()) {
return;
}
List<String> alreadyAddedProjects = context.prepareSelect(SELECT_PROJECTS_BY_APP).setString(1, applicationUuid)
.list(r -> r.getString(1));
- String queryParam = projects.stream().map(uuid -> "'" + uuid + "'").collect(Collectors.joining(","));
+ String queryParam = uniqueProjects.stream().map(uuid -> "'" + uuid + "'").collect(Collectors.joining(","));
Map<String, String> projectUuidsByKeys = context.prepareSelect(format(SELECT_PROJECTS_BY_KEYS, queryParam))
.list(r -> new AbstractMap.SimpleEntry<>(r.getString(1), r.getString(2)))
.stream()
.collect(Collectors.toMap(AbstractMap.SimpleEntry::getKey, AbstractMap.SimpleEntry::getValue));
if (!projectUuidsByKeys.isEmpty()) {
- insertApplicationProjects(context, app, applicationUuid, projectUuidsByKeys, now);
+ insertApplicationProjects(context, app, applicationUuid, projectUuidsByKeys, uniqueProjects, now);
}
if (!app.getApplicationBranches().isEmpty()) {
insertApplicationBranchesProjects(context, app, applicationUuid, projectUuidsByKeys, now);
}
private void insertApplicationProjects(Context context, ViewXml.ViewDef app, String applicationUuid,
- Map<String, String> projectUuidsByKeys, long createdTime) throws SQLException {
+ Map<String, String> projectUuidsByKeys, Set<String> uniqueProjects, long createdTime) throws SQLException {
Upsert insertApplicationProjectsQuery = context.prepareUpsert("insert into " +
"app_projects(uuid, application_uuid, project_uuid, created_at) " +
"values (?, ?, ?, ?)");
- for (String projectKey : app.getProjects()) {
+ for (String projectKey : uniqueProjects) {
String applicationProjectUuid = uuidFactory.create();
String projectUuid = projectUuidsByKeys.get(projectKey);
" </vw>\n" +
"</views>";
+ private static final String APP_WITH_DUPLICATED_PROJECTS_XML = "<views>\n" +
+ " <vw key=\"app1-key\" def=\"false\">\n" +
+ " <name><![CDATA[app1-key]]></name>\n" +
+ " <desc><![CDATA[]]></desc>\n" +
+ " <qualifier><![CDATA[APP]]></qualifier>\n" +
+ " <p>proj1-key</p>\n" +
+ " <p>proj1-key</p>\n" +
+ " <branch key=\"app1-branch1\">\n" +
+ " <p branch=\"proj1-branch-1\">proj1-key</p>\n" +
+ " </branch>\n" +
+ " <branch key=\"app1-branch2\">\n" +
+ " <p branch=\"proj1-branch-2\">proj1-key</p>\n" +
+ " </branch>\n" +
+ " </vw>\n" +
+ "</views>";
+
private static final String COMPLEX_XML_BEFORE = "<views>\n" +
" <vw key=\"app1-key\" def=\"false\">\n" +
" <name><![CDATA[app1-key]]></name>\n" +
tuple(APP_2_UUID, PROJECT_2_UUID, APP_2_BRANCH_1_UUID, PROJECT_2_BRANCH_1_UUID));
}
+ @Test
+ public void migrates_applications_handling_project_duplications_to_new_tables() throws SQLException {
+ setupProjectsAndApps();
+ insertViewsDefInternalProperty(APP_WITH_DUPLICATED_PROJECTS_XML);
+
+ underTest.execute();
+
+ assertThat(db.select("select uuid from projects"))
+ .extracting(r -> r.get("UUID"))
+ .containsExactlyInAnyOrder(PROJECT_1_UUID, PROJECT_2_UUID, APP_1_UUID, APP_2_UUID);
+ assertThat(db.select("select application_uuid, project_uuid from app_projects"))
+ .extracting(r -> r.get("APPLICATION_UUID"), r -> r.get("PROJECT_UUID"))
+ .containsExactly(tuple(APP_1_UUID, PROJECT_1_UUID));
+ assertThat(db.select("select application_uuid, project_uuid, application_branch_uuid, project_branch_uuid from app_branch_project_branch"))
+ .extracting(r -> r.get("APPLICATION_UUID"), r -> r.get("PROJECT_UUID"), r -> r.get("APPLICATION_BRANCH_UUID"), r -> r.get("PROJECT_BRANCH_UUID"))
+ .containsExactlyInAnyOrder(
+ tuple(APP_1_UUID, PROJECT_1_UUID, APP_1_BRANCH_1_UUID, PROJECT_1_BRANCH_1_UUID),
+ tuple(APP_1_UUID, PROJECT_1_UUID, APP_1_BRANCH_2_UUID, PROJECT_1_BRANCH_2_UUID));
+ }
+
@Test
public void migration_is_resilient() throws SQLException {
setupProjectsAndApps();