457f92b196793973837dac07184f89853dcbe833
java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/LeagueEventHierarchyOwnershipChangeTest.java
| ... | ... | @@ -2,6 +2,7 @@ package com.sap.sailing.server.test; |
| 2 | 2 | |
| 3 | 3 | import static org.junit.jupiter.api.Assertions.assertNull; |
| 4 | 4 | import static org.junit.jupiter.api.Assertions.assertSame; |
| 5 | +import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively; |
|
| 5 | 6 | |
| 6 | 7 | import java.util.Collections; |
| 7 | 8 | import java.util.Locale; |
| ... | ... | @@ -142,6 +143,48 @@ public class LeagueEventHierarchyOwnershipChangeTest { |
| 142 | 143 | final OwnershipAnnotation eventOwnership = securityService.getOwnership(event.getIdentifier()); |
| 143 | 144 | assertSame(eventOwnership.getAnnotation().getTenantOwner(), lg2Ownership.getAnnotation().getTenantOwner()); |
| 144 | 145 | } |
| 146 | + |
|
| 147 | + @Test |
|
| 148 | + public void testCyclicLeagueHierarchyOwnershipChangeStartingAtEventTerminatesWithNewCourseArea() { |
|
| 149 | + final CourseArea otherCourseArea = new CourseAreaImpl("Other", UUID.randomUUID(), /* centerPosition */ null, /* radius */ null); |
|
| 150 | + testCyclicLeagueHierarchyOwnershipChangeStartingAtEventTerminates(otherCourseArea); |
|
| 151 | + } |
|
| 152 | + |
|
| 153 | + @Test |
|
| 154 | + public void testCyclicLeagueHierarchyOwnershipChangeStartingAtEventTerminatesWithSharedCourseArea() { |
|
| 155 | + testCyclicLeagueHierarchyOwnershipChangeStartingAtEventTerminates(defaultCourseArea); |
|
| 156 | + } |
|
| 157 | + |
|
| 158 | + private void testCyclicLeagueHierarchyOwnershipChangeStartingAtEventTerminates(CourseArea courseAreaForSharedLeaderboard) { |
|
| 159 | + final Event otherEvent = service.addEvent("Test2", "Test Event 2", TimePoint.now(), TimePoint.now().plus(Duration.ONE_WEEK), "There", |
|
| 160 | + /* isPublic */ true, UUID.randomUUID()); |
|
| 161 | + otherEvent.getVenue().addCourseArea(courseAreaForSharedLeaderboard); |
|
| 162 | + try { |
|
| 163 | + final LeaderboardGroup sharedLeaderboardGroup = new LeaderboardGroupImpl("LG-shared", "LGDesc-shared", |
|
| 164 | + "The shared LG", /* displayGroupsInReverseOrder */ false, Collections.emptyList()); |
|
| 165 | + final Leaderboard sharedOverallLeaderboard = new LeaderboardGroupMetaLeaderboard(sharedLeaderboardGroup, new LowPoint(), |
|
| 166 | + new ThresholdBasedResultDiscardingRuleImpl(new int[0])); |
|
| 167 | + sharedLeaderboardGroup.setOverallLeaderboard(sharedOverallLeaderboard); |
|
| 168 | + sharedLeaderboardGroup.addLeaderboard(new FlexibleLeaderboardImpl("SharedFlexibleLeaderboard", |
|
| 169 | + new ThresholdBasedResultDiscardingRuleImpl(new int[0]), new LowPoint(), defaultCourseArea)); |
|
| 170 | + event.addLeaderboardGroup(sharedLeaderboardGroup); |
|
| 171 | + otherEvent.addLeaderboardGroup(sharedLeaderboardGroup); |
|
| 172 | + assertTimeoutPreemptively(java.time.Duration.ofSeconds(5), () -> SailingHierarchyOwnershipUpdater |
|
| 173 | + .createOwnershipUpdater(/* createNewGroup */ true, /* existingGroupIdOrNull */ null, |
|
| 174 | + THE_NEW_OWNING_GROUP_NAME, /* migrateCompetitors */ true, /* migrateBoats */ true, |
|
| 175 | + /* copyMembersAndRoles */ true, service) |
|
| 176 | + .updateGroupOwnershipForEventHierarchy(event)); |
|
| 177 | + final OwnershipAnnotation eventOwnership = securityService.getOwnership(event.getIdentifier()); |
|
| 178 | + final OwnershipAnnotation otherEventOwnership = securityService.getOwnership(otherEvent.getIdentifier()); |
|
| 179 | + assertSame(eventOwnership.getAnnotation().getTenantOwner(), otherEventOwnership.getAnnotation().getTenantOwner()); |
|
| 180 | + final OwnershipAnnotation overallLeaderboardOwnership = securityService.getOwnership(overallLeaderboard.getIdentifier()); |
|
| 181 | + assertSame(eventOwnership.getAnnotation().getTenantOwner(), overallLeaderboardOwnership.getAnnotation().getTenantOwner()); |
|
| 182 | + final OwnershipAnnotation sharedOverallLeaderboardOwnership = securityService.getOwnership(sharedOverallLeaderboard.getIdentifier()); |
|
| 183 | + assertSame(eventOwnership.getAnnotation().getTenantOwner(), sharedOverallLeaderboardOwnership.getAnnotation().getTenantOwner()); |
|
| 184 | + } finally { |
|
| 185 | + service.removeEvent(otherEvent.getId()); |
|
| 186 | + } |
|
| 187 | + } |
|
| 145 | 188 | |
| 146 | 189 | @AfterEach |
| 147 | 190 | public void tearDown() { |
java/com.sap.sailing.server/src/com/sap/sailing/server/hierarchy/SailingHierarchyOwnershipUpdater.java
| ... | ... | @@ -65,6 +65,9 @@ public class SailingHierarchyOwnershipUpdater { |
| 65 | 65 | private final boolean updateCompetitors; |
| 66 | 66 | private final boolean updateBoats; |
| 67 | 67 | private final Set<QualifiedObjectIdentifier> objectsToUpdateOwnershipsFor; |
| 68 | + private final Set<Event> visitedEvents; |
|
| 69 | + private final Set<LeaderboardGroup> visitedLeaderboardGroups; |
|
| 70 | + private final Set<Leaderboard> visitedLeaderboards; |
|
| 68 | 71 | |
| 69 | 72 | private SailingHierarchyOwnershipUpdater(final RacingEventService service, SecurityService securityService, |
| 70 | 73 | final GroupOwnerUpdateStrategy updateStrategy, final boolean updateCompetitors, final boolean updateBoats) { |
| ... | ... | @@ -74,6 +77,9 @@ public class SailingHierarchyOwnershipUpdater { |
| 74 | 77 | this.updateCompetitors = updateCompetitors; |
| 75 | 78 | this.updateBoats = updateBoats; |
| 76 | 79 | objectsToUpdateOwnershipsFor = new HashSet<>(); |
| 80 | + visitedEvents = new HashSet<>(); |
|
| 81 | + visitedLeaderboardGroups = new HashSet<>(); |
|
| 82 | + visitedLeaderboards = new HashSet<>(); |
|
| 77 | 83 | } |
| 78 | 84 | |
| 79 | 85 | public void updateGroupOwnershipForEventHierarchy(Event event) { |
| ... | ... | @@ -82,48 +88,48 @@ public class SailingHierarchyOwnershipUpdater { |
| 82 | 88 | } |
| 83 | 89 | |
| 84 | 90 | private void updateGroupOwnershipForEventHierarchyInternal(Event event) { |
| 85 | - updateGroupOwner(event.getIdentifier()); |
|
| 86 | - SailingHierarchyWalker.walkFromEvent(event, /* includeLeaderboardGroupsWithOverallLeaderboard */ false, |
|
| 87 | - new EventHierarchyVisitor() { |
|
| 88 | - @Override |
|
| 89 | - public void visit(Leaderboard leaderboard, Set<LeaderboardGroup> leaderboardGroups) { |
|
| 90 | - updateGroupOwnershipForLeaderboardHierarchyInternal(leaderboard); |
|
| 91 | - } |
|
| 92 | - |
|
| 93 | - @Override |
|
| 94 | - public void visit(LeaderboardGroup leaderboardGroup) { |
|
| 95 | - // leaderboard groups with overall leaderboard may be visited if all their leaderboards belong |
|
| 96 | - // to the "event", but the process won't recurse back into "event" as we pass it explicitly as |
|
| 97 | - // an event not to visit |
|
| 98 | - updateGroupOwnershipForLeaderboardGroupHierarchyInternal(leaderboardGroup, /* exclude */ event); |
|
| 99 | - } |
|
| 100 | - }); |
|
| 91 | + if (visitedEvents.add(event)) { |
|
| 92 | + updateGroupOwner(event.getIdentifier()); |
|
| 93 | + SailingHierarchyWalker.walkFromEvent(event, /* includeLeaderboardGroupsWithOverallLeaderboard */ false, |
|
| 94 | + new EventHierarchyVisitor() { |
|
| 95 | + @Override |
|
| 96 | + public void visit(Leaderboard leaderboard, Set<LeaderboardGroup> leaderboardGroups) { |
|
| 97 | + updateGroupOwnershipForLeaderboardHierarchyInternal(leaderboard); |
|
| 98 | + } |
|
| 99 | + |
|
| 100 | + @Override |
|
| 101 | + public void visit(LeaderboardGroup leaderboardGroup) { |
|
| 102 | + // leaderboard groups with overall leaderboard may be visited if all their leaderboards belong |
|
| 103 | + // to the "event", but the process won't recurse back into "event" as we pass it explicitly as |
|
| 104 | + // an event not to visit |
|
| 105 | + updateGroupOwnershipForLeaderboardGroupHierarchyInternal(leaderboardGroup); |
|
| 106 | + } |
|
| 107 | + }); |
|
| 108 | + } |
|
| 101 | 109 | } |
| 102 | 110 | |
| 103 | 111 | public void updateGroupOwnershipForLeaderboardGroupHierarchy(LeaderboardGroup leaderboardGroup) { |
| 104 | - updateGroupOwnershipForLeaderboardGroupHierarchyInternal(leaderboardGroup, /* eventToExclude */ null); |
|
| 112 | + updateGroupOwnershipForLeaderboardGroupHierarchyInternal(leaderboardGroup); |
|
| 105 | 113 | commitChanges(); |
| 106 | 114 | } |
| 107 | 115 | |
| 108 | - private void updateGroupOwnershipForLeaderboardGroupHierarchyInternal(LeaderboardGroup leaderboardGroup, Event eventToExclude) { |
|
| 109 | - updateGroupOwner(leaderboardGroup.getIdentifier()); |
|
| 110 | - SailingHierarchyWalker.walkFromLeaderboardGroup(service, leaderboardGroup, |
|
| 111 | - /* includeEventsIfLeaderboardGroupHasOverallLeaderboard */ true, |
|
| 112 | - new LeaderboardGroupHierarchyVisitor() { |
|
| 113 | - @Override |
|
| 114 | - public void visit(Leaderboard leaderboard) { |
|
| 115 | - updateGroupOwnershipForLeaderboardHierarchyInternal(leaderboard); |
|
| 116 | - } |
|
| 117 | - |
|
| 118 | - @Override |
|
| 119 | - public void visit(Event event) { |
|
| 120 | - if (event != eventToExclude) { |
|
| 121 | - // Only events of LeaderboardGroups with overall leaderboard are visited -> no infinite |
|
| 122 | - // recursion occurs |
|
| 116 | + private void updateGroupOwnershipForLeaderboardGroupHierarchyInternal(LeaderboardGroup leaderboardGroup) { |
|
| 117 | + if (visitedLeaderboardGroups.add(leaderboardGroup)) { |
|
| 118 | + updateGroupOwner(leaderboardGroup.getIdentifier()); |
|
| 119 | + SailingHierarchyWalker.walkFromLeaderboardGroup(service, leaderboardGroup, |
|
| 120 | + /* includeEventsIfLeaderboardGroupHasOverallLeaderboard */ true, |
|
| 121 | + new LeaderboardGroupHierarchyVisitor() { |
|
| 122 | + @Override |
|
| 123 | + public void visit(Leaderboard leaderboard) { |
|
| 124 | + updateGroupOwnershipForLeaderboardHierarchyInternal(leaderboard); |
|
| 125 | + } |
|
| 126 | + |
|
| 127 | + @Override |
|
| 128 | + public void visit(Event event) { |
|
| 123 | 129 | updateGroupOwnershipForEventHierarchyInternal(event); |
| 124 | 130 | } |
| 125 | - } |
|
| 126 | - }); |
|
| 131 | + }); |
|
| 132 | + } |
|
| 127 | 133 | } |
| 128 | 134 | |
| 129 | 135 | public void updateGroupOwnershipForLeaderboardHierarchy(Leaderboard leaderboard) { |
| ... | ... | @@ -132,31 +138,33 @@ public class SailingHierarchyOwnershipUpdater { |
| 132 | 138 | } |
| 133 | 139 | |
| 134 | 140 | private void updateGroupOwnershipForLeaderboardHierarchyInternal(Leaderboard leaderboard) { |
| 135 | - updateGroupOwner(leaderboard.getIdentifier()); |
|
| 136 | - if (leaderboard instanceof RegattaLeaderboard) { |
|
| 137 | - RegattaLeaderboard regattaLeaderboard = (RegattaLeaderboard) leaderboard; |
|
| 138 | - updateGroupOwner(regattaLeaderboard.getRegatta().getIdentifier()); |
|
| 139 | - } |
|
| 140 | - SailingHierarchyWalker.walkFromLeaderboard(leaderboard, new LeaderboardHierarchyVisitor() { |
|
| 141 | - @Override |
|
| 142 | - public void visit(TrackedRace race) { |
|
| 143 | - updateGroupOwner(race.getIdentifier()); |
|
| 141 | + if (visitedLeaderboards.add(leaderboard)) { |
|
| 142 | + updateGroupOwner(leaderboard.getIdentifier()); |
|
| 143 | + if (leaderboard instanceof RegattaLeaderboard) { |
|
| 144 | + RegattaLeaderboard regattaLeaderboard = (RegattaLeaderboard) leaderboard; |
|
| 145 | + updateGroupOwner(regattaLeaderboard.getRegatta().getIdentifier()); |
|
| 144 | 146 | } |
| 145 | - |
|
| 146 | - @Override |
|
| 147 | - public void visit(Boat boat) { |
|
| 148 | - if (updateBoats) { |
|
| 149 | - updateGroupOwner(boat.getIdentifier()); |
|
| 147 | + SailingHierarchyWalker.walkFromLeaderboard(leaderboard, new LeaderboardHierarchyVisitor() { |
|
| 148 | + @Override |
|
| 149 | + public void visit(TrackedRace race) { |
|
| 150 | + updateGroupOwner(race.getIdentifier()); |
|
| 150 | 151 | } |
| 151 | - } |
|
| 152 | - |
|
| 153 | - @Override |
|
| 154 | - public void visit(Competitor competitor) { |
|
| 155 | - if (updateCompetitors) { |
|
| 156 | - updateGroupOwner(competitor.getIdentifier()); |
|
| 152 | + |
|
| 153 | + @Override |
|
| 154 | + public void visit(Boat boat) { |
|
| 155 | + if (updateBoats) { |
|
| 156 | + updateGroupOwner(boat.getIdentifier()); |
|
| 157 | + } |
|
| 157 | 158 | } |
| 158 | - } |
|
| 159 | - }); |
|
| 159 | + |
|
| 160 | + @Override |
|
| 161 | + public void visit(Competitor competitor) { |
|
| 162 | + if (updateCompetitors) { |
|
| 163 | + updateGroupOwner(competitor.getIdentifier()); |
|
| 164 | + } |
|
| 165 | + } |
|
| 166 | + }); |
|
| 167 | + } |
|
| 160 | 168 | } |
| 161 | 169 | |
| 162 | 170 | private void updateGroupOwner(QualifiedObjectIdentifier id) { |