diff --git a/.gitignore b/.gitignore
index eb2b61ea..df9656e1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -70,6 +70,7 @@ buildNumber.properties
#custom exclusions
/uf-sdk-logs/
+**/uf-sdk-logs/
UFSdkConfiguration.properties
application.yml
@@ -77,4 +78,3 @@ application.yml
# logs
*.log.gz
-*.log
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index aed91f9c..15aa11d9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,8 @@
### Unified Feed SDK 2.x changelog
+**2.0.61 (2023-07-20)**
+* Stages can be of SprintRace type
+
**2.0.60.0 (2023-05-17)**
* CustomBetManager respects ExceptionHandlingStrategy for all non-argument-validating exceptions
* CustomBetManager now throws CommunicationException on API failures
diff --git a/pom.xml b/pom.xml
index ce896e3e..18a67a63 100644
--- a/pom.xml
+++ b/pom.xml
@@ -8,7 +8,7 @@
4.0.0
com.sportradar.unifiedodds.sdk
unified-feed-sdk-parent
- 2.0.60
+ 2.0.61
pom
Unified Odds Feed SDK - parent
UnifiedFeed SDK is a client library that enables easier integration with the Betradar XML feeds. SDK exposes XML feed service interface in a more user-friendly way and isolates the client from having to do XML feed parsing, proper connection handling, error recovery, event queuing, data caching and dispatching. It also makes a client solution more stable and robust when it comes to feed handling, especially with the release of new and updated XML feed versions.
diff --git a/sdk-core/pom.xml b/sdk-core/pom.xml
index a5b7d7b1..fc2dbba3 100644
--- a/sdk-core/pom.xml
+++ b/sdk-core/pom.xml
@@ -8,7 +8,7 @@
com.sportradar.unifiedodds.sdk
unified-feed-sdk
- 2.0.60
+ 2.0.61
Unified Odds Feed SDK
diff --git a/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/caching/exportable/ExportableRaceStageCI.java b/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/caching/exportable/ExportableRaceStageCI.java
index fabfac02..798eeb22 100644
--- a/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/caching/exportable/ExportableRaceStageCI.java
+++ b/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/caching/exportable/ExportableRaceStageCI.java
@@ -12,7 +12,7 @@
import java.util.Locale;
import java.util.Map;
-@SuppressWarnings({ "AbbreviationAsWordInName", "HiddenField", "ParameterNumber" })
+@SuppressWarnings({ "HiddenField", "ParameterNumber", "AbbreviationAsWordInName" })
public class ExportableRaceStageCI extends ExportableStageCI {
private Locale defaultLocale;
diff --git a/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/entities/StageType.java b/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/entities/StageType.java
index 4ac0304a..00da287d 100644
--- a/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/entities/StageType.java
+++ b/sdk-core/src/main/java/com/sportradar/unifiedodds/sdk/entities/StageType.java
@@ -24,6 +24,7 @@ public enum StageType {
Qualifying,
QualifyingPart,
Lap,
+ SprintRace,
Run;
public static StageType mapFromApiValue(String str) {
@@ -64,6 +65,8 @@ public static StageType mapFromApiValue(String str) {
return Lap;
case "run":
return Run;
+ case "sprint_race":
+ return SprintRace;
default:
return null;
}
diff --git a/sdk-core/src/test/java/com/sportradar/unifiedodds/sdk/ErrorHandlingStrategiesTest.java b/sdk-core/src/test/java/com/sportradar/unifiedodds/sdk/ErrorHandlingStrategiesTest.java
new file mode 100644
index 00000000..67da91ca
--- /dev/null
+++ b/sdk-core/src/test/java/com/sportradar/unifiedodds/sdk/ErrorHandlingStrategiesTest.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) Sportradar AG. See LICENSE for full license governing this code
+ */
+package com.sportradar.unifiedodds.sdk;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.junit.Test;
+
+public class ErrorHandlingStrategiesTest {
+
+ private final int sampleSize = 100;
+ private List strategies = Stream
+ .generate(() -> ExceptionHandlingStrategies.anyErrorHandlingStrategy())
+ .limit(sampleSize)
+ .distinct()
+ .collect(Collectors.toList());
+
+ @Test
+ public void anyStrategyGeneratesNotAlwaysTheSameStrategy() {
+ assertThat(strategies).hasSizeGreaterThan(1);
+ }
+
+ @Test
+ public void anyStrategyDoesNotGenerateNulls() {
+ assertThat(strategies).doesNotContainNull();
+ }
+}
diff --git a/sdk-core/src/test/java/com/sportradar/unifiedodds/sdk/ExceptionHandlingStrategies.java b/sdk-core/src/test/java/com/sportradar/unifiedodds/sdk/ExceptionHandlingStrategies.java
new file mode 100644
index 00000000..53d6d62f
--- /dev/null
+++ b/sdk-core/src/test/java/com/sportradar/unifiedodds/sdk/ExceptionHandlingStrategies.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) Sportradar AG. See LICENSE for full license governing this code
+ */
+package com.sportradar.unifiedodds.sdk;
+
+import static com.sportradar.unifiedodds.sdk.ExceptionHandlingStrategy.Catch;
+import static com.sportradar.unifiedodds.sdk.ExceptionHandlingStrategy.Throw;
+
+import java.util.Arrays;
+import java.util.Random;
+import lombok.val;
+
+public class ExceptionHandlingStrategies {
+
+ private static Random random = new Random();
+
+ private ExceptionHandlingStrategies() {}
+
+ public static ExceptionHandlingStrategy anyErrorHandlingStrategy() {
+ val strategiesPool = Arrays.asList(Throw, Catch);
+ return strategiesPool.get(random.nextInt(strategiesPool.size()));
+ }
+}
diff --git a/sdk-core/src/test/java/com/sportradar/unifiedodds/sdk/caching/impl/DataRouterManagers.java b/sdk-core/src/test/java/com/sportradar/unifiedodds/sdk/caching/impl/DataRouterManagers.java
new file mode 100644
index 00000000..7cfb84d3
--- /dev/null
+++ b/sdk-core/src/test/java/com/sportradar/unifiedodds/sdk/caching/impl/DataRouterManagers.java
@@ -0,0 +1,15 @@
+/*
+ * Copyright (C) Sportradar AG. See LICENSE for full license governing this code
+ */
+package com.sportradar.unifiedodds.sdk.caching.impl;
+
+import com.sportradar.unifiedodds.sdk.caching.DataRouterManager;
+
+public class DataRouterManagers {
+
+ private DataRouterManagers() {}
+
+ public static DataRouterManager any() {
+ return new NoOpDataRouterManager();
+ }
+}
diff --git a/sdk-core/src/test/java/com/sportradar/unifiedodds/sdk/caching/impl/NoOpDataRouterManager.java b/sdk-core/src/test/java/com/sportradar/unifiedodds/sdk/caching/impl/NoOpDataRouterManager.java
new file mode 100644
index 00000000..51f07f03
--- /dev/null
+++ b/sdk-core/src/test/java/com/sportradar/unifiedodds/sdk/caching/impl/NoOpDataRouterManager.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) Sportradar AG. See LICENSE for full license governing this code
+ */
+package com.sportradar.unifiedodds.sdk.caching.impl;
+
+import com.sportradar.uf.sportsapi.datamodel.SAPIMatchTimelineEndpoint;
+import com.sportradar.unifiedodds.sdk.caching.CacheItem;
+import com.sportradar.unifiedodds.sdk.caching.DataRouterManager;
+import com.sportradar.unifiedodds.sdk.custombetentities.AvailableSelections;
+import com.sportradar.unifiedodds.sdk.custombetentities.Calculation;
+import com.sportradar.unifiedodds.sdk.custombetentities.CalculationFilter;
+import com.sportradar.unifiedodds.sdk.custombetentities.Selection;
+import com.sportradar.unifiedodds.sdk.entities.FixtureChange;
+import com.sportradar.unifiedodds.sdk.entities.PeriodStatus;
+import com.sportradar.unifiedodds.sdk.entities.ResultChange;
+import com.sportradar.unifiedodds.sdk.exceptions.internal.CommunicationException;
+import com.sportradar.utils.URN;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+
+public class NoOpDataRouterManager implements DataRouterManager {
+
+ @Override
+ public void requestSummaryEndpoint(Locale locale, URN id, CacheItem requester)
+ throws CommunicationException {}
+
+ @Override
+ public void requestFixtureEndpoint(Locale locale, URN id, boolean useCachedProvider, CacheItem requester)
+ throws CommunicationException {}
+
+ @Override
+ public void requestDrawSummary(Locale locale, URN id, CacheItem requester)
+ throws CommunicationException {}
+
+ @Override
+ public void requestDrawFixture(Locale locale, URN id, CacheItem requester)
+ throws CommunicationException {}
+
+ @Override
+ public void requestAllTournamentsForAllSportsEndpoint(Locale locale) throws CommunicationException {}
+
+ @Override
+ public void requestAllSportsEndpoint(Locale locale) throws CommunicationException {}
+
+ @Override
+ public List requestAllLotteriesEndpoint(Locale locale, Boolean requireResult)
+ throws CommunicationException {
+ return null;
+ }
+
+ @Override
+ public List requestEventsFor(Locale locale, URN tournamentId) throws CommunicationException {
+ return null;
+ }
+
+ @Override
+ public List requestEventsFor(Locale locale, Date date) throws CommunicationException {
+ return null;
+ }
+
+ @Override
+ public List requestLotterySchedule(Locale locale, URN lotteryId, CacheItem requester)
+ throws CommunicationException {
+ return null;
+ }
+
+ @Override
+ public void requestPlayerProfileEndpoint(Locale locale, URN id, CacheItem requester)
+ throws CommunicationException {}
+
+ @Override
+ public void requestCompetitorEndpoint(Locale locale, URN id, CacheItem requester)
+ throws CommunicationException {}
+
+ @Override
+ public void requestSimpleTeamEndpoint(Locale locale, URN id, CacheItem requester)
+ throws CommunicationException {}
+
+ @Override
+ public List requestSeasonsFor(Locale locale, URN tournamentId) throws CommunicationException {
+ return null;
+ }
+
+ @Override
+ public SAPIMatchTimelineEndpoint requestEventTimelineEndpoint(Locale locale, URN id, CacheItem requester)
+ throws CommunicationException {
+ return null;
+ }
+
+ @Override
+ public void requestSportCategoriesEndpoint(Locale locale, URN id, CacheItem requester)
+ throws CommunicationException {}
+
+ @Override
+ public AvailableSelections requestAvailableSelections(URN id) throws CommunicationException {
+ return null;
+ }
+
+ @Override
+ public Calculation requestCalculateProbability(List selections) throws CommunicationException {
+ return null;
+ }
+
+ @Override
+ public CalculationFilter requestCalculateProbabilityFilter(List selections)
+ throws CommunicationException {
+ return null;
+ }
+
+ @Override
+ public List requestFixtureChanges(Date after, URN sportId, Locale locale)
+ throws CommunicationException {
+ return null;
+ }
+
+ @Override
+ public List requestResultChanges(Date after, URN sportId, Locale locale)
+ throws CommunicationException {
+ return null;
+ }
+
+ @Override
+ public List requestListSportEvents(Locale locale, int startIndex, int limit)
+ throws CommunicationException {
+ return null;
+ }
+
+ @Override
+ public List requestAvailableTournamentsFor(Locale locale, URN sportId)
+ throws CommunicationException {
+ return null;
+ }
+
+ @Override
+ public List requestPeriodSummary(
+ URN id,
+ Locale locale,
+ List competitorIds,
+ List periods
+ ) throws CommunicationException {
+ return null;
+ }
+
+ @Override
+ public void close() {}
+}
diff --git a/sdk-core/src/test/java/com/sportradar/unifiedodds/sdk/caching/impl/ci/RaceStageCiImplStageTypeTest.java b/sdk-core/src/test/java/com/sportradar/unifiedodds/sdk/caching/impl/ci/RaceStageCiImplStageTypeTest.java
new file mode 100644
index 00000000..cbddf0d0
--- /dev/null
+++ b/sdk-core/src/test/java/com/sportradar/unifiedodds/sdk/caching/impl/ci/RaceStageCiImplStageTypeTest.java
@@ -0,0 +1,513 @@
+/*
+ * Copyright (C) Sportradar AG. See LICENSE for full license governing this code
+ */
+package com.sportradar.unifiedodds.sdk.caching.impl.ci;
+
+import static com.sportradar.unifiedodds.sdk.ExceptionHandlingStrategy.Catch;
+import static com.sportradar.unifiedodds.sdk.ExceptionHandlingStrategy.Throw;
+import static com.sportradar.unifiedodds.sdk.caching.impl.ci.RaceStageCiToMergeTo.into;
+import static com.sportradar.unifiedodds.sdk.caching.impl.ci.RaceStageCis.exportSerializeAndUseConstructorToReimport;
+import static com.sportradar.unifiedodds.sdk.caching.impl.ci.RaceStageCis.usingConstructor;
+import static com.sportradar.unifiedodds.sdk.entities.StageType.SprintRace;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.Mockito.*;
+
+import com.sportradar.uf.sportsapi.datamodel.*;
+import com.sportradar.unifiedodds.sdk.ExceptionHandlingStrategy;
+import com.sportradar.unifiedodds.sdk.caching.DataRouterManager;
+import com.sportradar.unifiedodds.sdk.exceptions.internal.CommunicationException;
+import com.sportradar.unifiedodds.sdk.testutil.javautil.Languages;
+import junitparams.JUnitParamsRunner;
+import junitparams.Parameters;
+import lombok.val;
+import org.junit.Test;
+import org.junit.experimental.runners.Enclosed;
+import org.junit.runner.RunWith;
+import org.mockito.stubbing.Stubber;
+
+@RunWith(Enclosed.class)
+public class RaceStageCiImplStageTypeTest {
+
+ private static final String SAPI_SPRINT_RACE = "sprint_race";
+
+ private static SAPIStageSummaryEndpoint stageSummaryOfType(String type) {
+ val stageSummary = new SAPIStageSummaryEndpoint();
+ SAPISportEvent sportEvent = new SAPISportEvent();
+ sportEvent.setStageType(type);
+ stageSummary.setSportEvent(sportEvent);
+ return stageSummary;
+ }
+
+ public static class WhenStageTypeIsProvidedOnConstruction {
+
+ @Test
+ public void fromSportEventItPreservesStageType() {
+ SAPISportEvent stage = new SAPISportEvent();
+ stage.setStageType(SAPI_SPRINT_RACE);
+ val raceStage = usingConstructor().constructFrom(stage);
+
+ assertThat(raceStage.getStageType()).isEqualTo(SprintRace);
+ }
+
+ @Test
+ public void fromFixtureItPreserveStageType() {
+ val stage = new SAPIFixture();
+ stage.setStageType(SAPI_SPRINT_RACE);
+ val raceStage = usingConstructor().constructFrom(stage);
+
+ assertThat(raceStage.getStageType()).isEqualTo(SprintRace);
+ }
+
+ @Test
+ public void fromStageSummaryItPreserveStageType() {
+ val stage = new SAPIStageSummaryEndpoint();
+ SAPISportEvent stage1 = new SAPISportEvent();
+ stage1.setStageType(SAPI_SPRINT_RACE);
+ stage.setSportEvent(stage1);
+ val raceStage = usingConstructor().constructFrom(stage);
+
+ assertThat(raceStage.getStageType()).isEqualTo(SprintRace);
+ }
+
+ @Test
+ public void fromChildSportEventItPreserveStageType() {
+ val stage = new SAPISportEventChildren.SAPISportEvent();
+ stage.setStageType(SAPI_SPRINT_RACE);
+ val raceStage = usingConstructor().constructFrom(stage);
+
+ assertThat(raceStage.getStageType()).isEqualTo(SprintRace);
+ }
+
+ @Test
+ public void fromParentStageItPreserveStageType() {
+ val sprintStage = new SAPIParentStage();
+ sprintStage.setStageType(SAPI_SPRINT_RACE);
+ val raceStage = usingConstructor().constructFrom(sprintStage);
+
+ assertThat(raceStage.getStageType()).isEqualTo(SprintRace);
+ }
+
+ @Test
+ public void inFormOfImportingExportedStageCiItPreserveStageType() throws Exception {
+ val stage = new SAPIParentStage();
+ stage.setStageType(SAPI_SPRINT_RACE);
+ val raceStage = usingConstructor().constructFrom(stage);
+ val importedRaceStage = exportSerializeAndUseConstructorToReimport(raceStage).construct();
+
+ assertThat(importedRaceStage.getStageType()).isEqualTo(SprintRace);
+ }
+ }
+
+ @RunWith(Enclosed.class)
+ public static class GivenStageTypeIsNotAvailableOnConstruction {
+
+ @RunWith(JUnitParamsRunner.class)
+ public static class ButSubsequentMergeContainsStageType {
+
+ @Test
+ @Parameters(method = "raceStagesWithoutStageType")
+ public void whenSubsequentMergeObjectIsSportEvent(RaceStageCIImpl raceStage) {
+ val updatedStage = new SAPISportEvent();
+ updatedStage.setStageType(SAPI_SPRINT_RACE);
+
+ raceStage.merge(updatedStage, Languages.any());
+
+ assertThat(raceStage.getStageType()).isEqualTo(SprintRace);
+ }
+
+ @Test
+ @Parameters(method = "raceStagesWithoutStageType")
+ public void whenSubsequentMergeObjectIsFixture(RaceStageCIImpl raceStage) {
+ val updatedStage = new SAPIFixture();
+ updatedStage.setStageType(SAPI_SPRINT_RACE);
+
+ raceStage.merge(updatedStage, Languages.any());
+
+ assertThat(raceStage.getStageType()).isEqualTo(SprintRace);
+ }
+
+ @Test
+ @Parameters(method = "raceStagesWithoutStageType")
+ public void whenSubsequentMergeObjectIsStageSummary(RaceStageCIImpl raceStage) {
+ val updatedStage = new SAPIStageSummaryEndpoint();
+ SAPISportEvent stage = new SAPISportEvent();
+ stage.setStageType(SAPI_SPRINT_RACE);
+ updatedStage.setSportEvent(stage);
+
+ raceStage.merge(updatedStage, Languages.any());
+
+ assertThat(raceStage.getStageType()).isEqualTo(SprintRace);
+ }
+
+ @Test
+ @Parameters(method = "raceStagesWithoutStageType")
+ public void whenSubsequentMergeObjectIsChildSportEvent(RaceStageCIImpl raceStage) {
+ val updatedStage = new SAPISportEventChildren.SAPISportEvent();
+ updatedStage.setStageType(SAPI_SPRINT_RACE);
+
+ raceStage.merge(updatedStage, Languages.any());
+
+ assertThat(raceStage.getStageType()).isEqualTo(SprintRace);
+ }
+
+ @Test
+ @Parameters(method = "raceStagesWithoutStageType")
+ public void whenSubsequentMergeObjectIsParentStage(RaceStageCIImpl raceStage) {
+ val updatedStage = new SAPIParentStage();
+ updatedStage.setStageType(SAPI_SPRINT_RACE);
+
+ raceStage.merge(updatedStage, Languages.any());
+
+ assertThat(raceStage.getStageType()).isEqualTo(SprintRace);
+ }
+
+ private Object[] raceStagesWithoutStageType() throws Exception {
+ return new Object[][] {
+ { usingConstructor().constructFrom(new SAPISportEvent()) },
+ { usingConstructor().constructFrom(new SAPIFixture()) },
+ { usingConstructor().constructFrom(createEmptySapiStageSummary()) },
+ { usingConstructor().constructFrom(new SAPISportEventChildren.SAPISportEvent()) },
+ { usingConstructor().constructFrom(new SAPIParentStage()) },
+ { createReimportedStage() },
+ };
+ }
+
+ private static RaceStageCIImpl createReimportedStage() throws Exception {
+ SAPIParentStage anySapiObject = new SAPIParentStage();
+ val stage = usingConstructor().constructFrom(anySapiObject);
+ return exportSerializeAndUseConstructorToReimport(stage).construct();
+ }
+
+ private static SAPIStageSummaryEndpoint createEmptySapiStageSummary() {
+ val sapiStageSummary = new SAPIStageSummaryEndpoint();
+ sapiStageSummary.setSportEvent(new SAPISportEvent());
+ return sapiStageSummary;
+ }
+ }
+
+ public static class FromSummarySourceObject {
+
+ @Test
+ public void thenSummaryIsNotReQueriedAsItIsConsideredToBeSourceOfTruthForStageType()
+ throws CommunicationException {
+ val stageSummary = new SAPIStageSummaryEndpoint();
+ stageSummary.setSportEvent(new SAPISportEvent());
+ DataRouterManager dataRouterManager = mock(DataRouterManager.class);
+ val stage = usingConstructor().with(dataRouterManager).constructFrom(stageSummary);
+
+ stage.getStageType();
+
+ verify(dataRouterManager, never()).requestSummaryEndpoint(any(), any(), any());
+ }
+ }
+
+ @RunWith(Enclosed.class)
+ public static class FromNonSummarySourceObject {
+
+ public static class ThenSummaryIsQueriedButDueToSomeEdgeCaseDownstreamItIsNotMergedIntoCi {
+
+ private DataRouterManager dataRouterManager = mock(DataRouterManager.class);
+
+ @Test
+ public void whenSourceObjectForConstructionIsSportEvent() throws CommunicationException {
+ val stage = usingConstructor()
+ .with(dataRouterManager)
+ .constructFrom(new SAPISportEvent());
+
+ val stageType = stage.getStageType();
+
+ assertThat(stageType).isNull();
+ verify(dataRouterManager).requestSummaryEndpoint(any(), any(), any());
+ }
+
+ @Test
+ public void whenSourceObjectForConstructionIsFixture() throws CommunicationException {
+ val stage = usingConstructor().with(dataRouterManager).constructFrom(new SAPIFixture());
+
+ val stageType = stage.getStageType();
+
+ assertThat(stageType).isNull();
+ verify(dataRouterManager).requestSummaryEndpoint(any(), any(), any());
+ }
+
+ @Test
+ public void whenSourceObjectForConstructionIsChildSportEvent() throws CommunicationException {
+ val stage = usingConstructor()
+ .with(dataRouterManager)
+ .constructFrom(new SAPISportEventChildren.SAPISportEvent());
+
+ val stageType = stage.getStageType();
+
+ assertThat(stageType).isNull();
+ verify(dataRouterManager).requestSummaryEndpoint(any(), any(), any());
+ }
+
+ @Test
+ public void whenSourceObjectForConstructionIsParentStage() throws CommunicationException {
+ val stage = usingConstructor()
+ .with(dataRouterManager)
+ .constructFrom(new SAPIParentStage());
+
+ val stageType = stage.getStageType();
+
+ assertThat(stageType).isNull();
+ verify(dataRouterManager).requestSummaryEndpoint(any(), any(), any());
+ }
+
+ @Test
+ public void afterReimportingStageCi() throws Exception {
+ val stageWithoutType = usingConstructor().constructFrom(new SAPIParentStage());
+ val importedRaceStage = exportSerializeAndUseConstructorToReimport(stageWithoutType)
+ .with(dataRouterManager)
+ .construct();
+
+ val stageType = importedRaceStage.getStageType();
+
+ assertThat(stageType).isNull();
+ verify(dataRouterManager).requestSummaryEndpoint(any(), any(), any());
+ }
+ }
+
+ public static class ThenSummaryIsQueriedAndMergedIntoCiWithStageTypeUpdated {
+
+ private DataRouterManager dataRouterManager = mock(DataRouterManager.class);
+
+ @Test
+ public void whenSourceObjectForConstructionIsSportEvent() throws CommunicationException {
+ val stage = usingConstructor()
+ .with(dataRouterManager)
+ .constructFrom(new SAPISportEvent());
+ whenRequestedSummaryThenMerges(stageSummaryOfType(SAPI_SPRINT_RACE), into(stage));
+
+ assertThat(stage.getStageType()).isEqualTo(SprintRace);
+ }
+
+ @Test
+ public void whenSourceObjectForConstructionIsFixture() throws CommunicationException {
+ val stage = usingConstructor().with(dataRouterManager).constructFrom(new SAPIFixture());
+ whenRequestedSummaryThenMerges(stageSummaryOfType(SAPI_SPRINT_RACE), into(stage));
+
+ assertThat(stage.getStageType()).isEqualTo(SprintRace);
+ }
+
+ @Test
+ public void whenSourceObjectForConstructionIsChildSportEvent() throws CommunicationException {
+ val stage = usingConstructor()
+ .with(dataRouterManager)
+ .constructFrom(new SAPISportEventChildren.SAPISportEvent());
+ whenRequestedSummaryThenMerges(stageSummaryOfType(SAPI_SPRINT_RACE), into(stage));
+
+ assertThat(stage.getStageType()).isEqualTo(SprintRace);
+ }
+
+ @Test
+ public void whenSourceObjectForConstructionIsParentStage() throws CommunicationException {
+ val stage = usingConstructor()
+ .with(dataRouterManager)
+ .constructFrom(new SAPIParentStage());
+ whenRequestedSummaryThenMerges(stageSummaryOfType(SAPI_SPRINT_RACE), into(stage));
+
+ assertThat(stage.getStageType()).isEqualTo(SprintRace);
+ }
+
+ @Test
+ public void afterReimportingStageCi() throws Exception {
+ SAPIParentStage anySourceObject = new SAPIParentStage();
+ val stage = usingConstructor().constructFrom(anySourceObject);
+ val importedRaceStage = exportSerializeAndUseConstructorToReimport(stage)
+ .with(dataRouterManager)
+ .construct();
+ whenRequestedSummaryThenMerges(
+ stageSummaryOfType(SAPI_SPRINT_RACE),
+ into(importedRaceStage)
+ );
+
+ assertThat(importedRaceStage.getStageType()).isEqualTo(SprintRace);
+ }
+
+ private void whenRequestedSummaryThenMerges(
+ SAPIStageSummaryEndpoint raceStageSummary,
+ RaceStageCiToMergeTo stage
+ ) throws CommunicationException {
+ does(() -> stage.getValue().merge(raceStageSummary, Languages.any()))
+ .when(dataRouterManager)
+ .requestSummaryEndpoint(any(), any(), any());
+ }
+
+ private static Stubber does(Runnable action) {
+ return doAnswer(args -> {
+ action.run();
+ return null;
+ });
+ }
+ }
+
+ @RunWith(Enclosed.class)
+ public static class AndSummaryIsQueriedButItFailsDueToCommunicationErrorAndSdkIsConfiguredToThrowErrors {
+
+ public static class ThenErrorIsWrappedAndRethrown {
+
+ private DataRouterManager dataRouterManager = mock(DataRouterManager.class);
+ private CommunicationException communicationError = new CommunicationException(
+ "any error message",
+ "anyUrl"
+ );
+ private ExceptionHandlingStrategy sdkThrowsErrors = Throw;
+
+ @Test
+ public void whenSourceObjectForConstructionIsSportEvent() throws CommunicationException {
+ val stage = usingConstructor()
+ .with(dataRouterManager)
+ .with(sdkThrowsErrors)
+ .constructFrom(new SAPISportEvent());
+ doThrow(communicationError)
+ .when(dataRouterManager)
+ .requestSummaryEndpoint(any(), any(), any());
+
+ assertThatThrownBy(() -> stage.getStageType()).hasRootCause(communicationError);
+ }
+
+ @Test
+ public void whenSourceObjectForConstructionIsFixture() throws CommunicationException {
+ val stage = usingConstructor()
+ .with(dataRouterManager)
+ .with(sdkThrowsErrors)
+ .constructFrom(new SAPIFixture());
+ doThrow(communicationError)
+ .when(dataRouterManager)
+ .requestSummaryEndpoint(any(), any(), any());
+
+ assertThatThrownBy(() -> stage.getStageType()).hasRootCause(communicationError);
+ }
+
+ @Test
+ public void whenSourceObjectForConstructionIsChildSportEvent()
+ throws CommunicationException {
+ val stage = usingConstructor()
+ .with(dataRouterManager)
+ .with(sdkThrowsErrors)
+ .constructFrom(new SAPISportEventChildren.SAPISportEvent());
+ doThrow(communicationError)
+ .when(dataRouterManager)
+ .requestSummaryEndpoint(any(), any(), any());
+
+ assertThatThrownBy(() -> stage.getStageType()).hasRootCause(communicationError);
+ }
+
+ @Test
+ public void whenSourceObjectForConstructionIsParentStage() throws CommunicationException {
+ val stage = usingConstructor()
+ .with(dataRouterManager)
+ .with(sdkThrowsErrors)
+ .constructFrom(new SAPIParentStage());
+ doThrow(communicationError)
+ .when(dataRouterManager)
+ .requestSummaryEndpoint(any(), any(), any());
+
+ assertThatThrownBy(() -> stage.getStageType()).hasRootCause(communicationError);
+ }
+
+ @Test
+ public void afterReimportingStageCi() throws Exception {
+ val anySourceObject = new SAPIParentStage();
+ val stage = usingConstructor().constructFrom(anySourceObject);
+ val importedStage = exportSerializeAndUseConstructorToReimport(stage)
+ .with(dataRouterManager)
+ .with(sdkThrowsErrors)
+ .construct();
+ doThrow(communicationError)
+ .when(dataRouterManager)
+ .requestSummaryEndpoint(any(), any(), any());
+
+ assertThatThrownBy(() -> importedStage.getStageType())
+ .hasRootCause(communicationError);
+ }
+ }
+ }
+
+ @RunWith(Enclosed.class)
+ public static class AndSummaryIsQueriedButItFailsDueToCommunicationErrorAndSdkIsConfiguredToCatchErrors {
+
+ public static class ThenSdkDoesNotProvideStageType {
+
+ private DataRouterManager dataRouterManager = mock(DataRouterManager.class);
+ private CommunicationException communicationError = new CommunicationException(
+ "any error message",
+ "anyUrl"
+ );
+ private ExceptionHandlingStrategy sdkCatchesErrors = Catch;
+
+ @Test
+ public void whenSourceObjectForConstructionIsSportEvent() throws CommunicationException {
+ val stage = usingConstructor()
+ .with(dataRouterManager)
+ .with(sdkCatchesErrors)
+ .constructFrom(new SAPISportEvent());
+ doThrow(communicationError)
+ .when(dataRouterManager)
+ .requestSummaryEndpoint(any(), any(), any());
+
+ assertThat(stage.getStageType()).isNull();
+ }
+
+ @Test
+ public void whenSourceObjectForConstructionIsFixture() throws CommunicationException {
+ val stage = usingConstructor()
+ .with(dataRouterManager)
+ .with(sdkCatchesErrors)
+ .constructFrom(new SAPIFixture());
+ doThrow(communicationError)
+ .when(dataRouterManager)
+ .requestSummaryEndpoint(any(), any(), any());
+
+ assertThat(stage.getStageType()).isNull();
+ }
+
+ @Test
+ public void whenSourceObjectForConstructionIsChildSportEvent()
+ throws CommunicationException {
+ val stage = usingConstructor()
+ .with(dataRouterManager)
+ .with(sdkCatchesErrors)
+ .constructFrom(new SAPISportEventChildren.SAPISportEvent());
+ doThrow(communicationError)
+ .when(dataRouterManager)
+ .requestSummaryEndpoint(any(), any(), any());
+
+ assertThat(stage.getStageType()).isNull();
+ }
+
+ @Test
+ public void whenSourceObjectUserForConstructionIsParentStage()
+ throws CommunicationException {
+ val stage = usingConstructor()
+ .with(dataRouterManager)
+ .with(sdkCatchesErrors)
+ .constructFrom(new SAPIParentStage());
+ doThrow(communicationError)
+ .when(dataRouterManager)
+ .requestSummaryEndpoint(any(), any(), any());
+
+ assertThat(stage.getStageType()).isNull();
+ }
+
+ @Test
+ public void afterReimportingStageCi() throws Exception {
+ val anySapiSourceObject = new SAPIParentStage();
+ val stage = usingConstructor().constructFrom(anySapiSourceObject);
+ val importedStage = exportSerializeAndUseConstructorToReimport(stage)
+ .with(dataRouterManager)
+ .with(sdkCatchesErrors)
+ .construct();
+ doThrow(communicationError)
+ .when(dataRouterManager)
+ .requestSummaryEndpoint(any(), any(), any());
+
+ assertThat(importedStage.getStageType()).isNull();
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/sdk-core/src/test/java/com/sportradar/unifiedodds/sdk/caching/impl/ci/RaceStageCiToMergeTo.java b/sdk-core/src/test/java/com/sportradar/unifiedodds/sdk/caching/impl/ci/RaceStageCiToMergeTo.java
new file mode 100644
index 00000000..b72f41a0
--- /dev/null
+++ b/sdk-core/src/test/java/com/sportradar/unifiedodds/sdk/caching/impl/ci/RaceStageCiToMergeTo.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) Sportradar AG. See LICENSE for full license governing this code
+ */
+package com.sportradar.unifiedodds.sdk.caching.impl.ci;
+
+import com.sportradar.unifiedodds.sdk.caching.StageCI;
+
+class RaceStageCiToMergeTo {
+
+ private StageCI value;
+
+ private RaceStageCiToMergeTo(StageCI value) {
+ this.value = value;
+ }
+
+ static RaceStageCiToMergeTo into(StageCI target) {
+ return new RaceStageCiToMergeTo(target);
+ }
+
+ StageCI getValue() {
+ return value;
+ }
+}
diff --git a/sdk-core/src/test/java/com/sportradar/unifiedodds/sdk/caching/impl/ci/RaceStageCis.java b/sdk-core/src/test/java/com/sportradar/unifiedodds/sdk/caching/impl/ci/RaceStageCis.java
new file mode 100644
index 00000000..47137643
--- /dev/null
+++ b/sdk-core/src/test/java/com/sportradar/unifiedodds/sdk/caching/impl/ci/RaceStageCis.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) Sportradar AG. See LICENSE for full license governing this code
+ */
+package com.sportradar.unifiedodds.sdk.caching.impl.ci;
+
+import static com.sportradar.unifiedodds.sdk.ExceptionHandlingStrategies.anyErrorHandlingStrategy;
+import static com.sportradar.unifiedodds.sdk.testutil.serialization.JavaSerializer.deserialize;
+import static com.sportradar.unifiedodds.sdk.testutil.serialization.JavaSerializer.serialize;
+import static com.sportradar.utils.Urns.SportEvents.urnForAnyStage;
+import static java.util.Optional.empty;
+
+import com.sportradar.uf.sportsapi.datamodel.*;
+import com.sportradar.unifiedodds.sdk.ExceptionHandlingStrategy;
+import com.sportradar.unifiedodds.sdk.caching.DataRouterManager;
+import com.sportradar.unifiedodds.sdk.caching.exportable.ExportableRaceStageCI;
+import com.sportradar.unifiedodds.sdk.caching.impl.DataRouterManagers;
+import com.sportradar.unifiedodds.sdk.testutil.guava.libraryfixtures.Caches;
+import com.sportradar.unifiedodds.sdk.testutil.javautil.Languages;
+import java.util.*;
+import lombok.val;
+
+public class RaceStageCis {
+
+ private static Random random = new Random();
+
+ private RaceStageCis() {}
+
+ public static BuilderForConstructionOnly usingConstructor() {
+ return new BuilderForConstructionOnly();
+ }
+
+ public static BuilderForConstructionFromExportedOnly usingConstructorToReimport(
+ ExportableRaceStageCI exported
+ ) {
+ return new BuilderForConstructionFromExportedOnly(exported);
+ }
+
+ public static BuilderForConstructionFromExportedOnly exportSerializeAndUseConstructorToReimport(
+ RaceStageCIImpl original
+ ) throws Exception {
+ val exportedRaceStage = original.export();
+ val serialized = serialize(exportedRaceStage);
+ val deserialized = deserialize(serialized);
+ return usingConstructorToReimport((ExportableRaceStageCI) deserialized);
+ }
+
+ public static class BuilderForConstructionOnly {
+
+ private Optional providedDataRouterManager = empty();
+ private Optional providedErrorHandlingStrategy = empty();
+
+ private BuilderForConstructionOnly() {}
+
+ public BuilderForConstructionOnly with(DataRouterManager dataRouterManager) {
+ this.providedDataRouterManager = Optional.of(dataRouterManager);
+ return this;
+ }
+
+ public BuilderForConstructionOnly with(ExceptionHandlingStrategy exceptionHandlingStrategy) {
+ this.providedErrorHandlingStrategy = Optional.of(exceptionHandlingStrategy);
+ return this;
+ }
+
+ public RaceStageCIImpl constructFrom(SAPISportEvent sapiSourceObject) {
+ return new RaceStageCIImpl(
+ urnForAnyStage(),
+ providedDataRouterManager.orElse(DataRouterManagers.any()),
+ Languages.any(),
+ providedErrorHandlingStrategy.orElse(anyErrorHandlingStrategy()),
+ sapiSourceObject,
+ Languages.any(),
+ Caches.any()
+ );
+ }
+
+ public RaceStageCIImpl constructFrom(SAPIFixture sapiSourceObject) {
+ return new RaceStageCIImpl(
+ urnForAnyStage(),
+ providedDataRouterManager.orElse(DataRouterManagers.any()),
+ Languages.any(),
+ providedErrorHandlingStrategy.orElse(anyErrorHandlingStrategy()),
+ sapiSourceObject,
+ Languages.any(),
+ Caches.any()
+ );
+ }
+
+ public RaceStageCIImpl constructFrom(SAPIStageSummaryEndpoint sapiSourceObject) {
+ return new RaceStageCIImpl(
+ urnForAnyStage(),
+ providedDataRouterManager.orElse(DataRouterManagers.any()),
+ Languages.any(),
+ providedErrorHandlingStrategy.orElse(anyErrorHandlingStrategy()),
+ sapiSourceObject,
+ Languages.any(),
+ Caches.any()
+ );
+ }
+
+ public RaceStageCIImpl constructFrom(SAPISportEventChildren.SAPISportEvent sapiSourceObject) {
+ return new RaceStageCIImpl(
+ urnForAnyStage(),
+ providedDataRouterManager.orElse(DataRouterManagers.any()),
+ Languages.any(),
+ providedErrorHandlingStrategy.orElse(anyErrorHandlingStrategy()),
+ sapiSourceObject,
+ Languages.any(),
+ Caches.any()
+ );
+ }
+
+ public RaceStageCIImpl constructFrom(SAPIParentStage sapiSourceObject) {
+ return new RaceStageCIImpl(
+ urnForAnyStage(),
+ providedDataRouterManager.orElse(DataRouterManagers.any()),
+ Languages.any(),
+ providedErrorHandlingStrategy.orElse(anyErrorHandlingStrategy()),
+ sapiSourceObject,
+ Languages.any(),
+ Caches.any()
+ );
+ }
+ }
+
+ public static class BuilderForConstructionFromExportedOnly {
+
+ private ExportableRaceStageCI exportableToImport;
+ private Optional providedDataRouterManager = empty();
+ private Optional providedErrorHandlingStrategy = empty();
+
+ private BuilderForConstructionFromExportedOnly(ExportableRaceStageCI exportableToImport) {
+ this.exportableToImport = exportableToImport;
+ }
+
+ public BuilderForConstructionFromExportedOnly with(DataRouterManager dataRouterManager) {
+ this.providedDataRouterManager = Optional.of(dataRouterManager);
+ return this;
+ }
+
+ public BuilderForConstructionFromExportedOnly with(
+ ExceptionHandlingStrategy exceptionHandlingStrategy
+ ) {
+ this.providedErrorHandlingStrategy = Optional.of(exceptionHandlingStrategy);
+ return this;
+ }
+
+ public RaceStageCIImpl construct() {
+ return new RaceStageCIImpl(
+ exportableToImport,
+ providedDataRouterManager.orElse(DataRouterManagers.any()),
+ providedErrorHandlingStrategy.orElse(anyErrorHandlingStrategy()),
+ Caches.any()
+ );
+ }
+ }
+}
diff --git a/sdk-core/src/test/java/com/sportradar/unifiedodds/sdk/conn/RabbitProducer.java b/sdk-core/src/test/java/com/sportradar/unifiedodds/sdk/conn/RabbitProducer.java
index aff0dfd1..c6fbd865 100644
--- a/sdk-core/src/test/java/com/sportradar/unifiedodds/sdk/conn/RabbitProducer.java
+++ b/sdk-core/src/test/java/com/sportradar/unifiedodds/sdk/conn/RabbitProducer.java
@@ -19,6 +19,7 @@
import com.sportradar.unifiedodds.sdk.shared.TestProducersProvider;
import com.sportradar.unifiedodds.sdk.testutil.rabbit.integration.*;
import com.sportradar.utils.URN;
+import java.io.IOException;
import java.util.*;
import java.util.concurrent.*;
import lombok.val;
@@ -94,16 +95,18 @@ public void start() {
ManagementClient.closeConnection(connectionInfo.getName(), "cleanup");
}
+ val vhostLocation = VhostLocation.at(Constants.RABBIT_IP, Constants.UF_VIRTUALHOST);
+ val exchangeLocation = ExchangeLocation.at(vhostLocation, Constants.UF_EXCHANGE);
+ val adminCredentials = Credentials.with(Constants.ADMIN_USERNAME, Constants.ADMIN_PASSWORD);
+ val factory = new ConnectionFactory();
+
try {
- val vhostLocation = VhostLocation.at(Constants.RABBIT_IP, Constants.UF_VIRTUALHOST);
- val exchangeLocation = ExchangeLocation.at(vhostLocation, Constants.UF_EXCHANGE);
- val adminCredentials = Credentials.with(Constants.ADMIN_USERNAME, Constants.ADMIN_PASSWORD);
- val factory = new ConnectionFactory();
producer = connectDeclaringExchange(exchangeLocation, adminCredentials, factory, time);
- } catch (Exception ex) {
- Helper.writeToOutput(ex.getMessage());
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ } catch (TimeoutException e) {
+ throw new RuntimeException(e);
}
-
timerTaskScheduler = Executors.newScheduledThreadPool(1);
timerFuture =
timerTaskScheduler.scheduleAtFixedRate(() -> timerCheckAndSend(), 1, 1, TimeUnit.SECONDS);
@@ -154,16 +157,16 @@ public void send(UnmarshalledMessage message, String routingKey, long timestamp)
when(time.now()).thenReturn(timestamp);
try {
producer.send(msgBody, routingKey);
- String result = String.format(
- "Generated:%s, Routing: %s, Msg: %s",
- new Date(timestamp),
- routingKey,
- message
- );
- Helper.writeToOutput(result);
- } catch (Exception ex) {
- Helper.writeToOutput("Error sending message: " + ex.getMessage());
+ } catch (IOException e) {
+ throw new RuntimeException(e);
}
+ String result = String.format(
+ "Generated:%s, Routing: %s, Msg: %s",
+ new Date(timestamp),
+ routingKey,
+ message
+ );
+ Helper.writeToOutput(result);
}
/**
diff --git a/sdk-core/src/test/java/com/sportradar/unifiedodds/sdk/conn/SdkConnectionTests.java b/sdk-core/src/test/java/com/sportradar/unifiedodds/sdk/conn/SdkConnectionTests.java
index 1042b21c..1b6cd74b 100644
--- a/sdk-core/src/test/java/com/sportradar/unifiedodds/sdk/conn/SdkConnectionTests.java
+++ b/sdk-core/src/test/java/com/sportradar/unifiedodds/sdk/conn/SdkConnectionTests.java
@@ -426,7 +426,7 @@ public void multipleProducersWithAfterTest() throws InitException {
new TestHttpHelper.UrlReplacement("/liveodds/", 1, HttpStatus.SC_ACCEPTED)
);
feed.TestHttpHelper.PostResponses.add(
- new TestHttpHelper.UrlReplacement("/prematch/", 1, HttpStatus.SC_ACCEPTED)
+ new TestHttpHelper.UrlReplacement("/pre/", 1, HttpStatus.SC_ACCEPTED)
);
List disabledProducers = Arrays.asList(2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17);
@@ -614,7 +614,7 @@ public void multipleProducersMultiSessionTest() throws InitException {
new TestHttpHelper.UrlReplacement("/liveodds/", 1, HttpStatus.SC_ACCEPTED)
);
feed.TestHttpHelper.PostResponses.add(
- new TestHttpHelper.UrlReplacement("/prematch/", 1, HttpStatus.SC_ACCEPTED)
+ new TestHttpHelper.UrlReplacement("/pre/", 1, HttpStatus.SC_ACCEPTED)
);
List disabledProducers = Arrays.asList(2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17);
@@ -966,8 +966,8 @@ public void recoveryUnsuccessfulRetryTest() throws InitException {
rabbitProducer.send(snapshotComplete);
waitAndCheckTillTimeout(
- w -> checkProducerFlaggedDown(producerId, false),
- "Producer is not down",
+ w -> checkProducerFlaggedDown(producerId, true),
+ "Producer is down",
1000,
10000
);
@@ -1143,7 +1143,7 @@ public void producerNoAlivesMakeRecoveryTest() throws InitException {
w -> checkProducerRecovery(producerId, false),
"Producer recovery info is not null",
5000,
- 62000
+ 70000
);
producer = feed.getProducerManager().getProducer(producerId);
@@ -2044,7 +2044,7 @@ public void connectionBreakMultiSessionTest() throws InitException {
new TestHttpHelper.UrlReplacement("/liveodds/", 1, HttpStatus.SC_ACCEPTED)
);
feed.TestHttpHelper.PostResponses.add(
- new TestHttpHelper.UrlReplacement("/prematch/", 1, HttpStatus.SC_ACCEPTED)
+ new TestHttpHelper.UrlReplacement("/pre/", 1, HttpStatus.SC_ACCEPTED)
);
feed.TestHttpHelper.PostResponses.add(
new TestHttpHelper.UrlReplacement("/vf/", 1, HttpStatus.SC_ACCEPTED)
@@ -3140,6 +3140,7 @@ private void waitAndCheckTillTimeout(
Helper.durationBetweenDatesInMs(start, new Date())
)
);
+ throw new RuntimeException("Condition not met: " + message);
}
private void disableProducers(List producerIds, OddsFeed feed) {
diff --git a/sdk-core/src/test/java/com/sportradar/unifiedodds/sdk/testutil/guava/libraryfixtures/Caches.java b/sdk-core/src/test/java/com/sportradar/unifiedodds/sdk/testutil/guava/libraryfixtures/Caches.java
new file mode 100644
index 00000000..ef575655
--- /dev/null
+++ b/sdk-core/src/test/java/com/sportradar/unifiedodds/sdk/testutil/guava/libraryfixtures/Caches.java
@@ -0,0 +1,15 @@
+/*
+ * Copyright (C) Sportradar AG. See LICENSE for full license governing this code
+ */
+package com.sportradar.unifiedodds.sdk.testutil.guava.libraryfixtures;
+
+import com.google.common.cache.Cache;
+
+public class Caches {
+
+ private Caches() {}
+
+ public static Cache any() {
+ return new NoOpCache();
+ }
+}
diff --git a/sdk-core/src/test/java/com/sportradar/unifiedodds/sdk/testutil/guava/libraryfixtures/NoOpCache.java b/sdk-core/src/test/java/com/sportradar/unifiedodds/sdk/testutil/guava/libraryfixtures/NoOpCache.java
new file mode 100644
index 00000000..de9c07e6
--- /dev/null
+++ b/sdk-core/src/test/java/com/sportradar/unifiedodds/sdk/testutil/guava/libraryfixtures/NoOpCache.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) Sportradar AG. See LICENSE for full license governing this code
+ */
+package com.sportradar.unifiedodds.sdk.testutil.guava.libraryfixtures;
+
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheStats;
+import com.google.common.collect.ImmutableMap;
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ExecutionException;
+
+public class NoOpCache implements Cache {
+
+ @Override
+ public Object getIfPresent(Object o) {
+ return null;
+ }
+
+ @Override
+ public Object get(Object o, Callable callable) throws ExecutionException {
+ return null;
+ }
+
+ @Override
+ public void put(Object o, Object o2) {}
+
+ @Override
+ public void putAll(Map map) {}
+
+ @Override
+ public void invalidate(Object o) {}
+
+ @Override
+ public long size() {
+ return 0;
+ }
+
+ @Override
+ public CacheStats stats() {
+ return null;
+ }
+
+ @Override
+ public ConcurrentMap asMap() {
+ return null;
+ }
+
+ @Override
+ public void cleanUp() {}
+
+ @Override
+ public void invalidateAll() {}
+
+ @Override
+ public void invalidateAll(Iterable iterable) {}
+
+ @Override
+ public ImmutableMap getAllPresent(Iterable iterable) {
+ return null;
+ }
+}
diff --git a/sdk-core/src/test/java/com/sportradar/unifiedodds/sdk/testutil/javautil/Languages.java b/sdk-core/src/test/java/com/sportradar/unifiedodds/sdk/testutil/javautil/Languages.java
new file mode 100644
index 00000000..08551523
--- /dev/null
+++ b/sdk-core/src/test/java/com/sportradar/unifiedodds/sdk/testutil/javautil/Languages.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) Sportradar AG. See LICENSE for full license governing this code
+ */
+package com.sportradar.unifiedodds.sdk.testutil.javautil;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
+import java.util.Random;
+
+public class Languages {
+
+ private static Random random = new Random();
+
+ private Languages() {}
+
+ public static Locale any() {
+ List languagePool = Arrays.asList(
+ Locale.ENGLISH,
+ Locale.GERMANY,
+ Locale.CANADA,
+ Locale.FRENCH,
+ Locale.CHINESE,
+ Locale.ITALY,
+ Locale.JAPAN
+ );
+ return languagePool.get(random.nextInt(languagePool.size()));
+ }
+}
diff --git a/sdk-core/src/test/java/com/sportradar/unifiedodds/sdk/testutil/javautil/LanguagesTest.java b/sdk-core/src/test/java/com/sportradar/unifiedodds/sdk/testutil/javautil/LanguagesTest.java
new file mode 100644
index 00000000..0d90a21a
--- /dev/null
+++ b/sdk-core/src/test/java/com/sportradar/unifiedodds/sdk/testutil/javautil/LanguagesTest.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) Sportradar AG. See LICENSE for full license governing this code
+ */
+package com.sportradar.unifiedodds.sdk.testutil.javautil;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.List;
+import java.util.Locale;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.junit.Test;
+
+public class LanguagesTest {
+
+ private final int sampleSize = 100;
+ private List languages = Stream
+ .generate(() -> Languages.any())
+ .limit(sampleSize)
+ .distinct()
+ .collect(Collectors.toList());
+
+ @Test
+ public void anyLanguageGeneratesNotAlwaysTheSameLanguages() {
+ assertThat(languages).hasSizeGreaterThan(1);
+ }
+
+ @Test
+ public void anyLanguageDoesNotGenerateNullLanguages() {
+ assertThat(languages).doesNotContainNull();
+ }
+}
diff --git a/sdk-core/src/test/java/com/sportradar/unifiedodds/sdk/testutil/serialization/JavaSerializer.java b/sdk-core/src/test/java/com/sportradar/unifiedodds/sdk/testutil/serialization/JavaSerializer.java
new file mode 100644
index 00000000..f45afd11
--- /dev/null
+++ b/sdk-core/src/test/java/com/sportradar/unifiedodds/sdk/testutil/serialization/JavaSerializer.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) Sportradar AG. See LICENSE for full license governing this code
+ */
+package com.sportradar.unifiedodds.sdk.testutil.serialization;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+public class JavaSerializer {
+
+ private JavaSerializer() {}
+
+ public static byte[] serialize(Object ob) throws Exception {
+ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
+ objectOutputStream.writeObject(ob);
+ byte[] result = byteArrayOutputStream.toByteArray();
+ objectOutputStream.close();
+ byteArrayOutputStream.close();
+ return result;
+ }
+
+ public static T deserialize(byte[] bytes) throws Exception {
+ ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
+ ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
+ T object = (T) objectInputStream.readObject();
+ objectInputStream.close();
+ byteArrayInputStream.close();
+ return object;
+ }
+}
diff --git a/sdk-core/src/test/java/com/sportradar/unifiedodds/sdk/testutil/serialization/JavaSerializerTest.java b/sdk-core/src/test/java/com/sportradar/unifiedodds/sdk/testutil/serialization/JavaSerializerTest.java
new file mode 100644
index 00000000..72d78499
--- /dev/null
+++ b/sdk-core/src/test/java/com/sportradar/unifiedodds/sdk/testutil/serialization/JavaSerializerTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) Sportradar AG. See LICENSE for full license governing this code
+ */
+package com.sportradar.unifiedodds.sdk.testutil.serialization;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import java.io.NotSerializableException;
+import java.io.Serializable;
+import java.io.StreamCorruptedException;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.val;
+import org.junit.Test;
+
+public class JavaSerializerTest {
+
+ private static final byte[] RANDOM_BYTES = { 4, 7, 5, 1, 2, 4, 5, 6 };
+
+ @Test
+ public void notSerializesObjectWhichAreNotMarkedAsSerializable() throws Exception {
+ assertThatThrownBy(() -> JavaSerializer.serialize(new NotMarkedWithSerializable()))
+ .isInstanceOf(NotSerializableException.class);
+ }
+
+ @Test
+ public void doesNotDeserializeBytesWhichDoesNotRepresentObject() throws Exception {
+ assertThatThrownBy(() -> JavaSerializer.deserialize(RANDOM_BYTES))
+ .isInstanceOf(StreamCorruptedException.class);
+ }
+
+ @Test
+ public void serializationProcessShouldPreserveFieldValuesSetInitially() throws Exception {
+ String value = "someValue";
+ val originalObject = new SerializableClass();
+ originalObject.setSomeField(value);
+
+ val deserialized = (SerializableClass) JavaSerializer.deserialize(
+ JavaSerializer.serialize(originalObject)
+ );
+
+ assertThat(deserialized.getSomeField()).isEqualTo(value);
+ }
+
+ @Test
+ public void deserializationCreatesAnotherInstanceOfTheObject() throws Exception {
+ String value = "someValue";
+ val originalObject = new SerializableClass();
+ originalObject.setSomeField(value);
+
+ val deserialized = (SerializableClass) JavaSerializer.deserialize(
+ JavaSerializer.serialize(originalObject)
+ );
+
+ assertThat(deserialized).isNotSameAs(originalObject);
+ }
+
+ public static class NotMarkedWithSerializable {
+
+ private int anyField;
+ }
+
+ @Setter
+ @Getter
+ public static class SerializableClass implements Serializable {
+
+ private String someField;
+ }
+}
diff --git a/sdk-core/src/test/java/com/sportradar/utils/Urns.java b/sdk-core/src/test/java/com/sportradar/utils/Urns.java
index 79a849ed..ef6641c7 100644
--- a/sdk-core/src/test/java/com/sportradar/utils/Urns.java
+++ b/sdk-core/src/test/java/com/sportradar/utils/Urns.java
@@ -31,6 +31,11 @@ public static URN urnForAnySeason() {
final int anyId = 277;
return URN.parse("sr:season:" + anyId);
}
+
+ public static URN urnForAnyStage() {
+ String anyId = "338";
+ return URN.parse("sr:stage:" + anyId);
+ }
}
public static class Sports {
diff --git a/sdk-core/src/test/java/com/sportradar/utils/UrnsTest.java b/sdk-core/src/test/java/com/sportradar/utils/UrnsTest.java
index 00c365d4..e3f9898f 100644
--- a/sdk-core/src/test/java/com/sportradar/utils/UrnsTest.java
+++ b/sdk-core/src/test/java/com/sportradar/utils/UrnsTest.java
@@ -7,74 +7,94 @@
import lombok.val;
import org.junit.Test;
+import org.junit.experimental.runners.Enclosed;
+import org.junit.runner.RunWith;
+@RunWith(Enclosed.class)
public class UrnsTest {
public static final String SR = "sr";
- @Test
- public void shouldGetFootballUrn() {
- val footballId = 1L;
- URN forFootball = Urns.Sports.getForFootball();
+ private UrnsTest() {}
- assertEquals(SR, forFootball.getPrefix());
- assertEquals("sport", forFootball.getType());
- assertEquals(footballId, forFootball.getId());
- }
+ public static class CreatesSportUrns {
- @Test
- public void shouldGetUrnForAnySport() {
- URN forSport = Urns.Sports.urnForAnySport();
+ @Test
+ public void forFootball() {
+ val footballId = 1L;
+ URN forFootball = Urns.Sports.getForFootball();
- assertEquals(SR, forSport.getPrefix());
- assertEquals("sport", forSport.getType());
- assertTrue(forSport.getId() > 1);
- }
+ assertEquals(SR, forFootball.getPrefix());
+ assertEquals("sport", forFootball.getType());
+ assertEquals(footballId, forFootball.getId());
+ }
- @Test
- public void shouldGetUrnForMatch() {
- URN match = Urns.SportEvents.getForAnyMatch();
+ @Test
+ public void forAny() {
+ URN forSport = Urns.Sports.urnForAnySport();
- assertEquals(SR, match.getPrefix());
- assertEquals("match", match.getType());
- assertTrue(match.getId() > 0L);
+ assertEquals(SR, forSport.getPrefix());
+ assertEquals("sport", forSport.getType());
+ assertTrue(forSport.getId() > 1);
+ }
}
- @Test
- public void shouldProvideUrnForTournament() {
- URN tournament = Urns.SportEvents.urnForAnyTournament();
+ public static class CreateSportEventUrns {
- assertEquals(SR, tournament.getPrefix());
- assertEquals("tournament", tournament.getType());
- assertTrue(tournament.getId() > 0L);
- }
+ @Test
+ public void forAnyMatch() {
+ URN match = Urns.SportEvents.getForAnyMatch();
- @Test
- public void shouldProvideUrnForTournamentWithSpecificId() {
- final int tournamentId = 334;
+ assertEquals(SR, match.getPrefix());
+ assertEquals("match", match.getType());
+ assertTrue(match.getId() > 0L);
+ }
- URN tournament = Urns.SportEvents.urnForTournamentWithId(tournamentId);
+ @Test
+ public void forAnyTournament() {
+ URN tournament = Urns.SportEvents.urnForAnyTournament();
- assertEquals(SR, tournament.getPrefix());
- assertEquals("tournament", tournament.getType());
- assertEquals(tournamentId, tournament.getId());
- }
+ assertEquals(SR, tournament.getPrefix());
+ assertEquals("tournament", tournament.getType());
+ assertTrue(tournament.getId() > 0L);
+ }
- @Test
- public void shouldProvideUrnForSimpleTournament() {
- URN tournament = Urns.SportEvents.urnForAnySimpleTournament();
+ @Test
+ public void forTournamentWithSpecificId() {
+ final int tournamentId = 334;
- assertEquals(SR, tournament.getPrefix());
- assertEquals("simple_tournament", tournament.getType());
- assertTrue(tournament.getId() > 0L);
- }
+ URN tournament = Urns.SportEvents.urnForTournamentWithId(tournamentId);
+
+ assertEquals(SR, tournament.getPrefix());
+ assertEquals("tournament", tournament.getType());
+ assertEquals(tournamentId, tournament.getId());
+ }
+
+ @Test
+ public void forAnySimpleTournament() {
+ URN tournament = Urns.SportEvents.urnForAnySimpleTournament();
+
+ assertEquals(SR, tournament.getPrefix());
+ assertEquals("simple_tournament", tournament.getType());
+ assertTrue(tournament.getId() > 0L);
+ }
+
+ @Test
+ public void forSeason() {
+ URN season = Urns.SportEvents.urnForAnySeason();
+
+ assertEquals(SR, season.getPrefix());
+ assertEquals("season", season.getType());
+ assertTrue(season.getId() > 0L);
+ }
- @Test
- public void shouldProvideUrnForSeason() {
- URN season = Urns.SportEvents.urnForAnySeason();
+ @Test
+ public void forAnyStage() {
+ URN stage = Urns.SportEvents.urnForAnyStage();
- assertEquals(SR, season.getPrefix());
- assertEquals("season", season.getType());
- assertTrue(season.getId() > 0L);
+ assertEquals(SR, stage.getPrefix());
+ assertEquals("stage", stage.getType());
+ assertTrue(stage.getId() > 0L);
+ }
}
}
diff --git a/sdk-example/pom.xml b/sdk-example/pom.xml
index 1c6baa93..27bb91e2 100644
--- a/sdk-example/pom.xml
+++ b/sdk-example/pom.xml
@@ -8,7 +8,7 @@
unified-feed-sdk-parent
com.sportradar.unifiedodds.sdk
- 2.0.60
+ 2.0.61
com.sportradar.unifiedodds.sdk.example