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
52 changes: 29 additions & 23 deletions src/main/java/se/michaelthelin/spotify/Base64.java
Original file line number Diff line number Diff line change
@@ -1,18 +1,38 @@
package se.michaelthelin.spotify;

import java.io.ByteArrayOutputStream;
import java.util.Arrays;

/**
* Source: https://gist.github.com/EmilHernvall/953733#file-base64-java
* Due to Java version support issues with Datatypeconverter (<=1.7) class and Base64 (>=1.8) class.
* Source: <a href="https://gist.github.com/EmilHernvall/953733#file-base64-java">EmilHernvall/Base64.java</a>
* Due to Java version support issues with DataTypeConverter (&lt;=1.7) class and Base64 (&gt;=1.8) class.
*/
public class Base64 {
private static final char[] ENCODE_TABLE_BASE = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};

private static final int[] DECODE_TABLE_BASE = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54,
55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2,
3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30,
31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};

public static String encode(byte[] data) {
char[] tbl = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
char[] tbl = Arrays.copyOf(ENCODE_TABLE_BASE, ENCODE_TABLE_BASE.length);

StringBuilder buffer = new StringBuilder();
int pad = 0;
Expand Down Expand Up @@ -44,22 +64,8 @@ public static String encode(byte[] data) {
}

public static byte[] decode(String data) {
int[] tbl = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54,
55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2,
3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30,
31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
int[] tbl = Arrays.copyOf(DECODE_TABLE_BASE, DECODE_TABLE_BASE.length);

byte[] bytes = data.getBytes();
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
for (int i = 0; i < bytes.length; ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,8 @@ public boolean retryRequest(
final IOException exception,
final int execCount,
final HttpContext context) {
Args.notNull(request, "request");
Args.notNull(exception, "exception");
Objects.requireNonNull(request, "request");
Objects.requireNonNull(exception, "exception");

if (execCount > this.maxRetries) {
// Do not retry if over max retries
Expand Down Expand Up @@ -178,7 +178,7 @@ public boolean retryRequest(
final HttpResponse response,
final int execCount,
final HttpContext context) {
Args.notNull(response, "response");
Objects.requireNonNull(response, "response");

return execCount <= this.maxRetries && retriableCodes.contains(response.getCode());
}
Expand All @@ -188,7 +188,7 @@ public TimeValue getRetryInterval(
final HttpResponse response,
final int execCount,
final HttpContext context) {
Args.notNull(response, "response");
Objects.requireNonNull(response, "response");

return this.defaultRetryInterval;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,37 +17,37 @@ public interface IPlaylistItem extends IModelObject {
*
* @return The playlist item length in milliseconds.
*/
public Integer getDurationMs();
Integer getDurationMs();

/**
* Get the external URLs of the playlist item.<br>
* Example: Spotify-URL.
*
* @return Known external URLs for this playlist item.
*/
public ExternalUrl getExternalUrls();
ExternalUrl getExternalUrls();

/**
* Get the full Spotify Web API endpoint URL of the playlist item.
*
* @return A link to the Web API endpoint providing full details of the playlist item.
*/
public String getHref();
String getHref();

/**
* Get the <a href="https://developer.spotify.com/documentation/web-api/concepts/spotify-uris-ids">Spotify ID</a> of the
* playlist item.
*
* @return The Spotify ID for the playlist item.
*/
public String getId();
String getId();

/**
* Get the name of the playlist item.
*
* @return playlist item name.
*/
public String getName();
String getName();

/**
* Get the type of the IPlaylistItem.
Expand All @@ -63,5 +63,5 @@ public interface IPlaylistItem extends IModelObject {
* @return The <a href="https://developer.spotify.com/documentation/web-api/concepts/spotify-uris-ids">Spotify URI</a> for
* the playlist item.
*/
public String getUri();
String getUri();
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import se.michaelthelin.spotify.model_objects.specification.Track;

public class PlaylistItemFactory {
private static final JsonUtil jsonUtil = new JsonUtil() {
private static final JsonUtil<?> jsonUtil = new JsonUtil<>() {
@Override
public Object createModelObject(JsonObject jsonObject) {
return null;
Expand Down
20 changes: 20 additions & 0 deletions src/test/java/se/michaelthelin/spotify/Base64Test.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package se.michaelthelin.spotify;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

public class Base64Test {
private static final String BASE_64_TEST_DATA = "Hello World";
private static final String BASE_64_TEST_DATA_ENCODED = "SGVsbG8gV29ybGQ=";

@Test
public void testCustomBase64() {
byte[] testDataBytes = BASE_64_TEST_DATA.getBytes();

String encoded = Base64.encode(testDataBytes);
Assertions.assertEquals(BASE_64_TEST_DATA_ENCODED, encoded);

byte[] decoded = Base64.decode(encoded);
Assertions.assertArrayEquals(testDataBytes, decoded);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ public void testRetryAfterHeaderAsDate() {
final HttpResponse response = new BasicHttpResponse(503, "Oopsie");
response.setHeader(HttpHeaders.RETRY_AFTER, DateUtils.formatStandardDate(Instant.now().plus(100, ChronoUnit.SECONDS)));

Assertions.assertTrue(this.retryStrategy.getRetryInterval(response, 3, null).compareTo(TimeValue.ZERO_MILLISECONDS) == 0);
Assertions.assertEquals(0, this.retryStrategy.getRetryInterval(response, 3, null).compareTo(TimeValue.ZERO_MILLISECONDS));
}

@Test
Expand Down
3 changes: 2 additions & 1 deletion src/test/java/se/michaelthelin/spotify/TestUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import java.io.*;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.logging.Level;

import static org.mockito.ArgumentMatchers.nullable;
Expand All @@ -21,7 +22,7 @@ private static String readTestData(String fileName) throws IOException {
}

private static String readFromFile(File file) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8));
BufferedReader in = new BufferedReader(new InputStreamReader(Files.newInputStream(file.toPath()), StandardCharsets.UTF_8));
StringBuilder out = new StringBuilder();
String line;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,28 @@
package se.michaelthelin.spotify.requests.data.playlists;

import com.github.tomakehurst.wiremock.junit5.WireMockTest;
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
import static com.github.tomakehurst.wiremock.client.WireMock.get;
import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.fail;

import java.io.IOException;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import org.apache.hc.core5.http.ParseException;
import org.junit.jupiter.api.Test;

import com.github.tomakehurst.wiremock.junit5.WireMockTest;

import se.michaelthelin.spotify.ITest;
import se.michaelthelin.spotify.SpotifyApi;
import se.michaelthelin.spotify.SpotifyHttpManager;
Expand All @@ -13,12 +33,6 @@
import se.michaelthelin.spotify.model_objects.specification.Playlist;
import se.michaelthelin.spotify.requests.data.AbstractDataTest;

import java.io.IOException;
import java.util.concurrent.*;

import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static org.junit.jupiter.api.Assertions.*;

@WireMockTest(httpPort = 9090)
public class GetPlaylistRequestTest extends AbstractDataTest<Playlist> {
private final GetPlaylistRequest defaultRequest = ITest.SPOTIFY_API
Expand All @@ -35,7 +49,7 @@ public GetPlaylistRequestTest() throws Exception {
}

@Test
public void shouldThrowTooManyRequestExceptionAndNotBlockThread_WhenSpotifyReturns429() throws IOException, ParseException, SpotifyWebApiException {
public void shouldThrowTooManyRequestExceptionAndNotBlockThread_WhenSpotifyReturns429() {
SpotifyApi spotifyApi = new SpotifyApi.Builder()
.setScheme("http")
.setHost("localhost")
Expand All @@ -62,7 +76,7 @@ public void shouldThrowTooManyRequestExceptionAndNotBlockThread_WhenSpotifyRetur

try {
Future<Playlist> submit = executor.submit(playlistCall);
Playlist playlist = submit.get(10, TimeUnit.SECONDS);
submit.get(10, TimeUnit.SECONDS);
} catch (ExecutionException e) {
assertEquals(e.getCause().getClass(), TooManyRequestsException.class);
} catch (TimeoutException | InterruptedException e) {
Expand Down