3 * Copyright (C) 2009-2021 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.version.v86;
22 import java.sql.SQLException;
24 import javax.annotation.Nullable;
25 import org.junit.Rule;
26 import org.junit.Test;
27 import org.sonar.api.impl.utils.TestSystem2;
28 import org.sonar.api.utils.System2;
29 import org.sonar.core.util.UuidFactory;
30 import org.sonar.core.util.UuidFactoryFast;
31 import org.sonar.db.CoreDbTester;
32 import org.sonar.server.platform.db.migration.step.MigrationStep;
33 import org.xmlunit.builder.DiffBuilder;
34 import org.xmlunit.builder.Input;
35 import org.xmlunit.diff.Diff;
37 import static org.assertj.core.api.Assertions.assertThat;
38 import static org.assertj.core.api.Assertions.assertThatThrownBy;
39 import static org.assertj.core.api.Assertions.tuple;
40 import static org.sonar.server.platform.db.migration.version.v86.MigrateApplicationDefinitionsFromXmlToDb.TEXT_VALUE_MAX_LENGTH;
42 public class MigrateApplicationDefinitionsFromXmlToDbTest {
43 private static final String QUALIFIER_PROJECT = "TRK";
44 private static final String QUALIFIER_APP = "APP";
45 private static final long NOW = 100_000_000_000L;
47 private static final String PROJECT_1_UUID = "proj1-uuid";
48 private static final String PROJECT_1_MASTER_BRANCH_UUID = "proj1-master-uuid";
49 private static final String PROJECT_1_BRANCH_1_UUID = "proj1-branch1-uuid";
50 private static final String PROJECT_1_BRANCH_2_UUID = "proj1-branch2-uuid";
51 private static final String PROJECT_2_UUID = "proj2-uuid";
52 private static final String PROJECT_2_MASTER_BRANCH_UUID = "proj2-master-uuid";
53 private static final String PROJECT_2_BRANCH_1_UUID = "proj2-branch1-uuid";
54 private static final String APP_1_UUID = "app1-uuid";
55 private static final String APP_1_MASTER_BRANCH_UUID = "app1-master-uuid";
56 private static final String APP_1_BRANCH_1_UUID = "app1-branch1-uuid";
57 private static final String APP_1_BRANCH_2_UUID = "app1-branch2-uuid";
58 private static final String APP_2_UUID = "app2-uuid";
59 private static final String APP_2_MASTER_BRANCH_UUID = "app2-master-uuid";
60 private static final String APP_2_BRANCH_1_UUID = "app2-branch1-uuid";
61 private static final String EMPTY_XML = "<views></views>";
63 private static final String EMPTY_APP_XML = "<views>\n" +
64 " <vw key=\"app1-key\" def=\"false\">\n" +
65 " <name><![CDATA[app1]]></name>\n" +
66 " <desc><![CDATA[]]></desc>\n" +
67 " <qualifier><![CDATA[APP]]></qualifier>\n" +
71 private static final String APP_WITH_NO_BRANCHES_XML = "<views>\n" +
72 " <vw key=\"app1-key\" def=\"false\">\n" +
73 " <name><![CDATA[app1-key]]></name>\n" +
74 " <desc><![CDATA[]]></desc>\n" +
75 " <qualifier><![CDATA[APP]]></qualifier>\n" +
76 " <p>proj1-key</p>\n" +
77 " <p>proj2-key</p>\n" +
81 private static final String COMPLEX_XML_BEFORE = "<views>\n" +
82 " <vw key=\"app1-key\" def=\"false\">\n" +
83 " <name><![CDATA[app1-key]]></name>\n" +
84 " <desc><![CDATA[]]></desc>\n" +
85 " <qualifier><![CDATA[APP]]></qualifier>\n" +
86 " <p>proj1-key</p>\n" +
87 " <p>proj2-key</p>\n" +
88 " <branch key=\"app1-branch1\">\n" +
89 " <p branch=\"proj1-branch-1\">proj1-key</p>\n" +
90 " <p branch=\"m1\">proj2-key</p>\n" +
92 " <branch key=\"app1-branch2\">\n" +
93 " <p branch=\"proj1-branch-2\">proj1-key</p>\n" +
94 " <p branch=\"m1\">proj2-key</p>\n" +
97 " <vw key=\"app2-key\" def=\"false\">\n" +
98 " <name><![CDATA[app2-key]]></name>\n" +
99 " <desc><![CDATA[]]></desc>\n" +
100 " <qualifier><![CDATA[APP]]></qualifier>\n" +
101 " <p>proj1-key</p>\n" +
102 " <p>proj2-key</p>\n" +
103 " <branch key=\"m1\">\n" +
104 " <p branch=\"proj1-branch-1\">proj1-key</p>\n" +
105 " <p branch=\"m1\">proj2-key</p>\n" +
108 " <vw key=\"port1\" def=\"true\">\n" +
109 " <name><![CDATA[port1]]></name>\n" +
110 " <desc><![CDATA[]]></desc>\n" +
111 " <qualifier><![CDATA[VW]]></qualifier>\n" +
113 " <vw key=\"port2\" def=\"false\">\n" +
114 " <name><![CDATA[port2]]></name>\n" +
115 " <desc><![CDATA[]]></desc>\n" +
116 " <qualifier><![CDATA[VW]]></qualifier>\n" +
117 " <vw-ref><![CDATA[app1-key]]></vw-ref>\n" +
118 " <vw-ref><![CDATA[port1]]></vw-ref>\n" +
120 " <vw key=\"port3\" def=\"false\">\n" +
121 " <name><![CDATA[port3]]></name>\n" +
122 " <desc><![CDATA[]]></desc>\n" +
123 " <qualifier><![CDATA[VW]]></qualifier>\n" +
124 " <p>proj1-key</p>\n" +
126 " <vw key=\"port4\" def=\"false\">\n" +
127 " <name><![CDATA[port4]]></name>\n" +
128 " <desc><![CDATA[]]></desc>\n" +
129 " <qualifier><![CDATA[VW]]></qualifier>\n" +
131 " <vw key=\"portx\" def=\"false\" root=\"port2\" parent=\"port2\">\n" +
132 " <name><![CDATA[portx]]></name>\n" +
134 " <vw key=\"port5\" def=\"false\">\n" +
135 " <name><![CDATA[port5]]></name>\n" +
136 " <desc><![CDATA[]]></desc>\n" +
137 " <qualifier><![CDATA[VW]]></qualifier>\n" +
138 " <tagsAssociation>\n" +
139 " <tag>tag1</tag>\n" +
140 " </tagsAssociation>\n" +
142 " <vw key=\"port6\" def=\"false\">\n" +
143 " <name><![CDATA[port6]]></name>\n" +
144 " <desc><![CDATA[]]></desc>\n" +
145 " <regexp><![CDATA[.*oj.*]]></regexp>\n" +
146 " <qualifier><![CDATA[VW]]></qualifier>\n" +
148 " <vw key=\"port7\" def=\"false\">\n" +
149 " <name><![CDATA[port7]]></name>\n" +
150 " <desc><![CDATA[]]></desc>\n" +
151 " <tag_key><![CDATA[business_value]]></tag_key>\n" +
152 " <tag_value><![CDATA[12]]></tag_value>\n" +
153 " <qualifier><![CDATA[VW]]></qualifier>\n" +
157 private static final String COMPLEX_XML_AFTER = "<views>\n" +
158 " <vw key=\"port1\" def=\"true\">\n" +
159 " <name><![CDATA[port1]]></name>\n" +
160 " <desc><![CDATA[]]></desc>\n" +
161 " <qualifier><![CDATA[VW]]></qualifier>\n" +
163 " <vw key=\"port2\" def=\"false\">\n" +
164 " <name><![CDATA[port2]]></name>\n" +
165 " <desc><![CDATA[]]></desc>\n" +
166 " <qualifier><![CDATA[VW]]></qualifier>\n" +
167 " <vw-ref><![CDATA[app1-key]]></vw-ref>\n" +
168 " <vw-ref><![CDATA[port1]]></vw-ref>\n" +
170 " <vw key=\"port3\" def=\"false\">\n" +
171 " <name><![CDATA[port3]]></name>\n" +
172 " <desc><![CDATA[]]></desc>\n" +
173 " <qualifier><![CDATA[VW]]></qualifier>\n" +
174 " <p>proj1-key</p>\n" +
176 " <vw key=\"port4\" def=\"false\">\n" +
177 " <name><![CDATA[port4]]></name>\n" +
178 " <desc><![CDATA[]]></desc>\n" +
179 " <qualifier><![CDATA[VW]]></qualifier>\n" +
181 " <vw key=\"portx\" def=\"false\" root=\"port2\" parent=\"port2\">\n" +
182 " <name><![CDATA[portx]]></name>\n" +
184 " <vw key=\"port5\" def=\"false\">\n" +
185 " <name><![CDATA[port5]]></name>\n" +
186 " <desc><![CDATA[]]></desc>\n" +
187 " <qualifier><![CDATA[VW]]></qualifier>\n" +
188 " <tagsAssociation>\n" +
189 " <tag>tag1</tag>\n" +
190 " </tagsAssociation>\n" +
192 " <vw key=\"port6\" def=\"false\">\n" +
193 " <name><![CDATA[port6]]></name>\n" +
194 " <desc><![CDATA[]]></desc>\n" +
195 " <regexp><![CDATA[.*oj.*]]></regexp>\n" +
196 " <qualifier><![CDATA[VW]]></qualifier>\n" +
198 " <vw key=\"port7\" def=\"false\">\n" +
199 " <name><![CDATA[port7]]></name>\n" +
200 " <desc><![CDATA[]]></desc>\n" +
201 " <tag_key><![CDATA[business_value]]></tag_key>\n" +
202 " <tag_value><![CDATA[12]]></tag_value>\n" +
203 " <qualifier><![CDATA[VW]]></qualifier>\n" +
207 private static final String LARGE_XML_BEFORE_AND_AFTER = "<views>\n" +
208 " <vw key=\"port1\" def=\"true\">\n" +
209 " <name><![CDATA[port1]]></name>\n" +
210 " <desc><![CDATA[]]></desc>\n" +
211 " <qualifier><![CDATA[VW]]></qualifier>\n" +
213 " <vw key=\"port2\" def=\"false\">\n" +
214 " <name><![CDATA[port2]]></name>\n" +
215 " <desc><![CDATA[]]></desc>\n" +
216 " <qualifier><![CDATA[VW]]></qualifier>\n" +
217 " <vw-ref><![CDATA[app1-key]]></vw-ref>\n" +
218 " <vw-ref><![CDATA[port1]]></vw-ref>\n" +
220 " <vw key=\"port3\" def=\"false\">\n" +
221 " <name><![CDATA[port3]]></name>\n" +
222 " <desc><![CDATA[]]></desc>\n" +
223 " <qualifier><![CDATA[VW]]></qualifier>\n" +
224 " <p>proj1-key</p>\n" +
226 " <vw key=\"port4\" def=\"false\">\n" +
227 " <name><![CDATA[port4]]></name>\n" +
228 " <desc><![CDATA[]]></desc>\n" +
229 " <qualifier><![CDATA[VW]]></qualifier>\n" +
231 " <vw key=\"portx\" def=\"false\" root=\"port2\" parent=\"port2\">\n" +
232 " <name><![CDATA[portx]]></name>\n" +
234 " <vw key=\"port5\" def=\"false\">\n" +
235 " <name><![CDATA[port5]]></name>\n" +
236 " <desc><![CDATA[]]></desc>\n" +
237 " <qualifier><![CDATA[VW]]></qualifier>\n" +
238 " <tagsAssociation>\n" +
239 " <tag>tag1</tag>\n" +
240 " </tagsAssociation>\n" +
242 " <vw key=\"port6\" def=\"false\">\n" +
243 " <name><![CDATA[port6]]></name>\n" +
244 " <desc><![CDATA[]]></desc>\n" +
245 " <regexp><![CDATA[.*oj.*]]></regexp>\n" +
246 " <qualifier><![CDATA[VW]]></qualifier>\n" +
248 " <vw key=\"port7\" def=\"false\">\n" +
249 " <name><![CDATA[port7]]></name>\n" +
250 " <desc><![CDATA[]]></desc>\n" +
251 " <tag_key><![CDATA[business_value]]></tag_key>\n" +
252 " <tag_value><![CDATA[12]]></tag_value>\n" +
253 " <qualifier><![CDATA[VW]]></qualifier>\n" +
255 " <vw key=\"port8\" def=\"false\">\n" +
256 " <name><![CDATA[port7]]></name>\n" +
257 " <desc><![CDATA[]]></desc>\n" +
258 " <tag_key><![CDATA[business_value]]></tag_key>\n" +
259 " <tag_value><![CDATA[12]]></tag_value>\n" +
260 " <qualifier><![CDATA[VW]]></qualifier>\n" +
262 " <vw key=\"port9\" def=\"false\">\n" +
263 " <name><![CDATA[port7]]></name>\n" +
264 " <desc><![CDATA[]]></desc>\n" +
265 " <tag_key><![CDATA[business_value]]></tag_key>\n" +
266 " <tag_value><![CDATA[12]]></tag_value>\n" +
267 " <qualifier><![CDATA[VW]]></qualifier>\n" +
269 " <vw key=\"port10\" def=\"false\">\n" +
270 " <name><![CDATA[port7]]></name>\n" +
271 " <desc><![CDATA[]]></desc>\n" +
272 " <tag_key><![CDATA[business_value]]></tag_key>\n" +
273 " <tag_value><![CDATA[12]]></tag_value>\n" +
274 " <qualifier><![CDATA[VW]]></qualifier>\n" +
276 " <vw key=\"port11\" def=\"false\">\n" +
277 " <name><![CDATA[port7]]></name>\n" +
278 " <desc><![CDATA[]]></desc>\n" +
279 " <tag_key><![CDATA[business_value]]></tag_key>\n" +
280 " <tag_value><![CDATA[12]]></tag_value>\n" +
281 " <qualifier><![CDATA[VW]]></qualifier>\n" +
283 " <vw key=\"port12\" def=\"false\">\n" +
284 " <name><![CDATA[port7]]></name>\n" +
285 " <desc><![CDATA[]]></desc>\n" +
286 " <tag_key><![CDATA[business_value]]></tag_key>\n" +
287 " <tag_value><![CDATA[12]]></tag_value>\n" +
288 " <qualifier><![CDATA[VW]]></qualifier>\n" +
290 " <vw key=\"port13\" def=\"false\">\n" +
291 " <name><![CDATA[port7]]></name>\n" +
292 " <desc><![CDATA[]]></desc>\n" +
293 " <tag_key><![CDATA[business_value]]></tag_key>\n" +
294 " <tag_value><![CDATA[12]]></tag_value>\n" +
295 " <qualifier><![CDATA[VW]]></qualifier>\n" +
297 " <vw key=\"port14\" def=\"false\">\n" +
298 " <name><![CDATA[port7]]></name>\n" +
299 " <desc><![CDATA[]]></desc>\n" +
300 " <tag_key><![CDATA[business_value]]></tag_key>\n" +
301 " <tag_value><![CDATA[12]]></tag_value>\n" +
302 " <qualifier><![CDATA[VW]]></qualifier>\n" +
304 " <vw key=\"port15\" def=\"false\">\n" +
305 " <name><![CDATA[port7]]></name>\n" +
306 " <desc><![CDATA[]]></desc>\n" +
307 " <tag_key><![CDATA[business_value]]></tag_key>\n" +
308 " <tag_value><![CDATA[12]]></tag_value>\n" +
309 " <qualifier><![CDATA[VW]]></qualifier>\n" +
311 " <vw key=\"port16\" def=\"false\">\n" +
312 " <name><![CDATA[port7]]></name>\n" +
313 " <desc><![CDATA[]]></desc>\n" +
314 " <tag_key><![CDATA[business_value]]></tag_key>\n" +
315 " <tag_value><![CDATA[12]]></tag_value>\n" +
316 " <qualifier><![CDATA[VW]]></qualifier>\n" +
318 " <vw key=\"port17\" def=\"false\">\n" +
319 " <name><![CDATA[port7]]></name>\n" +
320 " <desc><![CDATA[]]></desc>\n" +
321 " <tag_key><![CDATA[business_value]]></tag_key>\n" +
322 " <tag_value><![CDATA[12]]></tag_value>\n" +
323 " <qualifier><![CDATA[VW]]></qualifier>\n" +
325 " <vw key=\"port18\" def=\"false\">\n" +
326 " <name><![CDATA[port7]]></name>\n" +
327 " <desc><![CDATA[]]></desc>\n" +
328 " <tag_key><![CDATA[business_value]]></tag_key>\n" +
329 " <tag_value><![CDATA[12]]></tag_value>\n" +
330 " <qualifier><![CDATA[VW]]></qualifier>\n" +
332 " <vw key=\"port19\" def=\"false\">\n" +
333 " <name><![CDATA[port7]]></name>\n" +
334 " <desc><![CDATA[]]></desc>\n" +
335 " <tag_key><![CDATA[business_value]]></tag_key>\n" +
336 " <tag_value><![CDATA[12]]></tag_value>\n" +
337 " <qualifier><![CDATA[VW]]></qualifier>\n" +
339 " <vw key=\"port20\" def=\"false\">\n" +
340 " <name><![CDATA[port7]]></name>\n" +
341 " <desc><![CDATA[]]></desc>\n" +
342 " <tag_key><![CDATA[business_value]]></tag_key>\n" +
343 " <tag_value><![CDATA[12]]></tag_value>\n" +
344 " <qualifier><![CDATA[VW]]></qualifier>\n" +
346 " <vw key=\"port21\" def=\"false\">\n" +
347 " <name><![CDATA[port7]]></name>\n" +
348 " <desc><![CDATA[]]></desc>\n" +
349 " <tag_key><![CDATA[business_value]]></tag_key>\n" +
350 " <tag_value><![CDATA[12]]></tag_value>\n" +
351 " <qualifier><![CDATA[VW]]></qualifier>\n" +
356 public CoreDbTester db = CoreDbTester.createForSchema(MigrateApplicationDefinitionsFromXmlToDbTest.class, "schema.sql");
358 private final UuidFactory uuidFactory = UuidFactoryFast.getInstance();
359 private final System2 system2 = new TestSystem2().setNow(NOW);
360 private final MigrationStep underTest = new MigrateApplicationDefinitionsFromXmlToDb(db.database(), uuidFactory, system2);
363 public void does_nothing_when_no_views_def_property() throws SQLException {
364 setupProjectsAndApps();
368 assertThat(db.countSql("select count(*) from app_projects")).isZero();
369 assertThat(db.countSql("select count(*) from app_branch_project_branch")).isZero();
370 assertThat(db.countSql("select count(*) from internal_properties where kee='views.def'")).isZero();
374 public void does_nothing_when_views_def_property_empty_string() throws SQLException {
375 setupProjectsAndApps();
376 insertViewsDefInternalProperty("");
380 assertThat(db.countSql("select count(*) from app_projects")).isZero();
381 assertThat(db.countSql("select count(*) from app_branch_project_branch")).isZero();
385 public void does_nothing_when_views_def_property_empty_views_content() throws SQLException {
386 setupProjectsAndApps();
387 insertViewsDefInternalProperty(EMPTY_XML);
391 assertThat(db.countSql("select count(*) from app_projects")).isZero();
392 assertThat(db.countSql("select count(*) from app_branch_project_branch")).isZero();
396 public void throws_ISE_when_views_def_property_does_not_pass_validation() {
397 setupProjectsAndApps();
398 insertViewsDefInternalProperty("abcdefghi");
400 assertThatThrownBy(underTest::execute)
401 .isInstanceOf(IllegalStateException.class)
402 .hasMessage("Failed to migrate views definitions property.");
404 assertThat(db.countSql("select count(*) from app_projects")).isZero();
405 assertThat(db.countSql("select count(*) from app_branch_project_branch")).isZero();
409 public void migrates_applications_to_new_tables() throws SQLException {
410 setupProjectsAndApps();
411 insertViewsDefInternalProperty(COMPLEX_XML_BEFORE);
415 assertThat(db.select("select uuid from projects"))
416 .extracting(r -> r.get("UUID"))
417 .containsExactlyInAnyOrder(PROJECT_1_UUID, PROJECT_2_UUID, APP_1_UUID, APP_2_UUID);
418 assertThat(db.select("select application_uuid, project_uuid from app_projects"))
419 .extracting(r -> r.get("APPLICATION_UUID"), r -> r.get("PROJECT_UUID"))
420 .containsExactlyInAnyOrder(
421 tuple(APP_1_UUID, PROJECT_1_UUID),
422 tuple(APP_1_UUID, PROJECT_2_UUID),
423 tuple(APP_2_UUID, PROJECT_1_UUID),
424 tuple(APP_2_UUID, PROJECT_2_UUID));
425 assertThat(db.select("select application_uuid, project_uuid, application_branch_uuid, project_branch_uuid from app_branch_project_branch"))
426 .extracting(r -> r.get("APPLICATION_UUID"), r -> r.get("PROJECT_UUID"), r -> r.get("APPLICATION_BRANCH_UUID"), r -> r.get("PROJECT_BRANCH_UUID"))
427 .containsExactlyInAnyOrder(
428 tuple(APP_1_UUID, PROJECT_1_UUID, APP_1_BRANCH_1_UUID, PROJECT_1_BRANCH_1_UUID),
429 tuple(APP_1_UUID, PROJECT_2_UUID, APP_1_BRANCH_1_UUID, PROJECT_2_BRANCH_1_UUID),
430 tuple(APP_1_UUID, PROJECT_1_UUID, APP_1_BRANCH_2_UUID, PROJECT_1_BRANCH_2_UUID),
431 tuple(APP_1_UUID, PROJECT_2_UUID, APP_1_BRANCH_2_UUID, PROJECT_2_BRANCH_1_UUID),
432 tuple(APP_2_UUID, PROJECT_1_UUID, APP_2_BRANCH_1_UUID, PROJECT_1_BRANCH_1_UUID),
433 tuple(APP_2_UUID, PROJECT_2_UUID, APP_2_BRANCH_1_UUID, PROJECT_2_BRANCH_1_UUID));
437 public void migration_is_resilient() throws SQLException {
438 setupProjectsAndApps();
439 insertViewsDefInternalProperty(COMPLEX_XML_BEFORE);
444 // xml stays the same (stopped during migration)
445 updateViewsDefInternalProperty(COMPLEX_XML_BEFORE);
447 // second attempt should not fail
450 assertThat(db.select("select uuid from projects"))
451 .extracting(r -> r.get("UUID"))
452 .containsExactlyInAnyOrder(PROJECT_1_UUID, PROJECT_2_UUID, APP_1_UUID, APP_2_UUID);
453 assertThat(db.select("select application_uuid, project_uuid from app_projects"))
454 .extracting(r -> r.get("APPLICATION_UUID"), r -> r.get("PROJECT_UUID"))
455 .containsExactlyInAnyOrder(
456 tuple(APP_1_UUID, PROJECT_1_UUID),
457 tuple(APP_1_UUID, PROJECT_2_UUID),
458 tuple(APP_2_UUID, PROJECT_1_UUID),
459 tuple(APP_2_UUID, PROJECT_2_UUID));
460 assertThat(db.select("select application_uuid, project_uuid, application_branch_uuid, project_branch_uuid from app_branch_project_branch"))
461 .extracting(r -> r.get("APPLICATION_UUID"), r -> r.get("PROJECT_UUID"), r -> r.get("APPLICATION_BRANCH_UUID"), r -> r.get("PROJECT_BRANCH_UUID"))
462 .containsExactlyInAnyOrder(
463 tuple(APP_1_UUID, PROJECT_1_UUID, APP_1_BRANCH_1_UUID, PROJECT_1_BRANCH_1_UUID),
464 tuple(APP_1_UUID, PROJECT_2_UUID, APP_1_BRANCH_1_UUID, PROJECT_2_BRANCH_1_UUID),
465 tuple(APP_1_UUID, PROJECT_1_UUID, APP_1_BRANCH_2_UUID, PROJECT_1_BRANCH_2_UUID),
466 tuple(APP_1_UUID, PROJECT_2_UUID, APP_1_BRANCH_2_UUID, PROJECT_2_BRANCH_1_UUID),
467 tuple(APP_2_UUID, PROJECT_1_UUID, APP_2_BRANCH_1_UUID, PROJECT_1_BRANCH_1_UUID),
468 tuple(APP_2_UUID, PROJECT_2_UUID, APP_2_BRANCH_1_UUID, PROJECT_2_BRANCH_1_UUID));
472 public void migrates_applications_without_application_branches_to_new_tables() throws SQLException {
475 setupApp1WithNoBranches();
476 insertViewsDefInternalProperty(APP_WITH_NO_BRANCHES_XML);
480 assertThat(db.select("select uuid from projects"))
481 .extracting(r -> r.get("UUID"))
482 .containsExactlyInAnyOrder(PROJECT_1_UUID, PROJECT_2_UUID, APP_1_UUID);
483 assertThat(db.select("select application_uuid, project_uuid from app_projects"))
484 .extracting(r -> r.get("APPLICATION_UUID"), r -> r.get("PROJECT_UUID"))
485 .containsExactlyInAnyOrder(
486 tuple(APP_1_UUID, PROJECT_1_UUID),
487 tuple(APP_1_UUID, PROJECT_2_UUID));
488 assertThat(db.countSql("select count(*) from app_branch_project_branch")).isZero();
492 public void skips_apps_that_exist_in_the_definition_but_does_not_exist_in_db() throws SQLException {
494 insertViewsDefInternalProperty(EMPTY_APP_XML);
498 assertThat(db.select("select uuid from projects"))
499 .extracting(r -> r.get("UUID"))
500 .containsExactlyInAnyOrder(PROJECT_1_UUID);
501 assertThat(db.countSql("select count(*) from app_projects")).isZero();
502 assertThat(db.countSql("select count(*) from app_branch_project_branch")).isZero();
506 public void migrates_app_with_0_projects_in_views_definition() throws SQLException {
509 setupApp1WithNoBranches();
510 insertViewsDefInternalProperty(EMPTY_APP_XML);
514 assertThat(db.select("select uuid from projects"))
515 .extracting(r -> r.get("UUID"))
516 .containsExactlyInAnyOrder(PROJECT_1_UUID, PROJECT_2_UUID, APP_1_UUID);
517 assertThat(db.countSql("select count(*) from app_projects")).isZero();
518 assertThat(db.countSql("select count(*) from app_branch_project_branch")).isZero();
522 public void skips_apps_that_are_present_in_views_definition_but_not_in_db() throws SQLException {
525 setupApp1WithTwoBranches();
526 insertViewsDefInternalProperty(COMPLEX_XML_BEFORE);
530 assertThat(db.select("select uuid from projects"))
531 .extracting(r -> r.get("UUID"))
532 .containsExactlyInAnyOrder(PROJECT_1_UUID, PROJECT_2_UUID, APP_1_UUID);
533 assertThat(db.select("select application_uuid, project_uuid from app_projects"))
534 .extracting(r -> r.get("APPLICATION_UUID"), r -> r.get("PROJECT_UUID"))
535 .containsExactlyInAnyOrder(
536 tuple(APP_1_UUID, PROJECT_1_UUID),
537 tuple(APP_1_UUID, PROJECT_2_UUID));
538 assertThat(db.select("select application_uuid, project_uuid, application_branch_uuid, project_branch_uuid from app_branch_project_branch"))
539 .extracting(r -> r.get("APPLICATION_UUID"), r -> r.get("PROJECT_UUID"), r -> r.get("APPLICATION_BRANCH_UUID"), r -> r.get("PROJECT_BRANCH_UUID"))
540 .containsExactlyInAnyOrder(
541 tuple(APP_1_UUID, PROJECT_1_UUID, APP_1_BRANCH_1_UUID, PROJECT_1_BRANCH_1_UUID),
542 tuple(APP_1_UUID, PROJECT_2_UUID, APP_1_BRANCH_1_UUID, PROJECT_2_BRANCH_1_UUID),
543 tuple(APP_1_UUID, PROJECT_1_UUID, APP_1_BRANCH_2_UUID, PROJECT_1_BRANCH_2_UUID),
544 tuple(APP_1_UUID, PROJECT_2_UUID, APP_1_BRANCH_2_UUID, PROJECT_2_BRANCH_1_UUID));
548 public void skips_app_branches_that_are_present_in_views_definition_but_not_in_db() throws SQLException {
551 setupApp1WithNoBranches();
553 insertViewsDefInternalProperty(COMPLEX_XML_BEFORE);
557 assertThat(db.select("select uuid from projects"))
558 .extracting(r -> r.get("UUID"))
559 .containsExactlyInAnyOrder(PROJECT_1_UUID, PROJECT_2_UUID, APP_1_UUID, APP_2_UUID);
560 assertThat(db.select("select application_uuid, project_uuid from app_projects"))
561 .extracting(r -> r.get("APPLICATION_UUID"), r -> r.get("PROJECT_UUID"))
562 .containsExactlyInAnyOrder(
563 tuple(APP_1_UUID, PROJECT_1_UUID),
564 tuple(APP_1_UUID, PROJECT_2_UUID),
565 tuple(APP_2_UUID, PROJECT_1_UUID),
566 tuple(APP_2_UUID, PROJECT_2_UUID));
567 assertThat(db.select("select application_uuid, project_uuid, application_branch_uuid, project_branch_uuid from app_branch_project_branch"))
568 .extracting(r -> r.get("APPLICATION_UUID"), r -> r.get("PROJECT_UUID"), r -> r.get("APPLICATION_BRANCH_UUID"), r -> r.get("PROJECT_BRANCH_UUID"))
569 .containsExactlyInAnyOrder(
570 tuple(APP_2_UUID, PROJECT_1_UUID, APP_2_BRANCH_1_UUID, PROJECT_1_BRANCH_1_UUID),
571 tuple(APP_2_UUID, PROJECT_2_UUID, APP_2_BRANCH_1_UUID, PROJECT_2_BRANCH_1_UUID));
575 public void skips_projects_that_are_present_in_apps_views_definitions_but_not_in_db() throws SQLException {
576 setupPartialProject1();
577 setupApp1WithTwoBranches();
579 insertViewsDefInternalProperty(COMPLEX_XML_BEFORE);
583 assertThat(db.select("select uuid from projects"))
584 .extracting(r -> r.get("UUID"))
585 .containsExactlyInAnyOrder(PROJECT_1_UUID, APP_1_UUID, APP_2_UUID);
586 assertThat(db.select("select application_uuid, project_uuid from app_projects"))
587 .extracting(r -> r.get("APPLICATION_UUID"), r -> r.get("PROJECT_UUID"))
588 .containsExactlyInAnyOrder(
589 tuple(APP_1_UUID, PROJECT_1_UUID),
590 tuple(APP_2_UUID, PROJECT_1_UUID));
591 assertThat(db.select("select application_uuid, project_uuid, application_branch_uuid, project_branch_uuid from app_branch_project_branch"))
592 .extracting(r -> r.get("APPLICATION_UUID"), r -> r.get("PROJECT_UUID"), r -> r.get("APPLICATION_BRANCH_UUID"), r -> r.get("PROJECT_BRANCH_UUID"))
593 .containsExactlyInAnyOrder(
594 tuple(APP_1_UUID, PROJECT_1_UUID, APP_1_BRANCH_1_UUID, PROJECT_1_BRANCH_1_UUID),
595 tuple(APP_2_UUID, PROJECT_1_UUID, APP_2_BRANCH_1_UUID, PROJECT_1_BRANCH_1_UUID));
599 public void skips_projects_branches_that_are_present_in_apps_views_definitions_but_not_in_db() throws SQLException {
600 setupPartialProject1();
602 setupApp1WithTwoBranches();
604 insertViewsDefInternalProperty(COMPLEX_XML_BEFORE);
608 assertThat(db.select("select uuid from projects"))
609 .extracting(r -> r.get("UUID"))
610 .containsExactlyInAnyOrder(PROJECT_1_UUID, PROJECT_2_UUID, APP_1_UUID, APP_2_UUID);
611 assertThat(db.select("select application_uuid, project_uuid from app_projects"))
612 .extracting(r -> r.get("APPLICATION_UUID"), r -> r.get("PROJECT_UUID"))
613 .containsExactlyInAnyOrder(
614 tuple(APP_1_UUID, PROJECT_1_UUID),
615 tuple(APP_1_UUID, PROJECT_2_UUID),
616 tuple(APP_2_UUID, PROJECT_1_UUID),
617 tuple(APP_2_UUID, PROJECT_2_UUID));
618 assertThat(db.select("select application_uuid, project_uuid, application_branch_uuid, project_branch_uuid from app_branch_project_branch"))
619 .extracting(r -> r.get("APPLICATION_UUID"), r -> r.get("PROJECT_UUID"), r -> r.get("APPLICATION_BRANCH_UUID"), r -> r.get("PROJECT_BRANCH_UUID"))
620 .containsExactlyInAnyOrder(
621 tuple(APP_1_UUID, PROJECT_1_UUID, APP_1_BRANCH_1_UUID, PROJECT_1_BRANCH_1_UUID),
622 tuple(APP_1_UUID, PROJECT_2_UUID, APP_1_BRANCH_1_UUID, PROJECT_2_BRANCH_1_UUID),
623 tuple(APP_1_UUID, PROJECT_2_UUID, APP_1_BRANCH_2_UUID, PROJECT_2_BRANCH_1_UUID),
624 tuple(APP_2_UUID, PROJECT_1_UUID, APP_2_BRANCH_1_UUID, PROJECT_1_BRANCH_1_UUID),
625 tuple(APP_2_UUID, PROJECT_2_UUID, APP_2_BRANCH_1_UUID, PROJECT_2_BRANCH_1_UUID));
629 public void removes_application_definitions_from_xml() throws SQLException {
630 setupProjectsAndApps();
631 insertViewsDefInternalProperty(COMPLEX_XML_BEFORE);
635 assertThat(db.countSql("select count(*) from internal_properties where kee='views.def'")).isOne();
636 assertViewsXmlDefinitionSimilar(COMPLEX_XML_AFTER, false);
640 public void removes_application_definitions_from_large_xmls() throws SQLException {
641 setupProjectsAndApps();
642 insertViewsDefInternalProperty(LARGE_XML_BEFORE_AND_AFTER);
646 assertThat(db.countSql("select count(*) from internal_properties where kee='views.def'")).isOne();
647 assertViewsXmlDefinitionSimilar(LARGE_XML_BEFORE_AND_AFTER, true);
651 public void does_not_change_the_xml_if_there_are_no_application_definitions() throws SQLException {
652 setupProjectsAndApps();
653 insertViewsDefInternalProperty(EMPTY_XML);
657 assertThat(db.countSql("select count(*) from internal_properties where kee='views.def'")).isOne();
658 assertViewsXmlDefinitionSimilar(EMPTY_XML, false);
661 private void setupProjectsAndApps() {
664 setupApp1WithTwoBranches();
668 private void setupFullProject1() {
669 setupPartialProject1();
670 insertBranch(PROJECT_1_BRANCH_2_UUID, PROJECT_1_UUID, "proj1-branch-2");
673 private void setupPartialProject1() {
674 insertProject(PROJECT_1_UUID, "proj1-key", QUALIFIER_PROJECT);
675 insertBranch(PROJECT_1_MASTER_BRANCH_UUID, PROJECT_1_UUID, "master");
676 insertBranch(PROJECT_1_BRANCH_1_UUID, PROJECT_1_UUID, "proj1-branch-1");
679 private void setupProject2() {
680 insertProject(PROJECT_2_UUID, "proj2-key", QUALIFIER_PROJECT);
681 insertBranch(PROJECT_2_MASTER_BRANCH_UUID, PROJECT_2_UUID, "master");
682 insertBranch(PROJECT_2_BRANCH_1_UUID, PROJECT_2_UUID, "m1");
685 private void setupApp1WithNoBranches() {
686 insertProject(APP_1_UUID, "app1-key", QUALIFIER_APP);
687 insertBranch(APP_1_MASTER_BRANCH_UUID, APP_1_UUID, "master");
690 private void setupApp1WithOneBranch() {
691 setupApp1WithNoBranches();
692 insertBranch(APP_1_BRANCH_1_UUID, APP_1_UUID, "app1-branch1");
695 private void setupApp1WithTwoBranches() {
696 setupApp1WithOneBranch();
697 insertBranch(APP_1_BRANCH_2_UUID, APP_1_UUID, "app1-branch2");
700 private void setupApp2() {
701 insertProject(APP_2_UUID, "app2-key", QUALIFIER_APP);
702 insertBranch(APP_2_MASTER_BRANCH_UUID, APP_2_UUID, "master");
703 insertBranch(APP_2_BRANCH_1_UUID, APP_2_UUID, "m1");
706 private void insertViewsDefInternalProperty(@Nullable String xml) {
707 String valueColumn = "text_value";
708 if (xml != null && xml.length() > TEXT_VALUE_MAX_LENGTH) {
709 valueColumn = "clob_value";
712 db.executeInsert("internal_properties",
716 "created_at", system2.now());
719 private void updateViewsDefInternalProperty(@Nullable String xml) {
720 db.executeUpdateSql("update internal_properties set text_value = ? where kee = 'views.def'",
724 private void insertProject(String uuid, String key, String qualifier) {
725 db.executeInsert("PROJECTS",
728 "QUALIFIER", qualifier,
729 "ORGANIZATION_UUID", uuid + "-key",
731 "PRIVATE", Boolean.toString(false),
732 "UPDATED_AT", System2.INSTANCE.now());
735 private void insertBranch(String uuid, String projectUuid, String key) {
739 "PROJECT_UUID", projectUuid,
741 "BRANCH_TYPE", "BRANCH",
742 "MERGE_BRANCH_UUID", null,
743 "CREATED_AT", System2.INSTANCE.now(),
744 "UPDATED_AT", System2.INSTANCE.now(),
745 "NEED_ISSUE_SYNC", Boolean.toString(false));
748 private void assertViewsXmlDefinitionSimilar(final String expectedValue, final boolean expectClob) {
749 Map<String, Object> result = db.selectFirst("select text_value, clob_value from internal_properties where kee='views.def'");
750 String textValue = (String) result.get("TEXT_VALUE");
751 String clobValue = (String) result.get("CLOB_VALUE");
753 String existingValue;
755 existingValue = clobValue;
756 assertThat(textValue).isNull();
758 existingValue = textValue;
759 assertThat(clobValue).isNull();
762 Diff diff = DiffBuilder
763 .compare(Input.fromString(expectedValue))
764 .withTest(Input.fromString(existingValue))
769 assertThat(diff.getDifferences())