3 * Copyright (C) 2009-2020 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\" 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 migrates_applications_without_application_branches_to_new_tables() throws SQLException {
440 setupApp1WithNoBranches();
441 insertViewsDefInternalProperty(APP_WITH_NO_BRANCHES_XML);
445 assertThat(db.select("select uuid from projects"))
446 .extracting(r -> r.get("UUID"))
447 .containsExactlyInAnyOrder(PROJECT_1_UUID, PROJECT_2_UUID, APP_1_UUID);
448 assertThat(db.select("select application_uuid, project_uuid from app_projects"))
449 .extracting(r -> r.get("APPLICATION_UUID"), r -> r.get("PROJECT_UUID"))
450 .containsExactlyInAnyOrder(
451 tuple(APP_1_UUID, PROJECT_1_UUID),
452 tuple(APP_1_UUID, PROJECT_2_UUID));
453 assertThat(db.countSql("select count(*) from app_branch_project_branch")).isZero();
457 public void migrates_app_with_0_projects_in_views_definition() throws SQLException {
458 setupProjectsAndApps();
459 insertViewsDefInternalProperty(EMPTY_APP_XML);
463 assertThat(db.select("select uuid from projects"))
464 .extracting(r -> r.get("UUID"))
465 .containsExactlyInAnyOrder(PROJECT_1_UUID, PROJECT_2_UUID, APP_1_UUID, APP_2_UUID);
466 assertThat(db.countSql("select count(*) from app_projects")).isZero();
467 assertThat(db.countSql("select count(*) from app_branch_project_branch")).isZero();
471 public void skips_apps_that_are_present_in_views_definition_but_not_in_db() throws SQLException {
474 setupApp1WithTwoBranches();
475 insertViewsDefInternalProperty(COMPLEX_XML_BEFORE);
479 assertThat(db.select("select uuid from projects"))
480 .extracting(r -> r.get("UUID"))
481 .containsExactlyInAnyOrder(PROJECT_1_UUID, PROJECT_2_UUID, APP_1_UUID);
482 assertThat(db.select("select application_uuid, project_uuid from app_projects"))
483 .extracting(r -> r.get("APPLICATION_UUID"), r -> r.get("PROJECT_UUID"))
484 .containsExactlyInAnyOrder(
485 tuple(APP_1_UUID, PROJECT_1_UUID),
486 tuple(APP_1_UUID, PROJECT_2_UUID));
487 assertThat(db.select("select application_uuid, project_uuid, application_branch_uuid, project_branch_uuid from app_branch_project_branch"))
488 .extracting(r -> r.get("APPLICATION_UUID"), r -> r.get("PROJECT_UUID"), r -> r.get("APPLICATION_BRANCH_UUID"), r -> r.get("PROJECT_BRANCH_UUID"))
489 .containsExactlyInAnyOrder(
490 tuple(APP_1_UUID, PROJECT_1_UUID, APP_1_BRANCH_1_UUID, PROJECT_1_BRANCH_1_UUID),
491 tuple(APP_1_UUID, PROJECT_2_UUID, APP_1_BRANCH_1_UUID, PROJECT_2_BRANCH_1_UUID),
492 tuple(APP_1_UUID, PROJECT_1_UUID, APP_1_BRANCH_2_UUID, PROJECT_1_BRANCH_2_UUID),
493 tuple(APP_1_UUID, PROJECT_2_UUID, APP_1_BRANCH_2_UUID, PROJECT_2_BRANCH_1_UUID));
497 public void skips_app_branches_that_are_present_in_views_definition_but_not_in_db() throws SQLException {
500 setupApp1WithNoBranches();
502 insertViewsDefInternalProperty(COMPLEX_XML_BEFORE);
506 assertThat(db.select("select uuid from projects"))
507 .extracting(r -> r.get("UUID"))
508 .containsExactlyInAnyOrder(PROJECT_1_UUID, PROJECT_2_UUID, APP_1_UUID, APP_2_UUID);
509 assertThat(db.select("select application_uuid, project_uuid from app_projects"))
510 .extracting(r -> r.get("APPLICATION_UUID"), r -> r.get("PROJECT_UUID"))
511 .containsExactlyInAnyOrder(
512 tuple(APP_1_UUID, PROJECT_1_UUID),
513 tuple(APP_1_UUID, PROJECT_2_UUID),
514 tuple(APP_2_UUID, PROJECT_1_UUID),
515 tuple(APP_2_UUID, PROJECT_2_UUID));
516 assertThat(db.select("select application_uuid, project_uuid, application_branch_uuid, project_branch_uuid from app_branch_project_branch"))
517 .extracting(r -> r.get("APPLICATION_UUID"), r -> r.get("PROJECT_UUID"), r -> r.get("APPLICATION_BRANCH_UUID"), r -> r.get("PROJECT_BRANCH_UUID"))
518 .containsExactlyInAnyOrder(
519 tuple(APP_2_UUID, PROJECT_1_UUID, APP_2_BRANCH_1_UUID, PROJECT_1_BRANCH_1_UUID),
520 tuple(APP_2_UUID, PROJECT_2_UUID, APP_2_BRANCH_1_UUID, PROJECT_2_BRANCH_1_UUID));
524 public void skips_projects_that_are_present_in_apps_views_definitions_but_not_in_db() throws SQLException {
525 setupPartialProject1();
526 setupApp1WithTwoBranches();
528 insertViewsDefInternalProperty(COMPLEX_XML_BEFORE);
532 assertThat(db.select("select uuid from projects"))
533 .extracting(r -> r.get("UUID"))
534 .containsExactlyInAnyOrder(PROJECT_1_UUID, APP_1_UUID, APP_2_UUID);
535 assertThat(db.select("select application_uuid, project_uuid from app_projects"))
536 .extracting(r -> r.get("APPLICATION_UUID"), r -> r.get("PROJECT_UUID"))
537 .containsExactlyInAnyOrder(
538 tuple(APP_1_UUID, PROJECT_1_UUID),
539 tuple(APP_2_UUID, PROJECT_1_UUID));
540 assertThat(db.select("select application_uuid, project_uuid, application_branch_uuid, project_branch_uuid from app_branch_project_branch"))
541 .extracting(r -> r.get("APPLICATION_UUID"), r -> r.get("PROJECT_UUID"), r -> r.get("APPLICATION_BRANCH_UUID"), r -> r.get("PROJECT_BRANCH_UUID"))
542 .containsExactlyInAnyOrder(
543 tuple(APP_1_UUID, PROJECT_1_UUID, APP_1_BRANCH_1_UUID, PROJECT_1_BRANCH_1_UUID),
544 tuple(APP_2_UUID, PROJECT_1_UUID, APP_2_BRANCH_1_UUID, PROJECT_1_BRANCH_1_UUID));
548 public void skips_projects_branches_that_are_present_in_apps_views_definitions_but_not_in_db() throws SQLException {
549 setupPartialProject1();
551 setupApp1WithTwoBranches();
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_1_UUID, PROJECT_1_UUID, APP_1_BRANCH_1_UUID, PROJECT_1_BRANCH_1_UUID),
571 tuple(APP_1_UUID, PROJECT_2_UUID, APP_1_BRANCH_1_UUID, PROJECT_2_BRANCH_1_UUID),
572 tuple(APP_1_UUID, PROJECT_2_UUID, APP_1_BRANCH_2_UUID, PROJECT_2_BRANCH_1_UUID),
573 tuple(APP_2_UUID, PROJECT_1_UUID, APP_2_BRANCH_1_UUID, PROJECT_1_BRANCH_1_UUID),
574 tuple(APP_2_UUID, PROJECT_2_UUID, APP_2_BRANCH_1_UUID, PROJECT_2_BRANCH_1_UUID));
578 public void removes_application_definitions_from_xml() throws SQLException {
579 setupProjectsAndApps();
580 insertViewsDefInternalProperty(COMPLEX_XML_BEFORE);
584 assertThat(db.countSql("select count(*) from internal_properties where kee='views.def'")).isOne();
585 assertViewsXmlDefinitionSimilar(COMPLEX_XML_AFTER, false);
589 public void removes_application_definitions_from_large_xmls() throws SQLException {
590 setupProjectsAndApps();
591 insertViewsDefInternalProperty(LARGE_XML_BEFORE_AND_AFTER);
595 assertThat(db.countSql("select count(*) from internal_properties where kee='views.def'")).isOne();
596 assertViewsXmlDefinitionSimilar(LARGE_XML_BEFORE_AND_AFTER, true);
600 public void does_not_change_the_xml_if_there_are_no_application_definitions() throws SQLException {
601 setupProjectsAndApps();
602 insertViewsDefInternalProperty(EMPTY_XML);
606 assertThat(db.countSql("select count(*) from internal_properties where kee='views.def'")).isOne();
607 assertViewsXmlDefinitionSimilar(EMPTY_XML, false);
610 private void setupProjectsAndApps() {
613 setupApp1WithTwoBranches();
617 private void setupFullProject1() {
618 setupPartialProject1();
619 insertBranch(PROJECT_1_BRANCH_2_UUID, PROJECT_1_UUID, "proj1-branch-2");
622 private void setupPartialProject1() {
623 insertProject(PROJECT_1_UUID, "proj1-key", QUALIFIER_PROJECT);
624 insertBranch(PROJECT_1_MASTER_BRANCH_UUID, PROJECT_1_UUID, "master");
625 insertBranch(PROJECT_1_BRANCH_1_UUID, PROJECT_1_UUID, "proj1-branch-1");
628 private void setupProject2() {
629 insertProject(PROJECT_2_UUID, "proj2-key", QUALIFIER_PROJECT);
630 insertBranch(PROJECT_2_MASTER_BRANCH_UUID, PROJECT_2_UUID, "master");
631 insertBranch(PROJECT_2_BRANCH_1_UUID, PROJECT_2_UUID, "m1");
634 private void setupApp1WithNoBranches() {
635 insertProject(APP_1_UUID, "app1-key", QUALIFIER_APP);
636 insertBranch(APP_1_MASTER_BRANCH_UUID, APP_1_UUID, "master");
639 private void setupApp1WithOneBranch() {
640 setupApp1WithNoBranches();
641 insertBranch(APP_1_BRANCH_1_UUID, APP_1_UUID, "app1-branch1");
644 private void setupApp1WithTwoBranches() {
645 setupApp1WithOneBranch();
646 insertBranch(APP_1_BRANCH_2_UUID, APP_1_UUID, "app1-branch2");
649 private void setupApp2() {
650 insertProject(APP_2_UUID, "app2-key", QUALIFIER_APP);
651 insertBranch(APP_2_MASTER_BRANCH_UUID, APP_2_UUID, "master");
652 insertBranch(APP_2_BRANCH_1_UUID, APP_2_UUID, "m1");
655 private void insertViewsDefInternalProperty(@Nullable String xml) {
656 String valueColumn = "text_value";
657 if (xml != null && xml.length() > TEXT_VALUE_MAX_LENGTH) {
658 valueColumn = "clob_value";
661 db.executeInsert("internal_properties",
665 "created_at", system2.now());
668 private void insertProject(String uuid, String key, String qualifier) {
669 db.executeInsert("PROJECTS",
672 "QUALIFIER", qualifier,
673 "ORGANIZATION_UUID", uuid + "-key",
675 "PRIVATE", Boolean.toString(false),
676 "UPDATED_AT", System2.INSTANCE.now());
679 private void insertBranch(String uuid, String projectUuid, String key) {
683 "PROJECT_UUID", projectUuid,
685 "BRANCH_TYPE", "BRANCH",
686 "MERGE_BRANCH_UUID", null,
687 "CREATED_AT", System2.INSTANCE.now(),
688 "UPDATED_AT", System2.INSTANCE.now(),
689 "NEED_ISSUE_SYNC", Boolean.toString(false));
692 private void assertViewsXmlDefinitionSimilar(final String expectedValue, final boolean expectClob) {
693 Map<String, Object> result = db.selectFirst("select text_value, clob_value from internal_properties where kee='views.def'");
694 String textValue = (String) result.get("TEXT_VALUE");
695 String clobValue = (String) result.get("CLOB_VALUE");
697 String existingValue;
699 existingValue = clobValue;
700 assertThat(textValue).isNull();
702 existingValue = textValue;
703 assertThat(clobValue).isNull();
706 Diff diff = DiffBuilder
707 .compare(Input.fromString(expectedValue))
708 .withTest(Input.fromString(existingValue))
713 assertThat(diff.getDifferences())