mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-14 16:20:57 +00:00
Merge remote-tracking branch 'origin/master' into mark-rounding-inference
This commit is contained in:
commit
3ee3c00a14
15 files changed
+491
-311
No files matched your search
+23
-3
@@ -6,6 +6,8 @@ import java.util.List;
|
||||
|
||||
import com.sap.sailing.domain.base.CourseArea;
|
||||
import com.sap.sailing.domain.base.Venue;
|
||||
import com.sap.sailing.util.impl.LockUtil;
|
||||
import com.sap.sailing.util.impl.NamedReentrantReadWriteLock;
|
||||
|
||||
public class VenueImpl implements Venue {
|
||||
private static final long serialVersionUID = 6854152040737643290L;
|
||||
@@ -16,25 +18,43 @@ public class VenueImpl implements Venue {
|
||||
* "NATO alphabet" (Alpha, Bravo, Charlie, ...).
|
||||
*/
|
||||
private final List<CourseArea> courseAreas;
|
||||
|
||||
private final NamedReentrantReadWriteLock courseAreasLock;
|
||||
|
||||
public VenueImpl(String name) {
|
||||
this.name = name;
|
||||
courseAreas = new ArrayList<CourseArea>();
|
||||
courseAreasLock = new NamedReentrantReadWriteLock("Course Areas for venue "+name, /* fair */ false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<CourseArea> getCourseAreas() {
|
||||
return Collections.unmodifiableList(courseAreas);
|
||||
LockUtil.lockForRead(courseAreasLock);
|
||||
try {
|
||||
return Collections.unmodifiableList(courseAreas);
|
||||
} finally {
|
||||
LockUtil.unlockAfterRead(courseAreasLock);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCourseArea(CourseArea courseArea) {
|
||||
courseAreas.add(courseArea);
|
||||
LockUtil.lockForWrite(courseAreasLock);
|
||||
try {
|
||||
courseAreas.add(courseArea);
|
||||
} finally {
|
||||
LockUtil.unlockAfterWrite(courseAreasLock);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeCourseArea(CourseArea courseArea) {
|
||||
courseAreas.remove(courseArea);
|
||||
LockUtil.lockForWrite(courseAreasLock);
|
||||
try {
|
||||
courseAreas.remove(courseArea);
|
||||
} finally {
|
||||
LockUtil.unlockAfterWrite(courseAreasLock);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-1
@@ -48,7 +48,7 @@ public class DummyTrackedRegattaRegistry implements TrackedRegattaRegistry {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRaceBeingTracked(RaceDefinition r) {
|
||||
public boolean isRaceBeingTracked(Regatta regattaContext, RaceDefinition r) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -140,7 +140,7 @@ public class LeaderboardOfflineTest extends AbstractLeaderboardTest {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public boolean isRaceBeingTracked(RaceDefinition r) {
|
||||
public boolean isRaceBeingTracked(Regatta regattaContext, RaceDefinition r) {
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
|
||||
+35
-2
@@ -4,12 +4,16 @@ import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sailing.domain.test.measurements.Measurement;
|
||||
import com.sap.sailing.domain.test.measurements.MeasurementCase;
|
||||
import com.sap.sailing.domain.test.measurements.MeasurementXMLFile;
|
||||
import com.sap.sailing.util.impl.LockUtil;
|
||||
import com.sap.sailing.util.impl.NamedReentrantReadWriteLock;
|
||||
|
||||
@@ -52,17 +56,46 @@ public class LockTraceTest {
|
||||
assertFalse(lock.getReaders().contains(Thread.currentThread()));
|
||||
assertEquals(0, lock.getReadHoldCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReentrantWriteLockingWithInBetweenReadLocking() {
|
||||
NamedReentrantReadWriteLock lock = new NamedReentrantReadWriteLock("testReentrantWriteLockingWithInBetweenReadLocking-Lock", /* fair */ false);
|
||||
LockUtil.lockForWrite(lock);
|
||||
assertTrue(lock.getWriter() == Thread.currentThread());
|
||||
LockUtil.lockForRead(lock); // reentrant read while holding write
|
||||
assertTrue(lock.getReaders().contains(Thread.currentThread()));
|
||||
LockUtil.lockForWrite(lock); // reentrant write
|
||||
assertTrue(lock.getWriter() == Thread.currentThread());
|
||||
assertTrue(lock.getReaders().contains(Thread.currentThread()));
|
||||
LockUtil.unlockAfterRead(lock);
|
||||
assertFalse(lock.getReaders().contains(Thread.currentThread()));
|
||||
assertEquals(0, lock.getReadHoldCount());
|
||||
assertTrue(lock.getWriter() == Thread.currentThread());
|
||||
assertFalse(lock.getReaders().contains(Thread.currentThread()));
|
||||
assertEquals(0, lock.getReadHoldCount());
|
||||
LockUtil.unlockAfterWrite(lock);
|
||||
assertTrue(lock.getWriter() == Thread.currentThread());
|
||||
LockUtil.unlockAfterWrite(lock);
|
||||
assertFalse(lock.getWriter() == Thread.currentThread());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLockingPerformance() {
|
||||
public void testLockingPerformance() throws IOException {
|
||||
NamedReentrantReadWriteLock lock = new NamedReentrantReadWriteLock("Lock", /* fair */ true);
|
||||
long start = System.currentTimeMillis();
|
||||
for (int i=0; i<100000; i++) {
|
||||
final int count = 100000;
|
||||
for (int i=0; i<count; i++) {
|
||||
LockUtil.lockForRead(lock);
|
||||
LockUtil.unlockAfterRead(lock);
|
||||
LockUtil.lockForWrite(lock);
|
||||
LockUtil.unlockAfterWrite(lock);
|
||||
}
|
||||
MeasurementXMLFile performanceReport = new MeasurementXMLFile(this.getClass());
|
||||
MeasurementCase performanceReportCase = performanceReport.addCase(getClass().getSimpleName());
|
||||
performanceReportCase.addMeasurement(new Measurement("Obtaining and releasing "+count+" read and write locks in ms",
|
||||
System.currentTimeMillis()-start));
|
||||
performanceReport.write();
|
||||
|
||||
System.out.println("Took "+(System.currentTimeMillis()-start)+"ms");
|
||||
}
|
||||
|
||||
|
||||
+1
-3
@@ -35,11 +35,9 @@ import com.sap.sailing.domain.tracking.impl.GPSFixMovingImpl;
|
||||
public class MarkPassingCalculatorPerformanceTest extends AbstractMockedRaceMarkPassingTest {
|
||||
|
||||
private static LinkedHashMap<String, Long> result = new LinkedHashMap<>();
|
||||
private static String className;
|
||||
|
||||
public MarkPassingCalculatorPerformanceTest() {
|
||||
super();
|
||||
className = getClass().getName();
|
||||
}
|
||||
|
||||
protected Random rnd = new Random();
|
||||
@@ -47,7 +45,7 @@ public class MarkPassingCalculatorPerformanceTest extends AbstractMockedRaceMark
|
||||
|
||||
@AfterClass
|
||||
public static void createXMLFile() throws IOException {
|
||||
MeasurementXMLFile performanceReport = new MeasurementXMLFile("TEST-MarkPassingCaculatorPerformanceTest.xml", "MarkPassingCaculatorPerformanceTest", className);
|
||||
MeasurementXMLFile performanceReport = new MeasurementXMLFile(MarkPassingCalculatorPerformanceTest.class);
|
||||
for (String key : result.keySet()) {
|
||||
MeasurementCase performanceReportCase = performanceReport.addCase(key);
|
||||
performanceReportCase.addMeasurement(new Measurement(key, result.get(key)));
|
||||
|
||||
+4
@@ -27,6 +27,10 @@ public class MeasurementXMLFile {
|
||||
private final Set<MeasurementCase> cases;
|
||||
private final String testClassName;
|
||||
|
||||
public MeasurementXMLFile(Class<?> testClass) {
|
||||
this("TEST-"+testClass.getSimpleName()+".xml", testClass.getSimpleName(), testClass.getName());
|
||||
}
|
||||
|
||||
public MeasurementXMLFile(String reportFileName, String testSuiteName, String testClassName) {
|
||||
this.reportFileName = reportFileName;
|
||||
this.testSuiteName = testSuiteName;
|
||||
|
||||
@@ -21,5 +21,4 @@ public interface RaceDefinition extends Named, WithID {
|
||||
Course getCourse();
|
||||
|
||||
Iterable<Competitor> getCompetitors();
|
||||
|
||||
}
|
||||
+2
-1
@@ -112,7 +112,8 @@ public class DomainFactoryImpl extends SharedDomainFactoryImpl implements Domain
|
||||
// Optional: Getting the places of the race
|
||||
PlacemarkOrderDTO racePlaces = withGeoLocationData ? getRacePlaces(trackedRace) : null;
|
||||
TrackedRaceDTO trackedRaceDTO = createTrackedRaceDTO(trackedRace);
|
||||
RaceDTO raceDTO = new RaceDTO(raceIdentifier, trackedRaceDTO, trackedRegattaRegistry.isRaceBeingTracked(trackedRace.getRace()));
|
||||
RaceDTO raceDTO = new RaceDTO(raceIdentifier, trackedRaceDTO, trackedRegattaRegistry.isRaceBeingTracked(
|
||||
trackedRace.getTrackedRegatta().getRegatta(), trackedRace.getRace()));
|
||||
raceDTO.places = racePlaces;
|
||||
updateRaceDTOWithTrackedRaceData(trackedRace, raceDTO);
|
||||
return raceDTO;
|
||||
|
||||
+1
-1
@@ -44,7 +44,7 @@ public interface TrackedRegattaRegistry {
|
||||
*/
|
||||
Regatta getRememberedRegattaForRace(Serializable raceID);
|
||||
|
||||
boolean isRaceBeingTracked(RaceDefinition r);
|
||||
boolean isRaceBeingTracked(Regatta regattaContext, RaceDefinition r);
|
||||
|
||||
/**
|
||||
* Stops all {@link RaceTracker}s currently tracking <code>race</code>. Note that if the same tracker also may have
|
||||
|
||||
+1
-1
@@ -900,7 +900,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
trackedRaceDTO = getBaseDomainFactory().createTrackedRaceDTO(trackedRace);
|
||||
}
|
||||
RaceWithCompetitorsDTO raceDTO = new RaceWithCompetitorsDTO(raceIdentifier, convertToCompetitorDTOs(r.getCompetitors()),
|
||||
trackedRaceDTO, getService().isRaceBeingTracked(r));
|
||||
trackedRaceDTO, getService().isRaceBeingTracked(regatta, r));
|
||||
if (trackedRace != null) {
|
||||
getBaseDomainFactory().updateRaceDTOWithTrackedRaceData(trackedRace, raceDTO);
|
||||
}
|
||||
|
||||
+14
-13
@@ -15,6 +15,7 @@ import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentSkipListSet;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -50,7 +51,7 @@ public class RaceTrackerStartStopTest {
|
||||
private RacingEventServiceImplMock racingEventService;
|
||||
private Regatta regatta;
|
||||
private BoatClass boatClass;
|
||||
private Set<RaceTracker> raceTrackerSet = new HashSet<RaceTracker>();
|
||||
private ConcurrentSkipListSet<RaceTracker> raceTrackerSet = new ConcurrentSkipListSet<RaceTracker>();
|
||||
|
||||
private RaceDefinition raceDef1;
|
||||
private RaceDefinition raceDef2;
|
||||
@@ -66,10 +67,10 @@ public class RaceTrackerStartStopTest {
|
||||
boatClass = new BoatClassImpl(BOATCLASSNAME, /* typicallyStartsUpwind */ true);
|
||||
regatta = new RegattaImpl(EmptyRaceLogStore.INSTANCE, EVENTNAME, boatClass, /* trackedRegattaRegistry */ null,
|
||||
DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.LOW_POINT), UUID.randomUUID(), null);
|
||||
racingEventService.getEventsByName().put(EVENTNAME, regatta);
|
||||
racingEventService.getRegattasByName().put(EVENTNAME, regatta);
|
||||
TrackedRegatta trackedRegatta1 = racingEventService.getOrCreateTrackedRegatta(regatta);
|
||||
racingEventService.getEventsByNameMap().put(EVENTNAME, regatta);
|
||||
raceTrackerSet = new HashSet<RaceTracker>();
|
||||
racingEventService.getRegattasByName().put(EVENTNAME, regatta);
|
||||
raceTrackerSet = new ConcurrentSkipListSet<RaceTracker>();
|
||||
raceDef1 = new RaceDefinitionImpl(RACENAME1, new CourseImpl("Course1", new ArrayList<Waypoint>()), boatClass, new ArrayList<Competitor>());
|
||||
raceDef2 = new RaceDefinitionImpl(RACENAME2, new CourseImpl("Course2", new ArrayList<Waypoint>()), boatClass, new ArrayList<Competitor>());
|
||||
raceDef3 = new RaceDefinitionImpl(RACENAME3, new CourseImpl("Course3", new ArrayList<Waypoint>()), boatClass, new ArrayList<Competitor>());
|
||||
@@ -100,7 +101,7 @@ public class RaceTrackerStartStopTest {
|
||||
raceTrackerSet.add(raceTracker1);
|
||||
raceTrackerSet.add(raceTracker2);
|
||||
raceTrackerSet.add(raceTracker3);
|
||||
racingEventService.getRaceTrackersByEventMap().put(regatta, raceTrackerSet);
|
||||
racingEventService.getRaceTrackersByRegattaMap().put(regatta, raceTrackerSet);
|
||||
racingEventService.getRaceTrackersByIDMap().put(trackerID1, raceTracker1);
|
||||
racingEventService.getRaceTrackersByIDMap().put(trackerID2, raceTracker2);
|
||||
racingEventService.getRaceTrackersByIDMap().put(trackerID3, raceTracker3);
|
||||
@@ -136,8 +137,8 @@ public class RaceTrackerStartStopTest {
|
||||
assertFalse(racingEventService.getRaceTrackersByIDMap().containsValue(raceTracker3));
|
||||
// The RaceTrakcersByEvent map should contain a tracker with a set of RaceDefinitions, containing the
|
||||
// raceDefinition1
|
||||
assertEquals(1, racingEventService.getRaceTrackersByEventMap().size());
|
||||
Iterator<RaceTracker> raceTrackerIter = racingEventService.getRaceTrackersByEventMap().get(regatta).iterator();
|
||||
assertEquals(1, racingEventService.getRaceTrackersByRegattaMap().size());
|
||||
Iterator<RaceTracker> raceTrackerIter = racingEventService.getRaceTrackersByRegattaMap().get(regatta).iterator();
|
||||
while (raceTrackerIter.hasNext()) {
|
||||
RaceTracker currentTracker = raceTrackerIter.next();
|
||||
assertSame(raceTracker1, currentTracker);
|
||||
@@ -165,9 +166,9 @@ public class RaceTrackerStartStopTest {
|
||||
}
|
||||
assertFalse(foundTrackedRaceForRaceDef2);
|
||||
// The trackers map should still contain the raceTrackers
|
||||
assertTrue(racingEventService.getRaceTrackersByEventMap().get(regatta).contains(raceTracker1));
|
||||
assertTrue(racingEventService.getRaceTrackersByEventMap().get(regatta).contains(raceTracker2));
|
||||
assertTrue(racingEventService.getRaceTrackersByEventMap().get(regatta).contains(raceTracker3));
|
||||
assertTrue(racingEventService.getRaceTrackersByRegattaMap().get(regatta).contains(raceTracker1));
|
||||
assertTrue(racingEventService.getRaceTrackersByRegattaMap().get(regatta).contains(raceTracker2));
|
||||
assertTrue(racingEventService.getRaceTrackersByRegattaMap().get(regatta).contains(raceTracker3));
|
||||
// The raceTrackerMap should still contain the raceTrackers. These raceTracker should not contain the raceDefinition raceDef2 anymore
|
||||
assertTrue(racingEventService.getRaceTrackersByIDMap().containsValue(raceTracker1));
|
||||
assertTrue(racingEventService.getRaceTrackersByIDMap().containsValue(raceTracker2));
|
||||
@@ -193,9 +194,9 @@ public class RaceTrackerStartStopTest {
|
||||
racingEventService.removeRace(regatta, raceDef1);
|
||||
racingEventService.removeRace(regatta, raceDef2);
|
||||
// The event map should still contain the raceTrackers except of raceTracker1 and raceTracker2
|
||||
assertFalse(racingEventService.getRaceTrackersByEventMap().get(regatta).contains(raceTracker1));
|
||||
assertFalse(racingEventService.getRaceTrackersByEventMap().get(regatta).contains(raceTracker2));
|
||||
assertTrue(racingEventService.getRaceTrackersByEventMap().get(regatta).contains(raceTracker3));
|
||||
assertFalse(racingEventService.getRaceTrackersByRegattaMap().get(regatta).contains(raceTracker1));
|
||||
assertFalse(racingEventService.getRaceTrackersByRegattaMap().get(regatta).contains(raceTracker2));
|
||||
assertTrue(racingEventService.getRaceTrackersByRegattaMap().get(regatta).contains(raceTracker3));
|
||||
// The RaceTrackerByID map should still contain raceTracker3, but not raceTracker1 and raceTracker2 anymore
|
||||
assertFalse(racingEventService.getRaceTrackersByIDMap().containsValue(raceTracker1));
|
||||
assertFalse(racingEventService.getRaceTrackersByIDMap().containsValue(raceTracker2));
|
||||
|
||||
+3
-7
@@ -1,7 +1,7 @@
|
||||
package com.sap.sailing.server.test;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentSkipListSet;
|
||||
|
||||
import com.sap.sailing.domain.base.Regatta;
|
||||
import com.sap.sailing.domain.common.impl.DataImportProgressImpl;
|
||||
@@ -22,11 +22,7 @@ public class RacingEventServiceImplMock extends RacingEventServiceImpl {
|
||||
lock.addProgress(dataImportProgressImpl.getOperationId(), dataImportProgressImpl);
|
||||
}
|
||||
|
||||
public Map<String, Regatta> getEventsByNameMap() {
|
||||
return regattasByName;
|
||||
}
|
||||
|
||||
public Map<Regatta, Set<RaceTracker>> getRaceTrackersByEventMap() {
|
||||
public Map<Regatta, ConcurrentSkipListSet<RaceTracker>> getRaceTrackersByRegattaMap() {
|
||||
return raceTrackersByRegatta;
|
||||
}
|
||||
|
||||
@@ -34,7 +30,7 @@ public class RacingEventServiceImplMock extends RacingEventServiceImpl {
|
||||
return raceTrackersByID;
|
||||
}
|
||||
|
||||
public Map<String, Regatta> getEventsByName() {
|
||||
public Map<String, Regatta> getRegattasByName() {
|
||||
return regattasByName;
|
||||
}
|
||||
|
||||
|
||||
@@ -269,6 +269,9 @@ class MediaLibrary {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a non-live copy of the media tracks
|
||||
*/
|
||||
Collection<MediaTrack> allTracks() {
|
||||
readLock.lock();
|
||||
try {
|
||||
|
||||
+392
-277
File diff suppressed because it is too large.
Load diff
+10
@@ -4,6 +4,16 @@ Our default Hudson runs on http://hudson.sapsailing.com. If you need access, ple
|
||||
|
||||
It is good practice to set up a new Hudson job for major branches that require solid testing before being merged into the master branch. The entry page at http://hudson.sapsailing.com explains how to do this. It basically comes down to copying a template job and adjusting the branch name. As easy as that :-)
|
||||
|
||||
## Collecting measurements using Hudson/Jenkins
|
||||
|
||||
If you have a test case that measures something, such as performance or level of fulfillment or any other numeric measure, you can have Hudson/Jenkins plot it. In your test case, use the class `com.sap.sailing.domain.test.measurements.MeasurementXMLFile` and add performance cases to which you add measurements, e.g., as follows:
|
||||
<pre>
|
||||
MeasurementXMLFile performanceReport = new MeasurementXMLFile(getClass());
|
||||
MeasurementCase performanceReportCase = performanceReport.addCase(getClass().getSimpleName());
|
||||
performanceReportCase.addMeasurement(new Measurement("My Measurement", theNumberIMeasured));
|
||||
performanceReport.write();
|
||||
</pre>
|
||||
|
||||
## In case you'd like to set up your own Hudson/Jenkins
|
||||
|
||||
Initially we had trouble with Jenkins and the GIT plug-in. However, https://issues.jenkins-ci.org/browse/JENKINS-13381?focusedCommentId=196689&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-196689 explains that installing the Credentials plugin into Jenkins may help. Basically, what is needed over and above a plain Jenkins installation are the following plug-ins:
|
||||
|
||||
Reference in new issue
Block a user