package com.faforever.client.api;
import com.faforever.client.leaderboard.Ranked1v1EntryBean;
import com.faforever.client.mod.ModInfoBean;
import com.faforever.client.mod.ModInfoBeanBuilder;
import com.faforever.client.preferences.PreferencesService;
import com.faforever.client.user.UserService;
import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.LowLevelHttpRequest;
import com.google.api.client.http.LowLevelHttpResponse;
import com.google.api.client.json.gson.GsonFactory;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
import org.mockito.stubbing.OngoingStubbing;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.mock.http.client.MockClientHttpRequest;
import org.springframework.mock.http.client.MockClientHttpResponse;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;
import static com.faforever.client.net.UriStartingWithMatcher.uriStartingWith;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.core.Is.is;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class FafApiAccessorImplTest {
@Rule
public TemporaryFolder preferencesDirectory = new TemporaryFolder();
private FafApiAccessorImpl instance;
@Mock
private PreferencesService preferencesService;
@Mock
private LowLevelHttpRequest httpRequest;
@Mock
private LowLevelHttpResponse lowLevelHttpResponse;
@Mock
private UserService userService;
@Mock
private ClientHttpRequestFactory clientHttpRequestFactory;
@Spy
private SpyableHttpTransport httpTransport;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
httpTransport.lowLevelHttpRequest = httpRequest;
instance = new FafApiAccessorImpl();
instance.preferencesService = preferencesService;
instance.baseUrl = "http://api.example.com";
instance.oAuthTokenServerUrl = "http://api.example.com/token";
instance.oAuthClientSecret = "123";
instance.oAuthClientId = "456";
instance.oAuthUrl = "http://api.example.com/oauth/authorize";
instance.oAuthLoginUrl = new URI("http://api.example.com/login");
instance.httpTransport = httpTransport;
instance.userService = userService;
instance.clientHttpRequestFactory = clientHttpRequestFactory;
instance.jsonFactory = new GsonFactory();
when(preferencesService.getPreferencesDirectory()).thenReturn(preferencesDirectory.getRoot().toPath());
when(lowLevelHttpResponse.getStatusCode()).thenReturn(200);
when(httpRequest.execute()).thenReturn(lowLevelHttpResponse);
instance.postConstruct();
}
@Test(expected = IllegalStateException.class)
public void testGetPlayerAchievementsUnauthorizedThrowsIse() throws Exception {
instance.getPlayerAchievements(123);
}
@Test
public void testGetPlayerAchievements() throws Exception {
instance.requestFactory = instance.httpTransport.createRequestFactory();
instance.credential = mock(Credential.class);
mockResponse("{'data': [" +
" {" +
" 'id': '1'," +
" 'attributes': {'achievement_id': '1-2-3'}" +
" }," +
" {" +
" 'id': '2'," +
" 'attributes': {'achievement_id': '2-3-4'}" +
" }" +
"]}");
PlayerAchievement playerAchievement1 = new PlayerAchievement();
playerAchievement1.setId("1");
playerAchievement1.setAchievementId("1-2-3");
PlayerAchievement playerAchievement2 = new PlayerAchievement();
playerAchievement2.setId("2");
playerAchievement2.setAchievementId("2-3-4");
List<PlayerAchievement> result = Arrays.asList(playerAchievement1, playerAchievement2);
assertThat(instance.getPlayerAchievements(123), is(result));
verify(httpTransport).buildRequest("GET", "http://api.example.com/players/123/achievements?page%5Bnumber%5D=1");
}
private void mockResponse(String... responses) throws IOException {
OngoingStubbing<InputStream> ongoingStubbing = when(lowLevelHttpResponse.getContent());
for (String string : responses) {
ongoingStubbing = ongoingStubbing.thenReturn(new ByteArrayInputStream(string.getBytes(UTF_8)));
}
}
@Test
public void testGetAchievementDefinitions() throws Exception {
instance.requestFactory = instance.httpTransport.createRequestFactory();
instance.credential = mock(Credential.class);
mockResponse("{'data': [" +
" {" +
" 'id': '1-2-3'," +
" 'attributes': {}" +
" }," +
" {" +
" 'id': '2-3-4'," +
" 'attributes': {}" +
" }" +
"]}");
AchievementDefinition achievementDefinition1 = new AchievementDefinition();
achievementDefinition1.setId("1-2-3");
AchievementDefinition achievementDefinition2 = new AchievementDefinition();
achievementDefinition2.setId("2-3-4");
List<AchievementDefinition> result = Arrays.asList(achievementDefinition1, achievementDefinition2);
assertThat(instance.getAchievementDefinitions(), is(result));
verify(httpTransport).buildRequest("GET", "http://api.example.com/achievements?sort=order&page%5Bnumber%5D=1");
}
@Test
public void testGetAchievementDefinition() throws Exception {
instance.requestFactory = instance.httpTransport.createRequestFactory();
instance.credential = mock(Credential.class);
AchievementDefinition achievementDefinition = new AchievementDefinition();
achievementDefinition.setId("1-2-3");
mockResponse("{'data': " +
" {" +
" 'id': '1-2-3'," +
" 'attributes': {}" +
" }" +
"}");
assertThat(instance.getAchievementDefinition("123"), is(achievementDefinition));
verify(httpTransport).buildRequest("GET", "http://api.example.com/achievements/123");
}
@Test
public void testAuthorize() throws Exception {
when(userService.getUsername()).thenReturn("junit");
when(userService.getPassword()).thenReturn("junit-password");
ClientHttpResponse loginResponse = new MockClientHttpResponse((byte[]) null, HttpStatus.FOUND);
loginResponse.getHeaders().add("Set-Cookie", "some cookies");
MockClientHttpRequest loginRequest = new MockClientHttpRequest();
loginRequest.setResponse(loginResponse);
when(clientHttpRequestFactory.createRequest(instance.oAuthLoginUrl, HttpMethod.POST)).thenReturn(loginRequest);
ClientHttpResponse authResponse = new MockClientHttpResponse((byte[]) null, HttpStatus.FOUND);
authResponse.getHeaders().setLocation(new URI("http://localhost:1111?code=1337"));
MockClientHttpRequest authRequest = new MockClientHttpRequest();
authRequest.setResponse(authResponse);
when(clientHttpRequestFactory.createRequest(uriStartingWith(instance.oAuthUrl), eq(HttpMethod.POST))).thenReturn(authRequest);
mockResponse("{}");
instance.authorize(123);
assertThat(instance.credential, notNullValue());
}
@Test
public void testGetPlayerEvents() throws Exception {
instance.requestFactory = instance.httpTransport.createRequestFactory();
instance.credential = mock(Credential.class);
mockResponse("{'data': [" +
" {" +
" 'id': '1'," +
" 'attributes': {'count': 11, 'event_id': '1-1-1' }" +
" }," +
" {" +
" 'id': '2'," +
" 'attributes': {'count': 22, 'event_id': '2-2-2' }" +
" }" +
"]}");
PlayerEvent playerEvent1 = new PlayerEvent();
playerEvent1.setId("1");
playerEvent1.setEventId("1-1-1");
playerEvent1.setCount(11);
PlayerEvent playerEvent2 = new PlayerEvent();
playerEvent2.setId("2");
playerEvent2.setEventId("2-2-2");
playerEvent2.setCount(22);
List<PlayerEvent> result = Arrays.asList(playerEvent1, playerEvent2);
assertThat(instance.getPlayerEvents(123), is(result));
verify(httpTransport).buildRequest("GET", "http://api.example.com/players/123/events?page%5Bnumber%5D=1");
}
@Test
public void testGetMods() throws Exception {
instance.requestFactory = instance.httpTransport.createRequestFactory();
instance.credential = mock(Credential.class);
mockResponse("{'data': [" +
" {" +
" 'id': '1'," +
" 'attributes': {" +
" 'create_time': '2011-12-03T10:15:30'," +
" 'download_url': 'http://example.com/mod1.zip'" +
" }" +
" }," +
" {" +
" 'id': '2'," +
" 'attributes': {" +
" 'create_time': '2011-12-03T10:15:30'," +
" 'download_url': 'http://example.com/mod2.zip'" +
" }" +
" }" +
"]}",
"{'data': []}");
List<ModInfoBean> result = Arrays.asList(
ModInfoBeanBuilder.create().defaultValues().uid("1").get(),
ModInfoBeanBuilder.create().defaultValues().uid("2").get()
);
assertThat(instance.getMods(), equalTo(result));
verify(httpTransport).buildRequest("GET", "http://api.example.com/mods?page%5Bnumber%5D=1");
verify(httpTransport).buildRequest("GET", "http://api.example.com/mods?page%5Bnumber%5D=2");
}
@Test
public void testGetRanked1v1Entries() throws Exception {
instance.requestFactory = instance.httpTransport.createRequestFactory();
instance.credential = mock(Credential.class);
mockResponse("{'data': [" +
" {" +
" 'id': '1'," +
" 'attributes': {" +
" 'login': 'user1'," +
" 'num_games': 5" +
" }" +
" }," +
" {" +
" 'id': '2'," +
" 'attributes': {" +
" 'login': 'user2'," +
" 'num_games': 3" +
" }" +
" }" +
"]}",
"{'data': []}");
List<Ranked1v1EntryBean> result = Arrays.asList(
Ranked1v1EntryBeanBuilder.create().defaultValues().username("user1").get(),
Ranked1v1EntryBeanBuilder.create().defaultValues().username("user2").get()
);
assertThat(instance.getRanked1v1Entries(), equalTo(result));
verify(httpTransport).buildRequest("GET", "http://api.example.com/leaderboards/1v1?page%5Bnumber%5D=1");
verify(httpTransport).buildRequest("GET", "http://api.example.com/leaderboards/1v1?page%5Bnumber%5D=2");
}
@Test
public void testGetRanked1v1Stats() throws Exception {
instance.requestFactory = instance.httpTransport.createRequestFactory();
instance.credential = mock(Credential.class);
mockResponse("{'data': [" +
" {" +
" 'id': '/leaderboards/1v1/stats'," +
" 'attributes': {" +
" '100': 1," +
" '1200': 5," +
" '1400': 5" +
" }" +
" }" +
"]}",
"{'data': []}");
Ranked1v1Stats ranked1v1Stats = new Ranked1v1Stats();
ranked1v1Stats.setId("/leaderboards/1v1/stats");
assertThat(instance.getRanked1v1Stats(), equalTo(ranked1v1Stats));
verify(httpTransport).buildRequest("GET", "http://api.example.com/leaderboards/1v1/stats");
}
@Test
public void testGetRanked1v1EntryForPlayer() throws Exception {
instance.requestFactory = instance.httpTransport.createRequestFactory();
instance.credential = mock(Credential.class);
mockResponse("{'data': [" +
" {" +
" 'id': '2'," +
" 'attributes': {" +
" 'login': 'user1'," +
" 'num_games': 3" +
" }" +
" }" +
"]}",
"{'data': []}");
Ranked1v1EntryBean entry = Ranked1v1EntryBeanBuilder.create().defaultValues().username("user1").get();
assertThat(instance.getRanked1v1EntryForPlayer(123), equalTo(entry));
verify(httpTransport).buildRequest("GET", "http://api.example.com/leaderboards/1v1/123");
}
@Test
public void testGetRatingHistoryGlobal() throws Exception {
instance.requestFactory = instance.httpTransport.createRequestFactory();
instance.credential = mock(Credential.class);
mockResponse("{" +
" 'data': {" +
" 'attributes': {" +
" 'history': {" +
" '1469921413': [1026.62, 49.4094]," +
" '1469989967': [1024.01, 49.4545]," +
" '1470842200': [1020.65, 50.1963]" +
" }" +
" }," +
" 'id': '21447'," +
" 'type': 'leaderboard_history'" +
" }" +
"}",
"{'data': []}");
History ratingHistory = instance.getRatingHistory(RatingType.GLOBAL, 123);
verify(httpTransport).buildRequest("GET", "http://api.example.com/players/123/ratings/global/history");
assertThat(ratingHistory.getData().values(), hasSize(3));
assertThat(ratingHistory.getData().get("1469921413").get(0), is(1026.62f));
assertThat(ratingHistory.getData().get("1469921413").get(1), is(49.4094f));
}
@Test
public void testGetRatingHistory1v1() throws Exception {
instance.requestFactory = instance.httpTransport.createRequestFactory();
instance.credential = mock(Credential.class);
mockResponse("{" +
" 'data': {" +
" 'attributes': {" +
" 'history': {" +
" '1469921413': [1026.62, 49.4094]," +
" '1469989967': [1024.01, 49.4545]," +
" '1470842200': [1020.65, 50.1963]" +
" }" +
" }," +
" 'id': '21447'," +
" 'type': 'leaderboard_history'" +
" }" +
"}",
"{'data': []}");
History ratingHistory = instance.getRatingHistory(RatingType.LADDER_1V1, 123);
verify(httpTransport).buildRequest("GET", "http://api.example.com/players/123/ratings/1v1/history");
assertThat(ratingHistory.getData().values(), hasSize(3));
assertThat(ratingHistory.getData().get("1469921413").get(0), is(1026.62f));
assertThat(ratingHistory.getData().get("1469921413").get(1), is(49.4094f));
}
@Test
public void testUploadMod() throws Exception {
instance.requestFactory = instance.httpTransport.createRequestFactory();
instance.credential = mock(Credential.class);
Path file = Files.createTempFile("foo", null);
// FIXME filename
instance.uploadMod(file, (written, total) -> {
});
verify(httpTransport).buildRequest("POST", "http://api.example.com/mods/upload");
}
private static class SpyableHttpTransport extends HttpTransport {
LowLevelHttpRequest lowLevelHttpRequest;
@Override
public LowLevelHttpRequest buildRequest(String method, String url) throws IOException {
return lowLevelHttpRequest;
}
}
}