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
}