package io.tus.java.client; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.io.ByteArrayInputStream; import java.io.IOException; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import org.junit.Test; import org.mockserver.model.HttpRequest; import org.mockserver.model.HttpResponse; public class TestTusClient extends MockServerProvider { @Test public void testTusClient() { TusClient client = new TusClient(); assertEquals(client.getUploadCreationURL(), null); } @Test public void testTusClientURL() throws MalformedURLException { TusClient client = new TusClient(); client.setUploadCreationURL(creationUrl); assertEquals(client.getUploadCreationURL(), creationUrl); } @Test public void testSetUploadCreationURL() throws MalformedURLException { TusClient client = new TusClient(); client.setUploadCreationURL(new URL("http://master.tus.io")); assertEquals(client.getUploadCreationURL(), new URL("http://master.tus.io")); } @Test public void testEnableResuming() { TusClient client = new TusClient(); assertEquals(client.resumingEnabled(), false); TusURLStore store = new TusURLMemoryStore(); client.enableResuming(store); assertEquals(client.resumingEnabled(), true); client.disableResuming(); assertEquals(client.resumingEnabled(), false); } @Test public void testCreateUpload() throws IOException, ProtocolException { mockServer.when(new HttpRequest() .withMethod("POST") .withPath("/files") .withHeader("Tus-Resumable", TusClient.TUS_VERSION) .withHeader("Upload-Metadata", "foo aGVsbG8=,bar d29ybGQ=") .withHeader("Upload-Length", "10")) .respond(new HttpResponse() .withStatusCode(201) .withHeader("Tus-Resumable", TusClient.TUS_VERSION) .withHeader("Location", mockServerURL + "/foo")); Map<String, String> metadata = new LinkedHashMap<String, String>(); metadata.put("foo", "hello"); metadata.put("bar", "world"); TusClient client = new TusClient(); client.setUploadCreationURL(mockServerURL); TusUpload upload = new TusUpload(); upload.setSize(10); upload.setInputStream(new ByteArrayInputStream(new byte[10])); upload.setMetadata(metadata); TusUploader uploader = client.createUpload(upload); assertEquals(uploader.getUploadURL(), new URL(mockServerURL + "/foo")); } @Test public void testCreateUploadWithMissingLocationHeader() throws IOException, Exception { mockServer.when(new HttpRequest() .withMethod("POST") .withPath("/files") .withHeader("Tus-Resumable", TusClient.TUS_VERSION) .withHeader("Upload-Length", "10")) .respond(new HttpResponse() .withStatusCode(201) .withHeader("Tus-Resumable", TusClient.TUS_VERSION)); TusClient client = new TusClient(); client.setUploadCreationURL(mockServerURL); TusUpload upload = new TusUpload(); upload.setSize(10); upload.setInputStream(new ByteArrayInputStream(new byte[10])); try { TusUploader uploader = client.createUpload(upload); throw new Exception("unreachable code reached"); } catch(ProtocolException e) { assertEquals(e.getMessage(), "missing upload URL in response for creating upload"); } } @Test public void testCreateUploadWithRelativeLocation() throws Exception { // We need to enable strict following for POST requests first System.setProperty("http.strictPostRedirect", "true"); // Attempt a real redirect mockServer.when(new HttpRequest() .withMethod("POST") .withPath("/filesRedirect") .withHeader("Tus-Resumable", TusClient.TUS_VERSION) .withHeader("Upload-Length", "10")) .respond(new HttpResponse() .withStatusCode(301) .withHeader("Location", mockServerURL + "Redirected/")); mockServer.when(new HttpRequest() .withMethod("POST") .withPath("/filesRedirected/") .withHeader("Tus-Resumable", TusClient.TUS_VERSION) .withHeader("Upload-Length", "10")) .respond(new HttpResponse() .withStatusCode(201) .withHeader("Tus-Resumable", TusClient.TUS_VERSION) .withHeader("Location", "foo")); TusClient client = new TusClient(); client.setUploadCreationURL(new URL(mockServerURL + "Redirect")); TusUpload upload = new TusUpload(); upload.setSize(10); upload.setInputStream(new ByteArrayInputStream(new byte[10])); TusUploader uploader = client.createUpload(upload); // The upload URL must be relative to the URL of the request by which is was returned, // not the upload creation URL. In most cases, there is no difference between those two // but it's still important to be correct here. assertEquals(uploader.getUploadURL(), new URL(mockServerURL + "Redirected/foo")); } @Test public void testResumeUpload() throws ResumingNotEnabledException, FingerprintNotFoundException, IOException, ProtocolException { mockServer.when(new HttpRequest() .withMethod("HEAD") .withPath("/files/foo") .withHeader("Tus-Resumable", TusClient.TUS_VERSION)) .respond(new HttpResponse() .withStatusCode(204) .withHeader("Tus-Resumable", TusClient.TUS_VERSION) .withHeader("Upload-Offset", "3")); TusClient client = new TusClient(); client.setUploadCreationURL(mockServerURL); client.enableResuming(new TestResumeUploadStore()); TusUpload upload = new TusUpload(); upload.setSize(10); upload.setInputStream(new ByteArrayInputStream(new byte[10])); upload.setFingerprint("test-fingerprint"); TusUploader uploader = client.resumeUpload(upload); assertEquals(uploader.getUploadURL(), new URL(mockServerURL.toString() + "/foo")); assertEquals(uploader.getOffset(), 3); } private class TestResumeUploadStore implements TusURLStore { public void set(String fingerprint, URL url) { assertTrue("set method must not be called", false); } public URL get(String fingerprint) { assertEquals(fingerprint, "test-fingerprint"); try { return new URL(mockServerURL.toString() + "/foo"); } catch(Exception e) {} return null; } public void remove(String fingerprint) { assertTrue("remove method must not be called", false); } } @Test public void testResumeOrCreateUpload() throws IOException, ProtocolException { mockServer.when(new HttpRequest() .withMethod("POST") .withPath("/files") .withHeader("Tus-Resumable", TusClient.TUS_VERSION) .withHeader("Upload-Length", "10")) .respond(new HttpResponse() .withStatusCode(201) .withHeader("Tus-Resumable", TusClient.TUS_VERSION) .withHeader("Location", mockServerURL + "/foo")); TusClient client = new TusClient(); client.setUploadCreationURL(mockServerURL); TusUpload upload = new TusUpload(); upload.setSize(10); upload.setInputStream(new ByteArrayInputStream(new byte[10])); TusUploader uploader = client.resumeOrCreateUpload(upload); assertEquals(uploader.getUploadURL(), new URL(mockServerURL + "/foo")); } @Test public void testResumeOrCreateUploadNotFound() throws IOException, ProtocolException { mockServer.when(new HttpRequest() .withMethod("HEAD") .withPath("/files/not_found") .withHeader("Tus-Resumable", TusClient.TUS_VERSION)) .respond(new HttpResponse() .withStatusCode(404)); mockServer.when(new HttpRequest() .withMethod("POST") .withPath("/files") .withHeader("Tus-Resumable", TusClient.TUS_VERSION) .withHeader("Upload-Length", "10")) .respond(new HttpResponse() .withStatusCode(201) .withHeader("Tus-Resumable", TusClient.TUS_VERSION) .withHeader("Location", mockServerURL + "/foo")); TusClient client = new TusClient(); client.setUploadCreationURL(mockServerURL); TusURLStore store = new TusURLMemoryStore(); store.set("fingerprint", new URL(mockServerURL + "/not_found")); client.enableResuming(store); TusUpload upload = new TusUpload(); upload.setSize(10); upload.setInputStream(new ByteArrayInputStream(new byte[10])); upload.setFingerprint("fingerprint"); TusUploader uploader = client.resumeOrCreateUpload(upload); assertEquals(uploader.getUploadURL(), new URL(mockServerURL + "/foo")); } @Test public void testBeginOrResumeUploadFromURL() throws IOException, ProtocolException { mockServer.when(new HttpRequest() .withMethod("HEAD") .withPath("/files/fooFromURL") .withHeader("Tus-Resumable", TusClient.TUS_VERSION)) .respond(new HttpResponse() .withStatusCode(204) .withHeader("Tus-Resumable", TusClient.TUS_VERSION) .withHeader("Upload-Offset", "3")); TusClient client = new TusClient(); URL uploadURL = new URL(mockServerURL.toString() + "/fooFromURL"); TusUpload upload = new TusUpload(); upload.setSize(10); upload.setInputStream(new ByteArrayInputStream(new byte[10])); TusUploader uploader = client.beginOrResumeUploadFromURL(upload, uploadURL); assertEquals(uploader.getUploadURL(), uploadURL); assertEquals(uploader.getOffset(), 3); } @Test public void testPrepareConnection() throws IOException { HttpURLConnection connection = (HttpURLConnection) mockServerURL.openConnection(); TusClient client = new TusClient(); client.prepareConnection(connection); assertEquals(connection.getRequestProperty("Tus-Resumable"), TusClient.TUS_VERSION); } @Test public void testSetHeaders() throws IOException { HttpURLConnection connection = (HttpURLConnection) mockServerURL.openConnection(); TusClient client = new TusClient(); Map<String, String> headers = new HashMap<String, String>(); headers.put("Greeting", "Hello"); headers.put("Important", "yes"); headers.put("Tus-Resumable", "evil"); assertNull(client.getHeaders()); client.setHeaders(headers); assertEquals(headers, client.getHeaders()); client.prepareConnection(connection); assertEquals(connection.getRequestProperty("Greeting"), "Hello"); assertEquals(connection.getRequestProperty("Important"), "yes"); } @Test public void testSetConnectionTimeout() throws IOException { HttpURLConnection connection = (HttpURLConnection) mockServerURL.openConnection(); TusClient client = new TusClient(); assertEquals(client.getConnectTimeout(), 5000); client.setConnectTimeout(3000); assertEquals(client.getConnectTimeout(), 3000); client.prepareConnection(connection); assertEquals(connection.getConnectTimeout(), 3000); } @Test public void testFollowRedirects() throws Exception { HttpURLConnection connection = (HttpURLConnection) mockServerURL.openConnection(); TusClient client = new TusClient(); // Should not follow by default client.prepareConnection(connection); assertFalse(connection.getInstanceFollowRedirects()); // Only follow if we enable strict redirects System.setProperty("http.strictPostRedirect", "true"); client.prepareConnection(connection); assertTrue(connection.getInstanceFollowRedirects()); // Attempt a real redirect mockServer.when(new HttpRequest() .withMethod("POST") .withPath("/filesRedirect") .withHeader("Tus-Resumable", TusClient.TUS_VERSION) .withHeader("Upload-Length", "10")) .respond(new HttpResponse() .withStatusCode(301) .withHeader("Location", mockServerURL + "Redirected")); mockServer.when(new HttpRequest() .withMethod("POST") .withPath("/filesRedirected") .withHeader("Tus-Resumable", TusClient.TUS_VERSION) .withHeader("Upload-Length", "10")) .respond(new HttpResponse() .withStatusCode(201) .withHeader("Tus-Resumable", TusClient.TUS_VERSION) .withHeader("Location", mockServerURL + "/foo")); client.setUploadCreationURL(new URL(mockServerURL + "Redirect")); TusUpload upload = new TusUpload(); upload.setSize(10); upload.setInputStream(new ByteArrayInputStream(new byte[10])); TusUploader uploader = client.createUpload(upload); assertEquals(uploader.getUploadURL(), new URL(mockServerURL + "/foo")); } @Test public void testRemoveFingerprintOnSuccessDisabled() throws IOException, ProtocolException { TusClient client = new TusClient(); TusURLStore store = new TusURLMemoryStore(); URL dummyURL = new URL("http://dummy-url/files/dummy"); store.set("fingerprint", dummyURL); client.enableResuming(store); assertTrue(!client.removeFingerprintOnSuccessEnabled()); TusUpload upload = new TusUpload(); upload.setFingerprint("fingerprint"); client.uploadFinished(upload); assertTrue(dummyURL.equals(store.get("fingerprint"))); } @Test public void testRemoveFingerprintOnSuccessEnabled() throws IOException, ProtocolException { TusClient client = new TusClient(); TusURLStore store = new TusURLMemoryStore(); URL dummyURL = new URL("http://dummy-url/files/dummy"); store.set("fingerprint", dummyURL); client.enableResuming(store); client.enableRemoveFingerprintOnSuccess(); assertTrue(client.removeFingerprintOnSuccessEnabled()); TusUpload upload = new TusUpload(); upload.setFingerprint("fingerprint"); client.uploadFinished(upload); assertTrue(store.get("fingerprint") == null); } }