package com.soundcloud.api;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.CoreMatchers.sameInstance;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.auth.AUTH;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.util.EntityUtils;
import org.hamcrest.CoreMatchers;
import org.junit.Test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.net.URI;
import java.util.Arrays;
import java.util.IllegalFormatException;
import java.util.Iterator;
import java.util.NoSuchElementException;
public class RequestTest {
@Test(expected = IllegalArgumentException.class)
public void shouldThrowIllegalArgumentForNonEvenParams() throws Exception {
new Request().with("1", 2, "3");
}
@Test
public void shouldBuildAQueryString() throws Exception {
assertThat(
new Request().with("foo", 100, "baz", 22.3f, "met\u00f8l", false).queryString(),
equalTo("foo=100&baz=22.3&met%C3%B8l=false"));
}
@Test
public void shouldGenerateUrlWithParameters() throws Exception {
Request p = new Request().with("foo", 100, "baz", 22.3f);
assertThat(p.toUrl("http://foo.com"), equalTo("http://foo.com?foo=100&baz=22.3"));
}
@Test
public void shouldNotModifyOriginalRequest() throws Exception {
String url = "http://ec-media.soundcloud.com/SdPniMt7cZzj.128.mp3?ff61182e3c2ecefa438cd02102d0e385713f0c1f" +
"af3b0339595660fd0603ed1dd95c308fdf4dfe37b272d5fc302cd60875f62fda2557f961990ca6e770fdb81c291f729" +
"2cb&AWSAccessKeyId=AKIAJBHW5FB4ERKUQUOQ&Expires=1337966965&Signature=dFluZNnDMGZiXCACfRru9VrB%2" +
"Bbg%3D";
Request r = new Request(url);
assertThat(r.toUrl(), equalTo(url));
}
@Test
public void shouldHaveSizeMethod() throws Exception {
Request p = new Request().with("foo", 100, "baz", 22.3f);
assertThat(p.size(), is(2));
}
@Test
public void shouldSupportWith() throws Exception {
Request p = new Request().with("foo", 100, "baz", 22.3f);
p.add("baz", 66);
assertThat(p.size(), is(3));
assertThat(p.queryString(), equalTo("foo=100&baz=22.3&baz=66"));
}
@Test
public void shouldSupportOverwritingParameters() {
Request r = new Request();
r.add("foo", 1)
.add("foo", 2);
assertThat(r.queryString(), equalTo("foo=1&foo=2"));
r.set("foo", 3);
assertThat(r.queryString(), equalTo("foo=3"));
r.clear("foo");
assertThat(r.queryString(), equalTo(""));
}
@Test
public void shouldAddParameter() throws Exception {
Request r = new Request();
r.add("param", "value");
assertThat(r.queryString(), equalTo("param=value"));
}
@Test
public void shouldAddOnlyParameterNameIfPassedNullValue() throws Exception {
Request r = new Request();
r.add("param", null);
assertThat(r.queryString(), equalTo("param"));
}
@Test
public void shouldAddAllContainedValuesIfPassedArrays() throws Exception {
Request r = new Request();
r.add("foo", new String[] { "1", "2"});
assertThat(r.queryString(), equalTo("foo=1&foo=2"));
}
@Test
public void shouldAddAllContainedValuesIfPassedIterable() throws Exception {
Request r = new Request();
r.add("foo", Arrays.asList("1", "2"));
assertThat(r.queryString(), equalTo("foo=1&foo=2"));
}
@Test
public void shouldCopyRequestWithNewResource() throws Exception {
Request p = new Request().with("foo", 100, "baz", 22.3f);
Request p2 = p.newResource("baz");
assertThat(p, not(sameInstance(p2)));
assertThat(p2.toString(),
equalTo("Request{mResource='baz', params=[foo=100, baz=22.3], files=null, entity=null, mToken=null, listener=null}"));
}
@Test
public void shouldImplementIterable() throws Exception {
Request p = new Request().with("foo", 100, "baz", 22.3f);
Iterator<NameValuePair> it = p.iterator();
assertThat(it.next().getName(), equalTo("foo"));
assertThat(it.next().getName(), equalTo("baz"));
try {
it.next();
throw new RuntimeException("NoSuchElementException expected");
} catch (NoSuchElementException ignored) {
}
}
@Test
public void shouldGetStringFromHttpResponse() throws Exception {
HttpResponse resp = mock(HttpResponse.class);
HttpEntity ent = mock(HttpEntity.class);
when(ent.getContent()).thenReturn(new ByteArrayInputStream("foo".getBytes()));
when(resp.getEntity()).thenReturn(ent);
assertThat(Http.getString(resp), equalTo("foo"));
}
@Test
public void shouldBuildARequest() throws Exception {
HttpGet request = Request.to("/foo").with("1", "2").buildRequest(HttpGet.class);
assertThat(request.getURI().toString(), equalTo("/foo?1=2"));
}
@Test
public void shouldAddTokenToHeaderIfSpecified() throws Exception {
HttpGet request = Request.to("/foo")
.with("1", "2")
.usingToken(new Token("acc3ss", "r3fr3sh"))
.buildRequest(HttpGet.class);
Header auth = request.getFirstHeader(AUTH.WWW_AUTH_RESP);
assertNotNull(auth);
assertThat(auth.getValue(), CoreMatchers.containsString("acc3ss"));
}
@Test
public void shouldAddRangeHeaderIfSpecified() throws Exception {
HttpGet request = Request.to("/foo")
.range(1,200)
.buildRequest(HttpGet.class);
Header auth = request.getFirstHeader("Range");
assertNotNull(auth);
assertThat(auth.getValue(), equalTo("bytes=1-200"));
}
@Test
public void shouldCreateMultipartRequestWhenFilesAreAdded() throws Exception {
File f = File.createTempFile("testing", "test");
HttpPost request = Request.to("/foo")
.with("key", "value")
.withFile("foo", f)
.buildRequest(HttpPost.class);
assertTrue(request.getEntity() instanceof MultipartEntity);
ByteArrayOutputStream os = new ByteArrayOutputStream();
request.getEntity().writeTo(os);
String encoded = os.toString();
assertThat(encoded, containsString("foo"));
assertThat(encoded, containsString("key"));
assertThat(encoded, containsString("value"));
assertThat(encoded, containsString("filename=\"testing"));
}
@Test
public void shouldOverrideFilenameInUpload() throws Exception {
File f = File.createTempFile("testing", "test");
HttpPost request = Request.to("/foo")
.with("key", "value")
.withFile("foo", f, "music.mp3")
.buildRequest(HttpPost.class);
assertTrue(request.getEntity() instanceof MultipartEntity);
ByteArrayOutputStream os = new ByteArrayOutputStream();
request.getEntity().writeTo(os);
String encoded = os.toString();
assertThat(encoded, containsString("foo"));
assertThat(encoded, containsString("key"));
assertThat(encoded, containsString("value"));
assertThat(encoded, containsString("filename=\"music.mp3\""));
}
@Test
public void shouldDetectMultipartRequests() throws Exception {
assertFalse(Request.to("/foo")
.with("key", "value").isMultipart());
assertTrue(Request.to("/foo")
.with("key", "value")
.withFile("foo", "foo".getBytes()).isMultipart());
}
@Test
public void shouldUploadByteDataWithFilename() throws Exception {
HttpPost request = Request.to("/foo")
.with("key", "value")
.withFile("testing", "foo".getBytes(), "music.mp3")
.buildRequest(HttpPost.class);
assertTrue(request.getEntity() instanceof MultipartEntity);
ByteArrayOutputStream os = new ByteArrayOutputStream();
request.getEntity().writeTo(os);
String encoded = os.toString();
assertThat(encoded, containsString("filename=\"music.mp3\""));
}
@Test
public void shouldPreservePostUri() throws Exception {
HttpPost request = Request.to("/foo")
.buildRequest(HttpPost.class);
assertThat(request.getURI(), notNullValue());
assertThat(request.getURI().toString(), equalTo("/foo"));
}
@Test
public void shouldCreateMultipartRequestWhenFilesAreAddedWithByteArray() throws Exception {
HttpPost request = Request.to("/foo")
.with("key", "value")
.withFile("testing", "foo".getBytes())
.buildRequest(HttpPost.class);
assertTrue(request.getEntity() instanceof MultipartEntity);
ByteArrayOutputStream os = new ByteArrayOutputStream();
request.getEntity().writeTo(os);
String encoded = os.toString();
assertThat(encoded, containsString("foo"));
assertThat(encoded, containsString("key"));
assertThat(encoded, containsString("value"));
assertThat(encoded, containsString("testing"));
}
@Test
public void shouldIncludeAnyEntityInRequest() throws Exception {
HttpPost request = Request.to("/too")
.withEntity(new StringEntity("foo"))
.buildRequest(HttpPost.class);
ByteArrayOutputStream os = new ByteArrayOutputStream();
request.getEntity().writeTo(os);
String body = os.toString();
assertThat("foo", equalTo(body));
}
@Test
public void shouldIncludeContentInRequest() throws Exception {
HttpPost request = Request.to("/too")
.withContent("<foo><baz>content</baz></foo>", "application/xml")
.buildRequest(HttpPost.class);
ByteArrayOutputStream os = new ByteArrayOutputStream();
request.getEntity().writeTo(os);
String body = os.toString();
assertThat(request.getFirstHeader("Content-Type").getValue(), equalTo("application/xml"));
assertThat("<foo><baz>content</baz></foo>", equalTo(body));
}
@Test
public void shouldUseUTF8AsDefaultEncodingForStringPayloads() throws Exception {
HttpPost request = Request.to("/too")
.withContent("{ string:\"îøüöéí\" }", "application/json")
.buildRequest(HttpPost.class);
ByteArrayOutputStream os = new ByteArrayOutputStream();
request.getEntity().writeTo(os);
String decoded = os.toString("UTF-8");
assertThat("{ string:\"îøüöéí\" }", equalTo(decoded));
}
@Test
public void shouldBuildARequestWithContentAndPreserveQueryParameters() throws Exception {
HttpPost post = Request
.to("/foo")
.withContent("{}", "application/json")
.with("1", "2").buildRequest(HttpPost.class);
assertThat(post.getURI().toString(), equalTo("/foo?1=2"));
assertTrue(post.getEntity() instanceof StringEntity);
assertThat(post.getEntity().getContentLength(), equalTo(2l));
assertThat(EntityUtils.toString(post.getEntity()), equalTo("{}"));
assertThat(post.getFirstHeader("Content-Type").getValue(), equalTo("application/json"));
}
@Test
public void whenAProgressListenerIsSpecifiedShouldHaveCountingMultipart() throws Exception {
HttpPost request = Request.to("/foo")
.with("key", "value")
.withFile("foo", new File("/tmp"))
.setProgressListener(mock(Request.TransferProgressListener.class))
.buildRequest(HttpPost.class);
assertTrue(request.getEntity() instanceof CountingMultipartEntity);
}
@Test
public void shouldDoStringFormattingInFactoryMethod() throws Exception {
assertThat(Request.to("/resource/%d", 200).toUrl(), equalTo("/resource/200"));
}
@Test(expected = IllegalFormatException.class)
public void shouldThrowIllegalFormatExceptionWhenInvalidParameters() throws Exception {
Request.to("/resource/%d", "int").toUrl();
}
@Test
public void toStringShouldWork() throws Exception {
assertThat(
new Request("/foo").with("1", "2").toString(),
equalTo("Request{mResource='/foo', params=[1=2], files=null, entity=null, mToken=null, listener=null}"));
}
@Test
public void itShouldParseExistingQueryParameters() throws Exception {
assertThat(
new Request("/foo?bar=baz").with("1", "2").toUrl(),
equalTo("/foo?bar=baz&1=2"));
assertThat(
new Request("/foo?").with("1", "2").toUrl(),
equalTo("/foo?1=2"));
assertThat(
new Request("/foo?bar=baz&foo=bar").with("1", "2").toUrl(),
equalTo("/foo?bar=baz&foo=bar&1=2"));
String s3 = "http://ak-media.soundcloud.com/XAGeEabPextR.128.mp3?AWSAccessKeyId=AKIAJBHW5FB4ERKUQUOQ&Expires=1319547723&Signature=o53ozj2b%2BrdARFBEZoAziK7mWIY%3D&__gda__=1319547723_e7e8d73cf3af2b003d891ecc01c20143";
assertThat(Request.to(s3).toUrl(), equalTo(s3));
}
@Test
public void itShouldParseFullURI() throws Exception {
assertThat(
new Request(URI.create("http://foo.soundcloud.com/foo?bar=baz")).with("1", "2").toUrl(),
equalTo("/foo?bar=baz&1=2"));
assertThat(
new Request(URI.create("http://foo.soundcloud.com/foo")).with("1", "2").toUrl(),
equalTo("/foo?1=2"));
assertThat(
new Request(URI.create("http://foo.soundcloud.com/")).toUrl(),
equalTo("/"));
}
@Test
public void shouldHaveCopyConstructor() {
Request orig = new Request("/foo").with("1", 2, "3",4);
Request copy = new Request(orig);
assertThat(copy.toUrl(),equalTo(orig.toUrl()));
assertThat(copy.getToken(),equalTo(orig.getToken()));
}
@Test(expected = IllegalArgumentException.class)
public void shouldNotAcceptNullStringInCtor() throws Exception {
new Request((String) null);
}
@Test
public void shouldNotModifyOriginal() {
Request orig = new Request("/foo").with("1", 2, "3",4);
orig.setProgressListener(new Request.TransferProgressListener(){
@Override public void transferred(long amount) {}
});
Request copy = new Request(orig);
orig.add("cursor","asdf");
orig.usingToken(new Token("access","refresh"));
assertThat(copy.toUrl(), not(equalTo(orig.toUrl())));
assertThat(copy.getToken(), not(equalTo(orig.getToken())));
assertThat(orig.getListener(),equalTo(copy.getListener()));
}
@Test
public void testFormatRange() throws Exception {
assertThat(Request.formatRange(1, 1000), equalTo("bytes=1-1000"));
assertThat(Request.formatRange(1), equalTo("bytes=1-"));
assertThat(Request.formatRange(), equalTo("bytes=0-"));
}
@Test(expected = IllegalArgumentException.class)
public void testFormatRangeInvalidArgument() throws Exception {
Request.formatRange(100,200,300);
}
@Test(expected = IllegalArgumentException.class)
public void testFormatRangeInvalidArgument2() throws Exception {
Request.formatRange(1000, 1);
}
@Test(expected = IllegalArgumentException.class)
public void testFormatRangeInvalidArgument3() throws Exception {
Request.formatRange(-1);
}
@Test(expected = IllegalArgumentException.class)
public void testFormatRangeInvalidArgument4() throws Exception {
Request.formatRange(-1, 200);
}
}