4f5f36f7531b4c09a58371b7f76ad41f91134459
java/com.sap.sailing.domain/src/com/sap/sailing/domain/markpassingcalculation/MarkPassingCalculator.java
| ... | ... | @@ -589,7 +589,7 @@ public class MarkPassingCalculator { |
| 589 | 589 | // creation matches that of this mark passing calculator's race; load instead of compute |
| 590 | 590 | updateMarkPassingsFromRegistry(); |
| 591 | 591 | queue.clear(); |
| 592 | - stop(); // ensures an end marker is written to queue to the queue.take() call in Listen.run() will always get unblocked after the queue.clear() above |
|
| 592 | + stop(); // ensures an end marker is written to queue so the queue.take() call in Listen.run() will always get unblocked after the queue.clear() above |
|
| 593 | 593 | suspended = false; |
| 594 | 594 | } else { |
| 595 | 595 | suspended = false; |
java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/core/WindowManager.java
| ... | ... | @@ -5,6 +5,7 @@ import java.util.Set; |
| 5 | 5 | import java.util.function.BiConsumer; |
| 6 | 6 | import java.util.function.Consumer; |
| 7 | 7 | import java.util.function.Supplier; |
| 8 | +import java.util.logging.Logger; |
|
| 8 | 9 | |
| 9 | 10 | import org.openqa.selenium.Dimension; |
| 10 | 11 | import org.openqa.selenium.JavascriptExecutor; |
| ... | ... | @@ -21,6 +22,8 @@ import org.openqa.selenium.support.ui.WebDriverWait; |
| 21 | 22 | * Riccardo Nimser (D049941) |
| 22 | 23 | */ |
| 23 | 24 | public class WindowManager { |
| 25 | + private static final Logger logger = Logger.getLogger(WindowManager.class.getName()); |
|
| 26 | + |
|
| 24 | 27 | private WebDriverWindow defaultWindow; |
| 25 | 28 | private final Set<WebDriverWindow> allWindows = new HashSet<>(); |
| 26 | 29 | private WebDriver driver; |
| ... | ... | @@ -108,12 +111,18 @@ public class WindowManager { |
| 108 | 111 | } |
| 109 | 112 | |
| 110 | 113 | private boolean isDriverAlive(WebDriver driver) { |
| 111 | - try { |
|
| 112 | - driver.getWindowHandles(); |
|
| 113 | - return true; |
|
| 114 | - } catch (NoSuchSessionException | SessionNotCreatedException e) { |
|
| 115 | - return false; |
|
| 114 | + boolean result; |
|
| 115 | + if (driver == null) { |
|
| 116 | + result = false; |
|
| 117 | + } else { |
|
| 118 | + try { |
|
| 119 | + driver.getWindowHandles(); |
|
| 120 | + result = true; |
|
| 121 | + } catch (NoSuchSessionException | SessionNotCreatedException e) { |
|
| 122 | + result = false; |
|
| 123 | + } |
|
| 116 | 124 | } |
| 125 | + return result; |
|
| 117 | 126 | } |
| 118 | 127 | |
| 119 | 128 | private void setWindowMaximized(WebDriver driver) { |
| ... | ... | @@ -137,6 +146,16 @@ public class WindowManager { |
| 137 | 146 | |
| 138 | 147 | public void closeAllWindows() { |
| 139 | 148 | forEachOpenedWindow(WebDriverWindow::close); |
| 149 | + if (driver != null) { |
|
| 150 | + try { |
|
| 151 | + driver.close(); |
|
| 152 | + driver.quit(); |
|
| 153 | + } catch (org.openqa.selenium.NoSuchSessionException e) { |
|
| 154 | + logger.warning("The Selenium driver seems to have already been closed"); |
|
| 155 | + // Already closed — ignore |
|
| 156 | + } |
|
| 157 | + driver = null; |
|
| 158 | + } |
|
| 140 | 159 | } |
| 141 | 160 | |
| 142 | 161 | private class ManagedWebDriverWindow extends WebDriverWindow { |
java/com.sap.sailing.server.trackfiles.test/src/com/sap/sailing/server/trackfiles/test/DynamicTrackedRaceWithMarkPassingCalculator.java
| ... | ... | @@ -0,0 +1,28 @@ |
| 1 | +package com.sap.sailing.server.trackfiles.test; |
|
| 2 | + |
|
| 3 | +import com.sap.sailing.domain.base.RaceDefinition; |
|
| 4 | +import com.sap.sailing.domain.base.Sideline; |
|
| 5 | +import com.sap.sailing.domain.markpassingcalculation.MarkPassingCalculator; |
|
| 6 | +import com.sap.sailing.domain.markpassinghash.MarkPassingRaceFingerprintRegistry; |
|
| 7 | +import com.sap.sailing.domain.racelog.RaceLogAndTrackedRaceResolver; |
|
| 8 | +import com.sap.sailing.domain.ranking.RankingMetricConstructor; |
|
| 9 | +import com.sap.sailing.domain.shared.tracking.TrackingConnectorInfo; |
|
| 10 | +import com.sap.sailing.domain.tracking.TrackedRegatta; |
|
| 11 | +import com.sap.sailing.domain.tracking.WindStore; |
|
| 12 | +import com.sap.sailing.domain.tracking.impl.DynamicTrackedRaceImpl; |
|
| 13 | + |
|
| 14 | +public class DynamicTrackedRaceWithMarkPassingCalculator extends DynamicTrackedRaceImpl { |
|
| 15 | + private static final long serialVersionUID = -8076705893930566222L; |
|
| 16 | + |
|
| 17 | + public DynamicTrackedRaceWithMarkPassingCalculator(TrackedRegatta trackedRegatta, RaceDefinition race, Iterable<Sideline> sidelines, |
|
| 18 | + WindStore windStore, long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, |
|
| 19 | + long millisecondsOverWhichToAverageSpeed, boolean useInternalMarkPassingAlgorithm, |
|
| 20 | + RankingMetricConstructor rankingMetricConstructor, RaceLogAndTrackedRaceResolver raceLogResolver, TrackingConnectorInfo trackingConnectorInfo, |
|
| 21 | + MarkPassingRaceFingerprintRegistry markPassingRaceFingerprintRegistry) { |
|
| 22 | + super(trackedRegatta, race, sidelines, windStore, delayToLiveInMillis, millisecondsOverWhichToAverageWind, millisecondsOverWhichToAverageSpeed, useInternalMarkPassingAlgorithm, rankingMetricConstructor, raceLogResolver, trackingConnectorInfo, markPassingRaceFingerprintRegistry); |
|
| 23 | + } |
|
| 24 | + |
|
| 25 | + public MarkPassingCalculator getMarkPassingCalculator() { |
|
| 26 | + return markPassingCalculator; |
|
| 27 | + } |
|
| 28 | +} |
java/com.sap.sailing.server.trackfiles.test/src/com/sap/sailing/server/trackfiles/test/JumpyTrackSmootheningTest.java
| ... | ... | @@ -68,7 +68,6 @@ import com.sap.sailing.domain.tracking.MarkPassing; |
| 68 | 68 | import com.sap.sailing.domain.tracking.TrackedRegatta; |
| 69 | 69 | import com.sap.sailing.domain.tracking.WindTrack; |
| 70 | 70 | import com.sap.sailing.domain.tracking.impl.DynamicGPSFixMovingTrackImpl; |
| 71 | -import com.sap.sailing.domain.tracking.impl.DynamicTrackedRaceImpl; |
|
| 72 | 71 | import com.sap.sailing.domain.tracking.impl.DynamicTrackedRegattaImpl; |
| 73 | 72 | import com.sap.sailing.domain.tracking.impl.EmptyWindStore; |
| 74 | 73 | import com.sap.sailing.domain.tracking.impl.OutlierFilter; |
| ... | ... | @@ -197,7 +196,7 @@ public class JumpyTrackSmootheningTest { |
| 197 | 196 | durationForOriginalTrack = startedAt.until(doneAt); |
| 198 | 197 | logger.info("Duration for computing mark passings with original track: "+durationForOriginalTrack); |
| 199 | 198 | assertNotNull(markPassings); |
| 200 | - assertEquals(13, markPassings.size()); |
|
| 199 | + assertEquals(5, markPassings.size()); // there are fewer mark passings with the spikes still included |
|
| 201 | 200 | } |
| 202 | 201 | assertTrue(durationForAdjustedTrack.times(2).compareTo(durationForOriginalTrack) < 0, |
| 203 | 202 | "Expected duration for mark passing analysis on adjusted track to be at least two times less than for original track: "+ |
| ... | ... | @@ -238,9 +237,9 @@ public class JumpyTrackSmootheningTest { |
| 238 | 237 | * its calculation. As a result, a test may determine the impact filtering / adjusting the track may have on the |
| 239 | 238 | * mark passing analysis. |
| 240 | 239 | */ |
| 241 | - private DynamicTrackedRace createRace(DynamicGPSFixTrack<Competitor, GPSFixMoving> competitorTrack) throws PatchFailedException, ParseException { |
|
| 240 | + private DynamicTrackedRace createRace(DynamicGPSFixTrack<Competitor, GPSFixMoving> competitorTrack) throws PatchFailedException, ParseException, InterruptedException { |
|
| 242 | 241 | final Competitor gallagherZelenka = competitorTrack.getTrackedItem(); |
| 243 | - final DynamicTrackedRace trackedRace = createTrackedRace("Oak cliff DH Distance Race", "R1", BoatClassMasterdata.MELGES_24, gallagherZelenka); |
|
| 242 | + final DynamicTrackedRaceWithMarkPassingCalculator trackedRace = createTrackedRace("Oak cliff DH Distance Race", "R1", BoatClassMasterdata.MELGES_24, gallagherZelenka); |
|
| 244 | 243 | final Series defaultSeries = trackedRace.getTrackedRegatta().getRegatta().getSeries().iterator().next(); |
| 245 | 244 | final Fleet defaultFleet = defaultSeries.getFleets().iterator().next(); |
| 246 | 245 | final RaceColumnInSeries r1RaceColumn = defaultSeries.getRaceColumns().iterator().next(); |
| ... | ... | @@ -291,7 +290,6 @@ public class JumpyTrackSmootheningTest { |
| 291 | 290 | addFixedMarkPassingToRaceLog("2020-10-14T18:21:38Z", gallagherZelenka, 4, raceLog); |
| 292 | 291 | trackedRace.setStatus(new TrackedRaceStatusImpl(TrackedRaceStatusEnum.LOADING, 0.0)); // suspends mark passing calculator |
| 293 | 292 | final DynamicGPSFixTrack<Competitor, GPSFixMoving> competitorTrackInRace = trackedRace.getTrack(gallagherZelenka); |
| 294 | - // TODO switch race into suspended mode to avoid updates during mass fix insertion: |
|
| 295 | 293 | competitorTrack.lockForRead(); |
| 296 | 294 | try { |
| 297 | 295 | for (final GPSFixMoving fix : competitorTrack.getRawFixes()) { |
| ... | ... | @@ -301,15 +299,11 @@ public class JumpyTrackSmootheningTest { |
| 301 | 299 | competitorTrack.unlockAfterRead(); |
| 302 | 300 | } |
| 303 | 301 | trackedRace.setStatus(new TrackedRaceStatusImpl(TrackedRaceStatusEnum.TRACKING, 1.0)); // resumes mark passing calculator |
| 304 | - // FIXME is it possible that MarkPassingCalculator.Listen has applied only a subset of the changes from its queue when this method returns? |
|
| 305 | - // It scoops up a few events from the queue under the MPC write lock and collects the changes in various collections, but doesn't re-calculate while suspended; |
|
| 306 | - // When the lock is released prior to fetching the next set of events from the queue, the test case calling this method may call getMarkPassings(..., true) |
|
| 307 | - // and obtain the read lock, keeping the Listen thread from applying the next round of updates. Yes, the getMarkPassings(...) call may return something, |
|
| 308 | - // but that may be the result of only applying a subset of the changes, with other changes still in the queue... |
|
| 302 | + trackedRace.getMarkPassingCalculator().waitUntilStopped(/* timeout in millis */ Duration.ONE_MINUTE.times(15).asMillis()); |
|
| 309 | 303 | return trackedRace; |
| 310 | 304 | } |
| 311 | 305 | |
| 312 | - private DynamicTrackedRace createTrackedRace(String regattaName, String name, BoatClassMasterdata boatClassMasterData, Competitor gallagherZelenka) { |
|
| 306 | + private DynamicTrackedRaceWithMarkPassingCalculator createTrackedRace(String regattaName, String name, BoatClassMasterdata boatClassMasterData, Competitor gallagherZelenka) { |
|
| 313 | 307 | final BoatClassImpl boatClass = new BoatClassImpl(boatClassMasterData); |
| 314 | 308 | final TrackedRegatta trackedRegatta = new DynamicTrackedRegattaImpl(new RegattaImpl(regattaName, boatClass, |
| 315 | 309 | /* canBoatsOfCompetitorsChangePerRace */ false, /* competitorRegistrationType */ CompetitorRegistrationType.CLOSED, |
| ... | ... | @@ -321,7 +315,7 @@ public class JumpyTrackSmootheningTest { |
| 321 | 315 | final Map<Competitor, Boat> competitorsAndTheirBoats = Util.<Competitor, Boat>mapBuilder().put(gallagherZelenka, boat).build(); |
| 322 | 316 | final Course course = new CourseImpl("R1 Course", Collections.emptySet()); |
| 323 | 317 | final RaceDefinition race = new RaceDefinitionImpl(name, course, boatClass, competitorsAndTheirBoats, UUID.randomUUID()); |
| 324 | - return new DynamicTrackedRaceImpl(trackedRegatta, race, /* sidelines */ Collections.emptySet(), new EmptyWindStore(), /* delayToLiveInMillis */ 1000, |
|
| 318 | + return new DynamicTrackedRaceWithMarkPassingCalculator(trackedRegatta, race, /* sidelines */ Collections.emptySet(), new EmptyWindStore(), /* delayToLiveInMillis */ 1000, |
|
| 325 | 319 | WindTrack.DEFAULT_MILLISECONDS_OVER_WHICH_TO_AVERAGE_WIND, /* time over which to average speed: */ boatClass.getApproximateManeuverDurationInMilliseconds(), |
| 326 | 320 | /* useInternalMarkPassingAlgorithm */ true, OneDesignRankingMetric::new, mock(RaceLogAndTrackedRaceResolver.class), /* trackingConnectorInfo */ null, /* markPassingRaceFingerprintRegistry */ null); |
| 327 | 321 | } |