diff --git a/backend/pom.xml b/backend/pom.xml index 0842744..2b5633f 100644 --- a/backend/pom.xml +++ b/backend/pom.xml @@ -21,6 +21,8 @@ 1.21 3.11.4 3.21.7 + 5.0.0 + 0.4.0 3.1.0 @@ -117,6 +119,29 @@ spring-boot-starter-test test + + org.jeasy + easy-random-core + ${easy-random.version} + test + + + io.github.murdos + easy-random-protobuf + ${easy-random-protobuf.version} + test + + + com.squareup.okhttp3 + okhttp + test + + + com.squareup.okhttp3 + mockwebserver + test + + diff --git a/backend/src/main/java/de/grimsi/gameyfin/igdb/IgdbWrapper.java b/backend/src/main/java/de/grimsi/gameyfin/igdb/IgdbWrapper.java index c4bc180..7903073 100644 --- a/backend/src/main/java/de/grimsi/gameyfin/igdb/IgdbWrapper.java +++ b/backend/src/main/java/de/grimsi/gameyfin/igdb/IgdbWrapper.java @@ -37,6 +37,12 @@ public class IgdbWrapper { @Value("${gameyfin.igdb.config.preferred-platforms:6}") private String preferredPlatforms; + @Value("${gameyfin.igdb.api.endpoints.base}") + private String igdbApiBaseUrl; + + @Value("${gameyfin.igdb.api.endpoints.auth}") + private String twitchAuthUrl; + private final WebClient.Builder webclientBuilder; private final WebClientConfig webClientConfig; private final GameMapper gameMapper; @@ -58,7 +64,8 @@ public class IgdbWrapper { log.info("Authenticating on Twitch API..."); URI url = UriComponentsBuilder - .fromHttpUrl("https://id.twitch.tv/oauth2/token?client_id={client_id}&client_secret={client_secret}&grant_type=client_credentials") + .fromHttpUrl(twitchAuthUrl) + .query("client_id={client_id}").query("client_secret={client_secret}").query("grant_type=client_credentials") .buildAndExpand(clientId, clientSecret) .toUri(); @@ -163,7 +170,7 @@ public class IgdbWrapper { } igdbApiClient = webclientBuilder - .baseUrl("https://api.igdb.com/v4/") + .baseUrl(igdbApiBaseUrl) .defaultHeader("Client-ID", clientId) .defaultHeader("Authorization", "Bearer %s".formatted(accessToken.getAccessToken())) .filter(WebClientConfig.fixProtobufContentTypeInterceptor()) diff --git a/backend/src/main/resources/config/gameyfin.yml b/backend/src/main/resources/config/gameyfin.yml index 1d7eef8..e82b5ac 100644 --- a/backend/src/main/resources/config/gameyfin.yml +++ b/backend/src/main/resources/config/gameyfin.yml @@ -4,6 +4,9 @@ gameyfin: file-extensions: iso, zip, rar, 7z, exe igdb: api: + endpoints: + auth: https://id.twitch.tv/oauth2/token + base: https://api.igdb.com/v4/ client-id: client-secret: max-concurrent-requests: 2 diff --git a/backend/src/test/java/de/grimsi/gameyfin/igdb/IgdbWrapperTest.java b/backend/src/test/java/de/grimsi/gameyfin/igdb/IgdbWrapperTest.java new file mode 100644 index 0000000..0b083db --- /dev/null +++ b/backend/src/test/java/de/grimsi/gameyfin/igdb/IgdbWrapperTest.java @@ -0,0 +1,60 @@ +package de.grimsi.gameyfin.igdb; + +import okhttp3.mockwebserver.MockWebServer; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; + +import java.io.IOException; + +import static org.junit.jupiter.api.Assertions.*; + +@SpringBootTest +class IgdbWrapperTest { + + private static final MockWebServer igdbApiMock = new MockWebServer(); + private static final MockWebServer twitchApiMock = new MockWebServer(); + + private IgdbWrapper target; + + @DynamicPropertySource + static void setupProperties(DynamicPropertyRegistry registry) { + registry.add("gameyfin.igdb.api.endpoints.base", () -> "http://localhost:%s".formatted(igdbApiMock.getPort())); + registry.add("gameyfin.igdb.api.endpoints.auth", () -> "http://localhost:%s".formatted(twitchApiMock.getPort())); + } + + @BeforeAll + static void setup() throws IOException { + igdbApiMock.start(); + twitchApiMock.start(); + } + + @AfterAll + static void tearDown() throws IOException { + igdbApiMock.shutdown(); + twitchApiMock.start(); + } + + @Test + void authenticate() { + } + + @Test + void getGameById() { + } + + @Test + void getGameBySlug() { + } + + @Test + void findPossibleMatchingTitles() { + } + + @Test + void searchForGameByTitle() { + } +} diff --git a/backend/src/test/java/de/grimsi/gameyfin/mapper/CompanyMapperTest.java b/backend/src/test/java/de/grimsi/gameyfin/mapper/CompanyMapperTest.java new file mode 100644 index 0000000..129c388 --- /dev/null +++ b/backend/src/test/java/de/grimsi/gameyfin/mapper/CompanyMapperTest.java @@ -0,0 +1,54 @@ +package de.grimsi.gameyfin.mapper; + +import com.igdb.proto.Igdb; +import de.grimsi.gameyfin.entities.Company; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; + +class CompanyMapperTest extends RandomMapperTest { + + @Test + @Disabled + void toCompany() { + Igdb.InvolvedCompany input = generateRandomInput(); + + Company output = CompanyMapper.toCompany(input); + + assertThat(output.getSlug()).isEqualTo(input.getCompany().getSlug()); + assertThat(output.getName()).isEqualTo(input.getCompany().getName()); + assertThat(output.getLogoId()).isEqualTo(input.getCompany().getLogo().getImageId()); + } + + @Test + @Disabled + void toCompanies() { + List input = List.of(generateRandomInput(), generateRandomInput(), generateRandomInput()); + + List output = CompanyMapper.toCompanies(input); + + for (int i = 0; i < output.size(); i++) { + assertThat(output.get(i).getSlug()).isEqualTo(input.get(i).getCompany().getSlug()); + assertThat(output.get(i).getName()).isEqualTo(input.get(i).getCompany().getName()); + assertThat(output.get(i).getLogoId()).isEqualTo(input.get(i).getCompany().getLogo().getImageId()); + } + } + + private static Igdb.InvolvedCompany generateRandomInvolvedCompany() { + Igdb.Company c = Igdb.Company.newBuilder() + .setSlug(UUID.randomUUID().toString()) + .setName(UUID.randomUUID().toString()) + .setLogo(Igdb.CompanyLogo.newBuilder() + .setImageId(UUID.randomUUID().toString()) + .build()) + .build(); + + return Igdb.InvolvedCompany.newBuilder() + .setCompany(c) + .build(); + } +} diff --git a/backend/src/test/java/de/grimsi/gameyfin/mapper/GenreMapperTest.java b/backend/src/test/java/de/grimsi/gameyfin/mapper/GenreMapperTest.java new file mode 100644 index 0000000..e60cab8 --- /dev/null +++ b/backend/src/test/java/de/grimsi/gameyfin/mapper/GenreMapperTest.java @@ -0,0 +1,37 @@ +package de.grimsi.gameyfin.mapper; + +import com.igdb.proto.Igdb; +import de.grimsi.gameyfin.entities.Genre; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +class GenreMapperTest extends RandomMapperTest { + + @Test + @Disabled + void toGenre() { + Igdb.Genre input = generateRandomInput(); + + Genre output = GenreMapper.toGenre(input); + + assertThat(output.getSlug()).isEqualTo(input.getSlug()); + assertThat(output.getName()).isEqualTo(input.getName()); + } + + @Test + @Disabled + void toGenres() { + List input = List.of(generateRandomInput(), generateRandomInput(), generateRandomInput()); + + List output = GenreMapper.toGenres(input); + + for (int i = 0; i < output.size(); i++) { + assertThat(output.get(i).getSlug()).isEqualTo(input.get(i).getSlug()); + assertThat(output.get(i).getName()).isEqualTo(input.get(i).getName()); + } + } +} diff --git a/backend/src/test/java/de/grimsi/gameyfin/mapper/RandomMapperTest.java b/backend/src/test/java/de/grimsi/gameyfin/mapper/RandomMapperTest.java new file mode 100644 index 0000000..172b853 --- /dev/null +++ b/backend/src/test/java/de/grimsi/gameyfin/mapper/RandomMapperTest.java @@ -0,0 +1,49 @@ +package de.grimsi.gameyfin.mapper; + +import com.google.protobuf.Message; +import org.jeasy.random.EasyRandom; +import org.jeasy.random.EasyRandomParameters; +import org.springframework.core.GenericTypeResolver; + +import java.util.List; + +public class RandomMapperTest { + + private static final int DEFAULT_COUNT = 5; + private final EasyRandom easyRandom = new EasyRandom(); + + private final Class inputClass; + private final Class outputClass; + + @SuppressWarnings("unchecked") + public RandomMapperTest() { + Class[] typeArguments = GenericTypeResolver.resolveTypeArguments(getClass(), RandomMapperTest.class); + assert typeArguments != null; + inputClass = (Class) typeArguments[0]; + outputClass = (Class) typeArguments[1]; + } + + protected Input generateRandomInput() { + return easyRandom.nextObject(inputClass); + } + + protected List generateRandomInputs() { + return easyRandom.objects(inputClass, DEFAULT_COUNT).toList(); + } + + protected List generateRandomInputs(int count) { + return easyRandom.objects(inputClass, count).toList(); + } + + protected Output generateRandomOutput() { + return easyRandom.nextObject(outputClass); + } + + protected List generateRandomOutputs() { + return easyRandom.objects(outputClass, DEFAULT_COUNT).toList(); + } + + protected List generateRandomOutputs(int count) { + return easyRandom.objects(outputClass, count).toList(); + } +} diff --git a/backend/src/test/resources/application-test.yml b/backend/src/test/resources/application-test.yml new file mode 100644 index 0000000..8702211 --- /dev/null +++ b/backend/src/test/resources/application-test.yml @@ -0,0 +1,7 @@ +gameyfin: + igdb: + api: + client-id: igdb_client_id + client-secret: igdb_client_secret + config: + preferred-platforms: 6 diff --git a/frontend/package-lock.json b/frontend/package-lock.json index ef089f2..0c909b5 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "frontend", - "version": "1.2.3-SNAPSHOT", + "version": "1.2.4-SNAPSHOT", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "frontend", - "version": "1.2.3-SNAPSHOT", + "version": "1.2.4-SNAPSHOT", "dependencies": { "@angular/animations": "^14.0.0", "@angular/cdk": "^14.1.0", diff --git a/frontend/package.json b/frontend/package.json index cf5b2db..6734fcf 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "frontend", - "version": "1.2.3-SNAPSHOT", + "version": "1.2.4-SNAPSHOT", "scripts": { "ng": "ng", "start": "ng serve",