mirror of
https://github.com/airsonic/airsonic.git
synced 2025-10-03 09:49:17 +02:00
Refactor stream integration test
Signed-off-by: Andrew DeMaria <lostonamountain@gmail.com>
This commit is contained in:
parent
eea9416fbe
commit
10e90beb30
5 changed files with 137 additions and 36 deletions
|
@ -2,9 +2,12 @@ package org.airsonic.test.cucumber.steps.api;
|
|||
|
||||
import cucumber.api.java8.En;
|
||||
import org.airsonic.test.cucumber.server.AirsonicServer;
|
||||
import org.airsonic.test.domain.SavedHttpResponse;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.io.HexDump;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.HeaderElement;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.RequestBuilder;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
|
@ -14,56 +17,117 @@ import org.junit.Assert;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class StreamStepDef implements En {
|
||||
|
||||
private CloseableHttpResponse response;
|
||||
private CloseableHttpClient client;
|
||||
private boolean closed = false;
|
||||
private byte[] body;
|
||||
private List<SavedHttpResponse> responses = new ArrayList<>();
|
||||
private String streamName;
|
||||
|
||||
public StreamStepDef(AirsonicServer server) {
|
||||
this.client = HttpClientBuilder.create().build();
|
||||
Given("Media file (.*) is added", (String mediaFile) -> {
|
||||
// TODO fix this
|
||||
Given("Media file (.*) is added", (String streamName) -> {
|
||||
this.streamName = streamName;
|
||||
server.uploadToDefaultMusicFolder(
|
||||
Paths.get(this.getClass().getResource("/blobs/stream/piano").toURI()),
|
||||
Paths.get(this.getClass().getResource("/blobs/stream/" + streamName).toURI()),
|
||||
"");
|
||||
});
|
||||
|
||||
When("A stream request is sent", () -> {
|
||||
Then("The response bytes are equal", () -> {
|
||||
for (int i = 0; i < responses.size(); i++) {
|
||||
checkBody(responses.get(i), i);
|
||||
}
|
||||
});
|
||||
Then("^Print debug output$", () -> {
|
||||
for (int i = 0; i < responses.size(); i++) {
|
||||
System.out.printf("Response %d%n", i + 1);
|
||||
printDebugInfo(responses.get(i), 2);
|
||||
}
|
||||
});
|
||||
Then("^The length headers are correct$", () -> {
|
||||
responses.forEach(this::checkLengths);
|
||||
});
|
||||
When("^A stream is consumed$", () -> {
|
||||
while(shouldDoRequest()) {
|
||||
responses.add(consumeResponse(doRequest(server)));
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private void checkBody(SavedHttpResponse savedHttpResponse, int iter) throws URISyntaxException, IOException {
|
||||
String expectedBodyResource = String.format("/blobs/stream/"+streamName+"/responses/%d.dat", iter+1);
|
||||
byte[] expected = IOUtils.toByteArray(
|
||||
this.getClass()
|
||||
.getResource(expectedBodyResource)
|
||||
.toURI());
|
||||
// TODO if debug...
|
||||
// FileUtils.writeByteArrayToFile(
|
||||
// new File(String.format("/tmp/bytearray-%d", iter+1)),
|
||||
// savedHttpResponse.getBody());
|
||||
// HexDump.dump(expected, 0, System.out, 0);
|
||||
|
||||
Assert.assertArrayEquals(expected, savedHttpResponse.getBody());
|
||||
|
||||
}
|
||||
|
||||
private void printDebugInfo(SavedHttpResponse savedHttpResponse, int indentLevel) {
|
||||
String indent = StringUtils.repeat(' ', indentLevel);
|
||||
System.out.println(indent + "Headers:");
|
||||
for (Header header : savedHttpResponse.getHeaders()) {
|
||||
System.out.print(indent + header.getName());
|
||||
System.out.print(": ");
|
||||
for (HeaderElement element : header.getElements()) {
|
||||
System.out.print(element);
|
||||
System.out.print(", ");
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
|
||||
private void checkLengths(SavedHttpResponse response) {
|
||||
Header header = response.getHeader("Content-Length");
|
||||
Assert.assertEquals(response.getBody().length, Integer.parseInt(header.getValue()));
|
||||
}
|
||||
|
||||
private boolean shouldDoRequest() {
|
||||
return responses.isEmpty() || isUnconsumedContent(responses.get(responses.size() - 1));
|
||||
}
|
||||
|
||||
private Pattern CONTENT_RANGE_PATTERN = Pattern.compile("^bytes (\\d+)-(\\d+)/(\\d+)$");
|
||||
private boolean isUnconsumedContent(SavedHttpResponse savedHttpResponse) {
|
||||
Header header = savedHttpResponse.getHeader("Content-Range");
|
||||
Matcher matcher = CONTENT_RANGE_PATTERN.matcher(header.getValue());
|
||||
if(!matcher.matches()) {
|
||||
throw new RuntimeException("Unexpected Content-Range format");
|
||||
}
|
||||
int start = Integer.parseInt(matcher.group(1));
|
||||
int end = Integer.parseInt(matcher.group(2));
|
||||
int total = Integer.parseInt(matcher.group(3));
|
||||
return (total - 1) > end;
|
||||
}
|
||||
|
||||
private CloseableHttpResponse doRequest(AirsonicServer server) throws IOException {
|
||||
RequestBuilder builder = RequestBuilder.create("GET").setUri(server.getBaseUri() + "/rest/stream");
|
||||
builder.addParameter("id", "2");
|
||||
builder.addParameter("id", "2"); // TODO abstract this out
|
||||
builder.addHeader("Range", "bytes=0-");
|
||||
builder.addHeader("Accept", "audio/webm,audio/ogg,audio/wav,audio/*;");
|
||||
server.addRestParameters(builder);
|
||||
response = client.execute(builder.build());
|
||||
});
|
||||
|
||||
Then("The response bytes are equal", () -> {
|
||||
ensureBodyRead();
|
||||
|
||||
FileUtils.writeByteArrayToFile(new File("/tmp/bytearray"), body);
|
||||
|
||||
byte[] expected = IOUtils.toByteArray(this.getClass().getResource("/blobs/stream/piano/piano.mp3").toURI());
|
||||
//
|
||||
// HexDump.dump(expected, 0, System.out, 0);
|
||||
|
||||
Assert.assertArrayEquals(expected, body);
|
||||
});
|
||||
|
||||
|
||||
return client.execute(builder.build());
|
||||
}
|
||||
|
||||
void ensureBodyRead() throws IOException {
|
||||
if(closed) {
|
||||
return;
|
||||
} else {
|
||||
this.body = EntityUtils.toByteArray(response.getEntity());
|
||||
closed = true;
|
||||
SavedHttpResponse consumeResponse(CloseableHttpResponse response) throws IOException {
|
||||
byte[] body = EntityUtils.toByteArray(response.getEntity());
|
||||
List<Header> headers = Arrays.asList(response.getAllHeaders());
|
||||
response.close();
|
||||
}
|
||||
return new SavedHttpResponse(headers, body);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
package org.airsonic.test.domain;
|
||||
|
||||
import org.apache.http.Header;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class SavedHttpResponse {
|
||||
private final List<Header> headers;
|
||||
private final byte[] body;
|
||||
|
||||
public SavedHttpResponse(List<Header> headers, byte[] body) {
|
||||
this.headers = headers;
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
public List<Header> getHeaders() {
|
||||
return headers;
|
||||
}
|
||||
|
||||
public byte[] getBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
public Header getHeader(String name) {
|
||||
List<Header> matchingHeaders = headers.stream().filter(header ->
|
||||
Objects.equals(header.getName(), name))
|
||||
.collect(Collectors.toList());
|
||||
if(matchingHeaders.size() != 1) {
|
||||
throw new RuntimeException("Did not find one matching header with name " + name);
|
||||
}
|
||||
return matchingHeaders.iterator().next();
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -1,11 +1,12 @@
|
|||
Feature: Stream API for MP3
|
||||
|
||||
Background:
|
||||
Given Media file stream/piano/piano.mp3 is added
|
||||
Given Media file piano is added
|
||||
And a scan is done
|
||||
|
||||
Scenario: Airsonic sends stream data
|
||||
When A stream request is sent
|
||||
When A stream is consumed
|
||||
Then Print debug output
|
||||
Then The response bytes are equal
|
||||
# TODO check length
|
||||
Then The length headers are correct
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue