Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
- Update to okhttp `5.3.2`

## [4.3.2]
- Remove `followers` property from `PlaylistUser` object
Expand Down
12 changes: 3 additions & 9 deletions spotify-web-api-java/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<url>https://github.com/sonallux/spotify-web-api-java</url>

<properties>
<okhttp.version>4.12.0</okhttp.version>
<okhttp.version>5.3.2</okhttp.version>
<jackson.version>2.20.1</jackson.version>

<moditect.module.name>de.sonallux.spotify.api</moditect.module.name>
Expand Down Expand Up @@ -48,7 +48,7 @@
<dependencies>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<artifactId>okhttp-jvm</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
Expand Down Expand Up @@ -78,14 +78,8 @@
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>mockwebserver</artifactId>
<artifactId>mockwebserver3</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

import de.sonallux.spotify.api.models.Episode;
import de.sonallux.spotify.api.models.Track;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import mockwebserver3.MockWebServer;
import mockwebserver3.MockResponse;
import okio.Buffer;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
Expand All @@ -29,7 +29,7 @@ void setup() throws IOException {

@AfterEach
void teardown() throws IOException{
webServer.shutdown();
webServer.close();
}

@Test
Expand All @@ -44,13 +44,13 @@ void testResponseSnakeCaseToCamelCase() throws Exception {
var firstTrack = playlist.getTracks().getItems().get(0);
assertNotNull(firstTrack);
assertEquals(Instant.parse("2021-03-07T23:01:00Z"), firstTrack.getAddedAt());
assertTrue(firstTrack.getTrack() instanceof Track);
assertInstanceOf(Track.class, firstTrack.getTrack());
assertEquals(6, ((Track) firstTrack.getTrack()).getTrackNumber());
}

@Test
void testRequestWithReservedKeyWord() throws Exception {
webServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 OK"));
webServer.enqueue(mockResponse(200).build());

var response = api.getPlaylistsApi().changePlaylistDetails("foo")
.name("Test")
Expand All @@ -61,35 +61,35 @@ void testRequestWithReservedKeyWord() throws Exception {
assertTrue(response.isSuccessful());

var request = webServer.takeRequest();
assertEquals("application/json; charset=UTF-8", request.getHeader("Content-Type"));
var actualBody = request.getBody().readUtf8();
assertEquals("application/json; charset=UTF-8", request.getHeaders().get("Content-Type"));
var actualBody = request.getBody().utf8();
assertEquals("{\"name\":\"Test\",\"collaborative\":false,\"description\":\"Test description\",\"public\":true}", actualBody);
}

@Test
void testRequestWithEmptyBodyObject() throws Exception {
webServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 OK"));
webServer.enqueue(mockResponse(200).build());

var response = api.getPlaylistsApi().changePlaylistDetails("foo").build().executeCall();
assertTrue(response.isSuccessful());

var request = webServer.takeRequest();
var actualBody = request.getBody().readUtf8();
var actualBody = request.getBody().utf8();
assertEquals("", actualBody);
}

@Test
void testRequestWithSnakeCaseToCamelCase() throws Exception {
webServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 OK").setBody("{\"snapshot_id\":\"12ab34cd\"}"));
webServer.enqueue(mockResponse(200).body("{\"snapshot_id\":\"12ab34cd\"}").build());

var newSnapshotId = api.getPlaylistsApi().removeTracksPlaylist("foo", List.of())
.snapshotId("ab12cd34")
.build().execute();
assertEquals("12ab34cd", newSnapshotId.getSnapshotId());

var request = webServer.takeRequest();
assertEquals("application/json; charset=UTF-8", request.getHeader("Content-Type"));
var actualBody = request.getBody().readUtf8();
assertEquals("application/json; charset=UTF-8", request.getHeaders().get("Content-Type"));
var actualBody = request.getBody().utf8();
assertEquals("{\"tracks\":[],\"snapshot_id\":\"ab12cd34\"}", actualBody);
}

Expand All @@ -101,16 +101,17 @@ void testUnionTypeHandlingWithAdditionalTypesParameter() throws Exception {
var track = response.getItems().get(0).getTrack();
assertNotNull(track);
assertEquals("track", track.getType());
assertTrue(track instanceof Track);
assertInstanceOf(Track.class, track);

var episode = response.getItems().get(1).getTrack();
assertNotNull(episode);
assertEquals("episode", episode.getType());
assertTrue(episode instanceof Episode);
assertInstanceOf(Episode.class, episode);
assertNotNull(((Episode) episode).getShow());

var request = webServer.takeRequest();
assertEquals("/playlists/foo/tracks?additional_types=track%2Cepisode", request.getPath());
assertEquals("/playlists/foo/tracks", request.getUrl().encodedPath());
assertEquals("additional_types=track%2Cepisode", request.getUrl().encodedQuery());
}

@Test
Expand All @@ -123,21 +124,22 @@ void testUnionTypeHandlingWithoutAdditionalTypesParameter() throws Exception {
var track = response.getItems().get(0).getTrack();
assertNotNull(track);
assertEquals("track", track.getType());
assertTrue(track instanceof Track);
assertInstanceOf(Track.class, track);

var episode = response.getItems().get(1).getTrack();
assertNotNull(episode);
assertEquals("episode", episode.getType());
assertTrue(episode instanceof Episode);
assertInstanceOf(Episode.class, episode);
assertNull(((Episode) episode).getShow());//show is not set, because episode is returned with track format

var request = webServer.takeRequest();
assertEquals("/playlists/foo/tracks?additional_types=track", request.getPath());
assertEquals("/playlists/foo/tracks", request.getUrl().encodedPath());
assertEquals("additional_types=track", request.getUrl().encodedQuery());
}

@Test
void testEmptyResponseBodyWithNonVoidType() throws Exception {
webServer.enqueue(new MockResponse().setStatus("HTTP/1.1 204 NO CONTENT"));
webServer.enqueue(mockResponse(204).build());

var response = api.getPlayerApi().getRecentlyPlayed().build().executeCall();
assertTrue(response.isSuccessful());
Expand All @@ -147,9 +149,13 @@ void testEmptyResponseBodyWithNonVoidType() throws Exception {
private MockResponse loadMockResponse(String fileName) throws Exception {
var stream = ConversionTest.class.getResourceAsStream("/responses/" + fileName);
var buffer = new Buffer().readFrom(stream);
return new MockResponse()
.setStatus("HTTP/1.1 200 OK")
return mockResponse(200)
.addHeader("Content-Type", "application/json; charset=utf-8")
.setBody(buffer);
.body(buffer)
.build();
}

private MockResponse.Builder mockResponse(int status) {
return new MockResponse.Builder().code(status);
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package de.sonallux.spotify.api;

import de.sonallux.spotify.api.authorization.ApiAuthorizationProvider;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import mockwebserver3.MockResponse;
import mockwebserver3.MockWebServer;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -33,7 +33,7 @@ void setup() throws IOException {

@AfterEach
void teardown() throws IOException{
webServer.shutdown();
webServer.close();
}

@Test
Expand All @@ -46,10 +46,10 @@ void addNoAuthorizationHeaderToRequest() throws Exception {
assertEquals("0OdUWJ0sBjDrqHygGUXeCF", artist.getId());
assertEquals("https://open.spotify.com/artist/0OdUWJ0sBjDrqHygGUXeCF", artist.getExternalUrls().getSpotify());

assertEquals(webServer.getRequestCount(), 1);
assertEquals(1, webServer.getRequestCount());
var request = webServer.takeRequest();
assertEquals(request.getRequestLine(), "GET /artists/foo HTTP/1.1");
assertNull(request.getHeader("Authorization"));
assertEquals("GET /artists/foo HTTP/1.1", request.getRequestLine());
assertNull(request.getHeaders().get("Authorization"));
}

@Test
Expand All @@ -62,10 +62,10 @@ void addAuthorizationHeaderToRequest() throws Exception {
assertEquals("0OdUWJ0sBjDrqHygGUXeCF", artist.getId());
assertEquals("https://open.spotify.com/artist/0OdUWJ0sBjDrqHygGUXeCF", artist.getExternalUrls().getSpotify());

assertEquals(webServer.getRequestCount(), 1);
assertEquals(1, webServer.getRequestCount());
var request = webServer.takeRequest();
assertEquals(request.getRequestLine(), "GET /artists/foo HTTP/1.1");
assertEquals(request.getHeader("Authorization"), "Bearer some-access-token");
assertEquals("GET /artists/foo HTTP/1.1", request.getRequestLine());
assertEquals("Bearer some-access-token", request.getHeaders().get("Authorization"));
}

@Test
Expand All @@ -81,11 +81,11 @@ void handlesUnauthorizedResponseWithRetry() throws Exception {

verify(apiAuthorizationProvider, times(1)).refreshAccessToken();

assertEquals(webServer.getRequestCount(), 2);
assertEquals(2, webServer.getRequestCount());
var request1 = webServer.takeRequest();
assertEquals(request1.getRequestLine(), "GET /artists/foo HTTP/1.1");
assertEquals("GET /artists/foo HTTP/1.1", request1.getRequestLine());
var request2 = webServer.takeRequest();
assertEquals(request2.getRequestLine(), "GET /artists/foo HTTP/1.1");
assertEquals("GET /artists/foo HTTP/1.1", request2.getRequestLine());
}

@Test
Expand All @@ -98,18 +98,19 @@ void handlesUnauthorizedResponseWithFailure() throws Exception {

verify(apiAuthorizationProvider, times(1)).refreshAccessToken();

assertEquals(webServer.getRequestCount(), 1);
assertEquals(1, webServer.getRequestCount());
var request1 = webServer.takeRequest();
assertEquals(request1.getRequestLine(), "GET /artists/foo HTTP/1.1");
assertEquals("GET /artists/foo HTTP/1.1", request1.getRequestLine());
}

private final MockResponse mockResponseUnauthorizedInvalidToken = new MockResponse()
.setStatus("HTTP/1.1 401 Unauthorized")
.setBody("{\"error\": {\"status\": 401,\"message\": \"Invalid access token\"}}");
private final MockResponse mockResponseUnauthorizedInvalidToken = new MockResponse.Builder()
.code(401)
.body("{\"error\": {\"status\": 401,\"message\": \"Invalid access token\"}}")
.build();

private final MockResponse mockResponseArtist = new MockResponse()
.setStatus("HTTP/1.1 200 OK")
.setBody("{\n" +
private final MockResponse mockResponseArtist = new MockResponse.Builder()
.code(200)
.body("{\n" +
" \"external_urls\" : {\n" +
" \"spotify\" : \"https://open.spotify.com/artist/0OdUWJ0sBjDrqHygGUXeCF\"\n" +
" },\n" +
Expand All @@ -133,5 +134,6 @@ void handlesUnauthorizedResponseWithFailure() throws Exception {
" \"popularity\" : 59,\n" +
" \"type\" : \"artist\",\n" +
" \"uri\" : \"spotify:artist:0OdUWJ0sBjDrqHygGUXeCF\"\n" +
"}");
"}")
.build();
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package de.sonallux.spotify.api.authorization.authorization_code;

import de.sonallux.spotify.api.authorization.*;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import okhttp3.mockwebserver.RecordedRequest;
import mockwebserver3.MockResponse;
import mockwebserver3.MockWebServer;
import mockwebserver3.RecordedRequest;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -36,7 +36,7 @@ void setup() throws IOException {

@AfterEach
void teardown() throws IOException{
webServer.shutdown();
webServer.close();
}

@Test
Expand Down Expand Up @@ -167,10 +167,10 @@ void refreshAccessTokenWithoutTokenTest() {

private void assertAuthTokensRequest(RecordedRequest request, String requestBody) {
assertEquals("POST", request.getMethod());
assertEquals("/api/token", request.getPath());
assertEquals("Basic MWEyYjNjNGQ1ZTZmNzpiYXI0NTY=", request.getHeader("Authorization"));
assertEquals("application/x-www-form-urlencoded", request.getHeader("Content-Type"));
assertEquals(requestBody, request.getBody().readUtf8());
assertEquals("/api/token", request.getUrl().encodedPath());
assertEquals("Basic MWEyYjNjNGQ1ZTZmNzpiYXI0NTY=", request.getHeaders().get("Authorization"));
assertEquals("application/x-www-form-urlencoded", request.getHeaders().get("Content-Type"));
assertEquals(requestBody, request.getBody().utf8());
}

private void assertStoreAuthTokensFromResponse() {
Expand All @@ -184,16 +184,18 @@ private void assertStoreAuthTokensFromResponse() {
}));
}

private final MockResponse mockResponseAuthTokens = new MockResponse()
.setStatus("HTTP/1.1 200 OK")
.setBody("{\n" +
private final MockResponse mockResponseAuthTokens = new MockResponse.Builder()
.code(200)
.body("{\n" +
" \"access_token\": \"NgA6ZcYIixn8bU\",\n" +
" \"token_type\": \"Bearer\",\n" +
" \"scope\": \"user-read-private user-read-email\",\n" +
" \"expires_in\": 3600\n" +
"}");
"}")
.build();

private final MockResponse mockResponseBadRequestAuthTokens = new MockResponse()
.setStatus("HTTP/1.1 400 Bad Request")
.setBody("{\"error\":\"invalid_client\",\"error_description\":\"Invalid client\"}");
private final MockResponse mockResponseBadRequestAuthTokens = new MockResponse.Builder()
.code(4)
.body("{\"error\":\"invalid_client\",\"error_description\":\"Invalid client\"}")
.build();
}
Loading