diff --git a/configuration.md b/configuration.md index 8c4fbb5a0..10b4da809 100644 --- a/configuration.md +++ b/configuration.md @@ -17,7 +17,7 @@ | DATABASE_ADDRESS | | | `127.0.0.1` | | DATABASE_NAME | | | `faf` | | DATABASE_PASSWORD | | | `banana` | -| DATABASE_SCHEMA_VERSION | `124` | | | +| DATABASE_SCHEMA_VERSION | `135` | | | | DATABASE_USERNAME | | | `faf-java-api` | | EMAIL_FROM_ADDRESS | | | `faf@example.com` | | EMAIL_FROM_NAME | | | `FAForever` | diff --git a/src/inttest/java/com/faforever/api/config/MainDbTestContainers.java b/src/inttest/java/com/faforever/api/config/MainDbTestContainers.java index 7cb1be6bd..530c6009f 100644 --- a/src/inttest/java/com/faforever/api/config/MainDbTestContainers.java +++ b/src/inttest/java/com/faforever/api/config/MainDbTestContainers.java @@ -21,7 +21,7 @@ @Configuration public class MainDbTestContainers { private static final MariaDBContainer fafDBContainer = new MariaDBContainer<>("mariadb:10.6"); - private static final GenericContainer flywayMigrationsContainer = new GenericContainer<>("faforever/faf-db-migrations:v133"); + private static final GenericContainer flywayMigrationsContainer = new GenericContainer<>("faforever/faf-db-migrations:v135"); private static final Network sharedNetwork = Network.newNetwork(); @Bean diff --git a/src/inttest/java/com/faforever/api/data/MatchmakerQueueMapPoolElideTest.java b/src/inttest/java/com/faforever/api/data/MatchmakerQueueMapPoolElideTest.java new file mode 100644 index 000000000..65096d640 --- /dev/null +++ b/src/inttest/java/com/faforever/api/data/MatchmakerQueueMapPoolElideTest.java @@ -0,0 +1,153 @@ +package com.faforever.api.data; + +import com.faforever.api.AbstractIntegrationTest; +import com.faforever.api.data.domain.GroupPermission; +import com.faforever.api.security.OAuthScope; +import org.junit.jupiter.api.Test; +import org.springframework.http.HttpHeaders; +import org.springframework.test.context.jdbc.Sql; +import org.springframework.test.context.jdbc.Sql.ExecutionPhase; + +import static com.faforever.api.data.JsonApiMediaType.JSON_API_MEDIA_TYPE; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.is; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@Sql(executionPhase = ExecutionPhase.BEFORE_TEST_METHOD, scripts = "classpath:sql/truncateTables.sql") +@Sql(executionPhase = ExecutionPhase.BEFORE_TEST_METHOD, scripts = "classpath:sql/prepDefaultData.sql") +@Sql(executionPhase = ExecutionPhase.BEFORE_TEST_METHOD, scripts = "classpath:sql/prepMatchmakerQueueMapPoolData.sql") +public class MatchmakerQueueMapPoolElideTest extends AbstractIntegrationTest { + + private static final String genUpdateRequestForField(String fieldName, T fieldValue) { + if (fieldValue instanceof String) { + fieldValue = (T) ("\"" + fieldValue + "\""); + } + + return "{" + + " \"data\": { " + + " \"type\": \"matchmakerQueueMapPool\"," + + " \"id\": \"101\"," + + " \"attributes\": {" + + " \"" + fieldName + "\": " + fieldValue + "\n" + + " }" + + " }" + + "}"; + } + + @Test + public void canReadMatchmakerQueueMapPoolWithoutScopeAndRole() throws Exception { + mockMvc.perform(get("/data/matchmakerQueueMapPool") + .with(getOAuthTokenWithActiveUser(NO_SCOPE, NO_AUTHORITIES))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.data", hasSize(5))); + } + + @Test + public void canReadMatchmakerQueueMapPoolParamsWithoutScopeAndRole() throws Exception { + mockMvc.perform(get("/data/matchmakerQueueMapPool/101") + .with(getOAuthTokenWithActiveUser(NO_SCOPE, NO_AUTHORITIES))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.data.id", is("101"))) + .andExpect(jsonPath("$.data.type", is("matchmakerQueueMapPool"))) + .andExpect(jsonPath("$.data.attributes.maxRating", is(800.0))) + .andExpect(jsonPath("$.data.attributes.minRating", is(300.0))) + .andExpect(jsonPath("$.data.attributes.vetoTokensPerPlayer", is(1))) + .andExpect(jsonPath("$.data.attributes.minimumMapsAfterVeto", is(1.5))) + .andExpect(jsonPath("$.data.attributes.maxTokensPerMap", is(1))) + .andExpect(jsonPath("$.data.relationships.mapPool.data.id", is("2"))) + .andExpect(jsonPath("$.data.relationships.matchmakerQueue.data.id", is("1"))); + } + + @Test + public void cannotUpdateMatchmakerQueueMapPoolMinRatingWithoutScopeAndRole() throws Exception { + mockMvc.perform(patch("/data/matchmakerQueueMapPool/101") + .with(getOAuthTokenWithActiveUser(NO_SCOPE, NO_AUTHORITIES)) + .header(HttpHeaders.CONTENT_TYPE, JSON_API_MEDIA_TYPE) + .content(genUpdateRequestForField("minRating", 1000))) + .andExpect(status().isForbidden()); + } + + @Test + public void cannotUpdateMatchmakerQueueMapPoolMaxRatingWithoutScopeAndRole() throws Exception { + mockMvc.perform(patch("/data/matchmakerQueueMapPool/101") + .with(getOAuthTokenWithActiveUser(NO_SCOPE, NO_AUTHORITIES)) + .header(HttpHeaders.CONTENT_TYPE, JSON_API_MEDIA_TYPE) + .content(genUpdateRequestForField("maxRating", 1000))) + .andExpect(status().isForbidden()); + } + + @Test + public void cannotUpdateMatchmakerQueueMapPoolVetoTokensPerPlayerWithoutScopeAndRole() throws Exception { + mockMvc.perform(patch("/data/matchmakerQueueMapPool/101") + .with(getOAuthTokenWithActiveUser(NO_SCOPE, NO_AUTHORITIES)) + .header(HttpHeaders.CONTENT_TYPE, JSON_API_MEDIA_TYPE) + .content(genUpdateRequestForField("vetoTokensPerPlayer", 1))) + .andExpect(status().isForbidden()); + } + + @Test + public void cannotUpdateMatchmakerQueueMapPoolMaxTokensPerMapWithoutScopeAndRole() throws Exception { + mockMvc.perform(patch("/data/matchmakerQueueMapPool/101") + .with(getOAuthTokenWithActiveUser(NO_SCOPE, NO_AUTHORITIES)) + .header(HttpHeaders.CONTENT_TYPE, JSON_API_MEDIA_TYPE) + .content(genUpdateRequestForField("maxTokensPerMap", 2))) + .andExpect(status().isForbidden()); + } + + @Test + public void cannotUpdateMatchmakerQueueMapPoolMinimumMapsAfterVetoWithoutScopeAndRole() throws Exception { + mockMvc.perform(patch("/data/matchmakerQueueMapPool/101") + .with(getOAuthTokenWithActiveUser(NO_SCOPE, NO_AUTHORITIES)) + .header(HttpHeaders.CONTENT_TYPE, JSON_API_MEDIA_TYPE) + .content(genUpdateRequestForField("minimumMapsAfterVeto", 3.1))) + .andExpect(status().isForbidden()); + } + + @Test + public void canUpdateMatchmakerQueueMapPoolMinRatingWithScopeAndRole() throws Exception { + mockMvc.perform(patch("/data/matchmakerQueueMapPool/101") + .with(getOAuthTokenWithActiveUser(OAuthScope._ADMINISTRATIVE_ACTION, GroupPermission.ROLE_WRITE_MATCHMAKER_MAP)) + .header(HttpHeaders.CONTENT_TYPE, JSON_API_MEDIA_TYPE) + .content(genUpdateRequestForField("minRating", 1000))) + .andExpect(status().isNoContent()); + } + + @Test + public void canUpdateMatchmakerQueueMapPoolMaxRatingWithScopeAndRole() throws Exception { + mockMvc.perform(patch("/data/matchmakerQueueMapPool/101") + .with(getOAuthTokenWithActiveUser(OAuthScope._ADMINISTRATIVE_ACTION, GroupPermission.ROLE_WRITE_MATCHMAKER_MAP)) + .header(HttpHeaders.CONTENT_TYPE, JSON_API_MEDIA_TYPE) + .content(genUpdateRequestForField("maxRating", 1000))) + .andExpect(status().isNoContent()); + } + + @Test + public void canUpdateMatchmakerQueueMapPoolVetoTokensPerPlayerWithScopeAndRole() throws Exception { + mockMvc.perform(patch("/data/matchmakerQueueMapPool/101") + .with(getOAuthTokenWithActiveUser(OAuthScope._ADMINISTRATIVE_ACTION, GroupPermission.ROLE_WRITE_MATCHMAKER_MAP)) + .header(HttpHeaders.CONTENT_TYPE, JSON_API_MEDIA_TYPE) + .content(genUpdateRequestForField("vetoTokensPerPlayer", 1))) + .andExpect(status().isNoContent()); + } + + @Test + public void canUpdateMatchmakerQueueMapPoolMaxTokensPerMapWithScopeAndRole() throws Exception { + mockMvc.perform(patch("/data/matchmakerQueueMapPool/101") + .with(getOAuthTokenWithActiveUser(OAuthScope._ADMINISTRATIVE_ACTION, GroupPermission.ROLE_WRITE_MATCHMAKER_MAP)) + .header(HttpHeaders.CONTENT_TYPE, JSON_API_MEDIA_TYPE) + .content(genUpdateRequestForField("maxTokensPerMap", 2))) + .andExpect(status().isNoContent()); + } + + @Test + public void canUpdateMatchmakerQueueMapPoolMinimumMapsAfterVetoWithScopeAndRole() throws Exception { + mockMvc.perform(patch("/data/matchmakerQueueMapPool/101") + .with(getOAuthTokenWithActiveUser(OAuthScope._ADMINISTRATIVE_ACTION, GroupPermission.ROLE_WRITE_MATCHMAKER_MAP)) + .header(HttpHeaders.CONTENT_TYPE, JSON_API_MEDIA_TYPE) + .content(genUpdateRequestForField("minimumMapsAfterVeto", 3.1))) + .andExpect(status().isNoContent()); + } +} diff --git a/src/inttest/resources/sql/prepMapData.sql b/src/inttest/resources/sql/prepMapData.sql index 401d416a1..afabf4334 100644 --- a/src/inttest/resources/sql/prepMapData.sql +++ b/src/inttest/resources/sql/prepMapData.sql @@ -13,12 +13,12 @@ INSERT INTO map_pool (id, name) VALUES (4, 'Ladder 1v1 1300-1800'), (5, 'Ladder 1v1 1800+'); -INSERT INTO matchmaker_queue_map_pool (matchmaker_queue_id, map_pool_id, min_rating, max_rating) VALUES - (1, 1, null, 300), - (1, 2, 300, 800), - (1, 3, 800, 1300), - (1, 4, 1300, 1800), - (1, 5, 1800, null); +INSERT INTO matchmaker_queue_map_pool (matchmaker_queue_id, map_pool_id, min_rating, max_rating, veto_tokens_per_player, max_tokens_per_map, minimum_maps_after_veto) VALUES + (1, 1, null, 300,1,1,1), + (1, 2, 300, 800,1,1,1), + (1, 3, 800, 1300,1,1,1), + (1, 4, 1300, 1800,1,1,1), + (1, 5, 1800, null,1,1,1); INSERT INTO map_pool_map_version (id, map_pool_id, map_version_id, map_params, weight) VALUES (1, 1, 1, null, 1), diff --git a/src/inttest/resources/sql/prepMatchmakerQueueMapPoolData.sql b/src/inttest/resources/sql/prepMatchmakerQueueMapPoolData.sql new file mode 100644 index 000000000..19e94495d --- /dev/null +++ b/src/inttest/resources/sql/prepMatchmakerQueueMapPoolData.sql @@ -0,0 +1,13 @@ +INSERT INTO map_pool (id, name) VALUES + (1, 'Ladder 1v1 <300'), + (2, 'Ladder 1v1 300-800'), + (3, 'Ladder 1v1 800-1300'), + (4, 'Ladder 1v1 1300-1800'), + (5, 'Ladder 1v1 1800+'); + +INSERT INTO matchmaker_queue_map_pool (id, matchmaker_queue_id, map_pool_id, min_rating, max_rating, veto_tokens_per_player, max_tokens_per_map, minimum_maps_after_veto) VALUES + (100, 1, 1, null, 300,1,1,1), + (101, 1, 2, 300, 800,1,1,1.5), + (102, 1, 3, 800, 1300,1,1,1), + (103, 1, 4, 1300, 1800,1,1,1), + (104, 1, 5, 1800, null,1,1,1); diff --git a/src/main/java/com/faforever/api/data/domain/MatchmakerQueueMapPool.java b/src/main/java/com/faforever/api/data/domain/MatchmakerQueueMapPool.java index 59f2f532a..e43c597fd 100644 --- a/src/main/java/com/faforever/api/data/domain/MatchmakerQueueMapPool.java +++ b/src/main/java/com/faforever/api/data/domain/MatchmakerQueueMapPool.java @@ -30,6 +30,10 @@ public class MatchmakerQueueMapPool extends AbstractEntity