diff --git a/CHANGELOG.md b/CHANGELOG.md index a1096e6..9220bd6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,19 @@ ### Not released yet ### +#### Major Release * Exchange the Socket based assembly status fetching with a Server-Sent-Events (SSE) solution. * Added new methods to the AssemblyListener interface to provide more information about the assembly status. e.g. encoding progress with AssemblyListener#onAssemblyProgress(). * Changed existing methods in the AssemblyListener interface to provide the bare JSON response from the api instead of pre-parsed data. +* Removed the deprecated AsyncAssemblies class and functionality. + +##### Breaking Changes - Upgrade Guide +* The AssemblyListener interface has been upgraded. As a result you will have to implement the following methods: + - `onFileUploadFinished(JSONObject uploadInformation);` + - `onAssemblyProgress(JSONObject progress)` + - `onAssemblyResultFinished(JSONArray result)` + +* The AsyncAssembly class has been removed. If you were using it, you will have to switch to the regular Assembly class. + It has been extended with asynchronous upload capabilities in the past. +The Example under `examples/src/main/java/com/transloadit/examples/MultiStepProcessing.java` shows how to use the new features. ### 1.0.1 / 2024-11-28 ### * Added SDK support for generating signed Smart CDN URLs (see https://transloadit.com/docs/topics/signature-authentication/#smart-cdn). This functionality ships as Transloadit#getSignedSmartCDNUrl() - Method. diff --git a/examples/src/main/java/com/transloadit/examples/async/AsyncExample.java b/examples/src/main/java/com/transloadit/examples/async/AsyncExample.java deleted file mode 100644 index 05dbbc2..0000000 --- a/examples/src/main/java/com/transloadit/examples/async/AsyncExample.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.transloadit.examples.async; - -import com.transloadit.sdk.Transloadit; -import com.transloadit.sdk.async.AsyncAssembly; -import com.transloadit.sdk.async.UploadProgressListener; -import com.transloadit.sdk.exceptions.LocalOperationException; -import com.transloadit.sdk.exceptions.RequestException; - -import java.io.File; -import java.util.HashMap; -import java.util.Map; - -public final class AsyncExample { - /** - * Runs a asynchronous Transloadit assembly. - * @param args - */ - public static void main(String[] args) { - Transloadit transloadit = new Transloadit(System.getenv("TRANSLOADIT_KEY"), System.getenv("TRANSLOADIT_SECRET")); - - Map stepOptions = new HashMap(); - stepOptions.put("width", 75); - stepOptions.put("height", 75); - stepOptions.put("resize_strategy", "pad"); - - ProgressListener listener = new ProgressListener(); - AsyncAssembly assembly = transloadit.newAssembly(listener); - assembly.addStep("resize", "/image/resize", stepOptions); - - File image = new File(AsyncExample.class.getResource("/lol_cat.jpg").getFile()); - assembly.addFile(image); - - try { - assembly.save(); - } catch (RequestException | LocalOperationException e) { - e.printStackTrace(); - } - } - - static class ProgressListener implements UploadProgressListener { - @Override - public void onUploadFinished() { - System.out.println("upload finished!!! waiting for execution ..."); - } - - @Override - public void onUploadProgress(long uploadedBytes, long totalBytes) { - System.out.println("uploaded: " + uploadedBytes + " of: " + totalBytes); - } - - @Override - public void onUploadFailed(Exception exception) { - System.out.println("upload failed :("); - exception.printStackTrace(); - } - - @Override - public void onParallelUploadsStarting(int parallelUploads, int uploadNumber) { - - } - } - /** - * Prohibits instantiation of utility class. - */ - private AsyncExample() { - throw new IllegalStateException("Utility class"); - } -} diff --git a/examples/src/main/java/com/transloadit/examples/async/AsyncPausePlayExample.java b/examples/src/main/java/com/transloadit/examples/async/AsyncPausePlayExample.java deleted file mode 100644 index f83fdf2..0000000 --- a/examples/src/main/java/com/transloadit/examples/async/AsyncPausePlayExample.java +++ /dev/null @@ -1,90 +0,0 @@ -package com.transloadit.examples.async; - -import com.transloadit.sdk.Transloadit; -import com.transloadit.sdk.async.AsyncAssembly; -import com.transloadit.sdk.async.UploadProgressListener; -import com.transloadit.sdk.exceptions.LocalOperationException; -import com.transloadit.sdk.exceptions.RequestException; - -import java.io.File; -import java.util.HashMap; -import java.util.Map; - -public final class AsyncPausePlayExample { - /** - * Runs an asynchronous Transloadit assembly, with the file's upload being paused and resumed. - * @param args - */ - public static void main(String[] args) { - Transloadit transloadit = new Transloadit(System.getenv("TRANSLOADIT_KEY"), System.getenv("TRANSLOADIT_SECRET")); - - Map stepOptions = new HashMap(); - stepOptions.put("width", 75); - stepOptions.put("height", 75); - stepOptions.put("resize_strategy", "pad"); - - ProgressListener listener = new ProgressListener(); - AsyncAssembly assembly = transloadit.newAssembly(listener); - assembly.addStep("resize", "/image/resize", stepOptions); - - File image = new File(AsyncPausePlayExample.class.getResource("/lol_cat.jpg").getFile()); - assembly.addFile(image); - // setting a small chunk size here in order to demo the pause and resume feature - // No need to use this method in your implementation unless you truly want to upload in a specified - // amount (small or large) of chunks. - assembly.setUploadChunkSize(200); - - try { - assembly.save(); - // wait the till we are sure that the upload has started - synchronized (listener) { - listener.wait(10000); - } - System.out.println("about to pause ..."); - assembly.pauseUpload(); - System.out.println("upload just got paused ..."); - Thread.sleep(3000); - assembly.resumeUpload(); - System.out.println("upload just got resumed .."); - } catch (RequestException | LocalOperationException | InterruptedException e) { - e.printStackTrace(); - } - } - - static class ProgressListener implements UploadProgressListener { - @Override - public void onUploadFinished() { - System.out.println("upload finished!!! waiting for execution ..."); - } - - @Override - public void onUploadProgress(long uploadedBytes, long totalBytes) { - double percentage = ((double) uploadedBytes / (double) totalBytes) * 100.0; - System.out.println("uploaded: " + uploadedBytes + " of: " + totalBytes); - - // notify the main class to pause the upload - if (percentage > 0 && percentage < 20) { - synchronized (this) { - this.notifyAll(); - } - } - } - - @Override - public void onUploadFailed(Exception exception) { - System.out.println("upload failed :("); - exception.printStackTrace(); - } - - @Override - public void onParallelUploadsStarting(int parallelUploads, int uploadNumber) { - System.out.println("Upload started: " + uploadNumber + " parallel Uploads in total " + parallelUploads); - } - } - /** - * Prohibits instantiation of utility class. - */ - private AsyncPausePlayExample() { - throw new IllegalStateException("Utility class"); - } -} diff --git a/examples/src/main/java/com/transloadit/examples/async/package-info.java b/examples/src/main/java/com/transloadit/examples/async/package-info.java deleted file mode 100644 index 2b91fe6..0000000 --- a/examples/src/main/java/com/transloadit/examples/async/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * This package provides examples for asynchronous Transloadit assemblies and their usage. - */ -package com.transloadit.examples.async; diff --git a/src/main/java/com/transloadit/sdk/Assembly.java b/src/main/java/com/transloadit/sdk/Assembly.java index 819d3b2..3c37bca 100644 --- a/src/main/java/com/transloadit/sdk/Assembly.java +++ b/src/main/java/com/transloadit/sdk/Assembly.java @@ -819,13 +819,4 @@ protected String obtainUploadUrlSuffix() { return "/assemblies/" + assemblyId; } } - - /** - * Returns the current Thread List. - * - * @return List of Type TusUploadRunnable - */ - protected ArrayList getThreadList() { - return threadList; - } } diff --git a/src/main/java/com/transloadit/sdk/Transloadit.java b/src/main/java/com/transloadit/sdk/Transloadit.java index 530d51b..ce4f86b 100644 --- a/src/main/java/com/transloadit/sdk/Transloadit.java +++ b/src/main/java/com/transloadit/sdk/Transloadit.java @@ -1,8 +1,5 @@ package com.transloadit.sdk; -import com.transloadit.sdk.async.AssemblyProgressListener; -import com.transloadit.sdk.async.UploadProgressListener; -import com.transloadit.sdk.async.AsyncAssembly; import com.transloadit.sdk.exceptions.RequestException; import com.transloadit.sdk.exceptions.LocalOperationException; import com.transloadit.sdk.response.AssemblyResponse; @@ -213,31 +210,6 @@ public Assembly newAssembly() { return new Assembly(this); } - /** - * Returns an AsyncAssembly instance that can be used to create a new assembly asynchronously. - * This method is good for running assemblies in the background - * - * @param listener an implementation of {@link UploadProgressListener} to serve as a callback - * for the asynchronous assembly. - * @return {@link AsyncAssembly} - */ - public AsyncAssembly newAssembly(UploadProgressListener listener) { - return new AsyncAssembly(this, listener); - } - - /** - * Returns an AsyncAssembly instance that can be used to create a new assembly asynchronously. - * This method is good for running assemblies in the background - * - * @param listener an implementation of {@link AssemblyProgressListener} to serve as a callback - * for the asynchronous assembly. - * @deprecated use {@link #newAssembly(UploadProgressListener)} instead - * @return {@link AsyncAssembly} - */ - public AsyncAssembly newAssembly(AssemblyProgressListener listener) { - return new AsyncAssembly(this, listener); - } - /** * Returns a single assembly. * diff --git a/src/main/java/com/transloadit/sdk/async/AssemblyProgressListener.java b/src/main/java/com/transloadit/sdk/async/AssemblyProgressListener.java deleted file mode 100644 index 3e65337..0000000 --- a/src/main/java/com/transloadit/sdk/async/AssemblyProgressListener.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.transloadit.sdk.async; - -import com.transloadit.sdk.response.AssemblyResponse; - - -/** - * Deprecated because its use is limited to the also deprecated {@link AsyncAssembly}. - * Implementations of this interface are used to handle progress and completion of a background - * Assembly file upload and execution. - */ -@Deprecated -public interface AssemblyProgressListener { - - /** - * Callback to be executed when the Assembly upload is complete. - */ - void onUploadFinished(); - - /** - * Callback to be executed as an upload progress receiver. - * - * @param uploadedBytes the number of bytes uploaded so far. - * @param totalBytes the total number of bytes to uploaded (i.e the size of all the files all together). - */ - void onUploadProgress(long uploadedBytes, long totalBytes); - - /** - * Callback to be executed when the Assembly execution is done executing. - * This encompasses any kind of termination of the assembly. - * Including when the assembly aborts due to failure. - * - * @param response {@link AssemblyResponse} response with the updated status of the assembly. - */ - void onAssemblyFinished(AssemblyResponse response); - - /** - * Callback to be executed if the Assembly upload fails. - * - * @param exception the error that causes the failure. - */ - void onUploadFailed(Exception exception); - - /** - * Callback to be executed if the Assembly status update retrieve fails. - * - * @param exception the error that causes the failure. - */ - void onAssemblyStatusUpdateFailed(Exception exception); -} diff --git a/src/main/java/com/transloadit/sdk/async/AsyncAssembly.java b/src/main/java/com/transloadit/sdk/async/AsyncAssembly.java deleted file mode 100644 index 26def34..0000000 --- a/src/main/java/com/transloadit/sdk/async/AsyncAssembly.java +++ /dev/null @@ -1,365 +0,0 @@ -package com.transloadit.sdk.async; - -import com.transloadit.sdk.Assembly; -import com.transloadit.sdk.Transloadit; -import com.transloadit.sdk.exceptions.LocalOperationException; -import com.transloadit.sdk.exceptions.RequestException; -import com.transloadit.sdk.response.AssemblyResponse; -import io.tus.java.client.ProtocolException; -import io.tus.java.client.TusExecutor; -import io.tus.java.client.TusUploader; -import org.jetbrains.annotations.Nullable; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.Map; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; - - -/** - * Deprecated because the {@link Assembly} is capable of asynchronous and pauseable / resumeable uploads now. - * You can use {@link Assembly#pauseUploads()} and {@link Assembly#resumeUploads()} as a replacement. - * This class represents a new assembly being created. - * It is similar to {@link Assembly} but provides Asynchronous functionality. - */ -@Deprecated -public class AsyncAssembly extends Assembly { - private AssemblyProgressListener progressListener; - private UploadProgressListener uploadListener; - private long uploadedBytes; - private long totalUploadSize; - private TusUploader lastTusUploader; - - @Nullable private String url; - enum State { - INIT, - UPLOADING, - PAUSED, - UPLOAD_COMPLETE - } - State state; - - protected AsyncAssemblyExecutor executor; - - /** - * Initializes a new {@link Assembly} object with asynchronous functionality. - * @param transloadit {@link Transloadit} the transloadit client. - * @param uploadListener {@link UploadProgressListener} tracks upload and completion of a background upload. - */ - public AsyncAssembly(Transloadit transloadit, UploadProgressListener uploadListener) { - super(transloadit); - // make true by default to avoid breaking change - shouldWaitForCompletion = true; - this.uploadListener = uploadListener; - state = State.INIT; - uploadedBytes = 0; - totalUploadSize = 0; - lastTusUploader = null; - url = null; - } - - /** - * Initializes a new {@link Assembly} object with asynchroneous functionality. - * Calls {@link #AsyncAssembly(Transloadit, UploadProgressListener)} - * @param transloadit {@link Transloadit} the transloadit client. - * @param listener {@link AssemblyProgressListener} which gets converted to an {@link UploadProgressListener}. - */ - public AsyncAssembly(Transloadit transloadit, final AssemblyProgressListener listener) { - this(transloadit, toUploadProgressListener(listener)); - progressListener = listener; - } - - /** - * Converts an {@link AssemblyProgressListener} to an {@link UploadProgressListener}. - * @param listener {@link AssemblyProgressListener} tracks upload and completion of a background upload and the - * states of Assembly execution. - * @return {@link UploadProgressListener} tracks upload and completion of a background upload. - */ - private static UploadProgressListener toUploadProgressListener(final AssemblyProgressListener listener) { - return new UploadProgressListener() { - @Override - public void onUploadFinished() { - listener.onUploadFinished(); - } - - @Override - public void onUploadProgress(long uploadedBytes, long totalBytes) { - listener.onUploadProgress(uploadedBytes, totalBytes); - } - - @Override - public void onUploadFailed(Exception exception) { - listener.onUploadFailed(exception); - } - - @Override - public void onParallelUploadsStarting(int parallelUploads, int uploadNumber) { - - } - }; - } - - /** - * Return the AssemblyProgresssListener that has been previously set. - * - * @return {@link AssemblyProgressListener} - */ - public AssemblyProgressListener getListener() { - return progressListener; - } - - /** - * Return the AssemblyProgresssListener that has been previously set. - * - * @return {@link UploadProgressListener} - */ - public UploadProgressListener getUploadListener() { - return uploadListener; - } - - /** - * Pauses the file upload. This is a blocking function that would try to wait till the assembly file uploads - * have actually been paused if possible. - * - * @throws LocalOperationException if the method is called while no upload is going on. - */ - public void pauseUpload() throws LocalOperationException { - if (state == State.UPLOADING) { - setState(State.PAUSED); - executor.hardStop(); - } else { - throw new LocalOperationException("Attempt to pause upload while assembly is not uploading"); - } - } - - /** - * Resumes the paused upload. - * - * @throws LocalOperationException if the upload hasn't been paused. - */ - public void resumeUpload() throws LocalOperationException { - if (state == State.PAUSED) { - startExecutor(); - } else { - throw new LocalOperationException("Attempt to resume un-paused upload"); - } - } - - /** - * Sets the state of the {@link AsyncAssembly} to the overhanded value. - * @param state {@link State} represents states of Assembly execution - */ - synchronized void setState(State state) { - this.state = state; - } - - /** - * Returns always false to indicate to the {@link Assembly#save} method that it should never wait for the Assembly - * to be complete by observing the HTTP - Response. - * @return false - * @see Assembly#shouldWaitWithoutSSE() - * @see Assembly#save(boolean) - */ - protected boolean shouldWaitWithoutSSE() { - return false; - } - - /** - * Runs intermediate check on the Assembly status until it is finished executing, - * then returns it as a response. - * - * @return {@link AssemblyResponse} - * @throws LocalOperationException if something goes wrong while running non-http operations. - * @throws RequestException if request to Transloadit server fails. - */ - protected AssemblyResponse watchStatus() throws LocalOperationException, RequestException { - return waitTillComplete(getClient().getAssemblyByUrl(url)); - } - - /** - * Does the actual uploading of files (when tus is enabled). - * - * @throws IOException when there's a failure with file retrieval - * @throws ProtocolException when there's a failure with tus upload - */ - @Override - protected void uploadTusFiles() throws IOException, ProtocolException { - setState(State.UPLOADING); - while (uploads.size() > 0) { - final TusUploader tusUploader; - // don't recreate uploader if it already exists. - // this is to avoid multiple connections being open. And to avoid some connections left unclosed. - if (lastTusUploader != null) { - tusUploader = lastTusUploader; - lastTusUploader = null; - } else { - tusUploader = tusClient.resumeOrCreateUpload(uploads.get(0)); - if (getUploadChunkSize() > 0) { - tusUploader.setChunkSize(getUploadChunkSize()); - } - } - - TusExecutor tusExecutor = new TusExecutor() { - @Override - protected void makeAttempt() throws ProtocolException, IOException { - while (state == State.UPLOADING) { - int chunkUploaded = tusUploader.uploadChunk(); - if (chunkUploaded > 0) { - uploadedBytes += chunkUploaded; - uploadListener.onUploadProgress(uploadedBytes, totalUploadSize); - } else { - // upload is complete - break; - } - } - } - }; - - tusExecutor.makeAttempts(); - if (state != State.UPLOADING) { - // if upload is paused, save the uploader so it can be reused on resume, then leave the method early. - lastTusUploader = tusUploader; - return; - } - - // remove upload instance from list - uploads.remove(0); - tusUploader.finish(); - } - - setState(State.UPLOAD_COMPLETE); - } - - /** - * If tus uploads are enabled, this method would be called by {@link Assembly#save()} to handle the file uploads. - * - * @param response {@link AssemblyResponse} - * @throws IOException when there's a failure with file retrieval. - * @throws ProtocolException when there's a failure with tus upload. - */ - @Override - protected void handleTusUpload(AssemblyResponse response) throws IOException, ProtocolException { - url = response.getSslUrl(); - totalUploadSize = getTotalUploadSize(); - processTusFiles(url, response.getTusUrl()); - startExecutor(); - } - - /** - * Starts the executor that would manage the asynchronous submission of the assembly. - */ - protected void startExecutor() { - executor = new AsyncAssemblyExecutorImpl(new AssemblyRunnable()); - executor.execute(); - } - - class AssemblyRunnable implements Runnable { - private AsyncAssemblyExecutorImpl executor; - - void setExecutor(AsyncAssemblyExecutorImpl executor) { - this.executor = executor; - } - - @Override - public void run() { - try { - uploadTusFiles(); - } catch (ProtocolException e) { - getUploadListener().onUploadFailed(e); - executor.stop(); - return; - } catch (IOException e) { - getUploadListener().onUploadFailed(e); - executor.stop(); - return; - } - - if (state == State.UPLOAD_COMPLETE) { - getUploadListener().onUploadFinished(); - if (!shouldWaitWithSSE() && shouldWaitForCompletion && (getListener() != null)) { - try { - getListener().onAssemblyFinished(watchStatus()); - } catch (LocalOperationException | RequestException e) { - getListener().onAssemblyStatusUpdateFailed(e); - } finally { - executor.stop(); - } - } else { - executor.stop(); - } - } - } - } - - // used for upload progress - private long getTotalUploadSize() throws IOException { - long size = 0; - for (Map.Entry entry : files.entrySet()) { - size += entry.getValue().length(); - } - - for (Map.Entry entry : fileStreams.entrySet()) { - size += entry.getValue().available(); - } - return size; - } - - /** - * Provides a pattern for an AsyncAssemblyExecutor. - */ - protected interface AsyncAssemblyExecutor { - /** - * starts the execution of the assembly on a separate thread. - */ - void execute(); - - /** - * A blocking method that stops the execution of the assembly. - * This method should wait till the execution is stopped if possible. - */ - void hardStop(); - - /** - * A non-blocking method that stops the execution of the assembly. - */ - void stop(); - } - - private class AsyncAssemblyExecutorImpl implements AsyncAssemblyExecutor { - private final ExecutorService service; - private Runnable runnable; - - AsyncAssemblyExecutorImpl(AsyncAssembly.AssemblyRunnable runnable) { - this.runnable = runnable; - runnable.setExecutor(this); - service = Executors.newSingleThreadExecutor(); - } - - @Override - public void execute() { - service.execute(runnable); - } - - @Override - public void hardStop() { - service.shutdown(); - boolean terminated = false; - // wait till shutdown is done - while (!terminated) { - try { - terminated = service.awaitTermination(800, TimeUnit.MILLISECONDS); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - - @Override - public void stop() { - service.shutdown(); - } - } -} diff --git a/src/main/java/com/transloadit/sdk/async/UploadProgressListener.java b/src/main/java/com/transloadit/sdk/async/UploadProgressListener.java deleted file mode 100644 index 9719356..0000000 --- a/src/main/java/com/transloadit/sdk/async/UploadProgressListener.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.transloadit.sdk.async; - -/** - * Deprecated as being a part of {@link AsyncAssembly} - * Implementations of this interface are used to handle progress and completion of a background - * Assembly file upload. - */ -@Deprecated -public interface UploadProgressListener { - - /** - * Callback to be executed when the Assembly upload is complete. - */ - void onUploadFinished(); - - /** - * Callback to be executed as an upload progress receiver. - * - * @param uploadedBytes the number of bytes uploaded so far. - * @param totalBytes the total number of bytes to uploaded (i.e the size of all the files all together). - */ - void onUploadProgress(long uploadedBytes, long totalBytes); - - /** - * Callback to be executed if the Assembly upload fails. - * - * @param exception the error that causes the failure. - */ - void onUploadFailed(Exception exception); - - /** - * Callback to be executed if the Assembly uploads are starting. - * - * @param parallelUploads Number of started uploads. - * @param uploadNumber Number of the specific started upload. - */ - void onParallelUploadsStarting(int parallelUploads, int uploadNumber); -} diff --git a/src/main/java/com/transloadit/sdk/async/package-info.java b/src/main/java/com/transloadit/sdk/async/package-info.java deleted file mode 100644 index 70cab67..0000000 --- a/src/main/java/com/transloadit/sdk/async/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Provides classes for asynchronous Assembly execution. - */ -package com.transloadit.sdk.async; diff --git a/src/test/java/com/transloadit/sdk/async/AsyncAssemblyTest.java b/src/test/java/com/transloadit/sdk/async/AsyncAssemblyTest.java deleted file mode 100644 index e0ba765..0000000 --- a/src/test/java/com/transloadit/sdk/async/AsyncAssemblyTest.java +++ /dev/null @@ -1,291 +0,0 @@ -package com.transloadit.sdk.async; - -//CHECKSTYLE:OFF -// It was necessary to turn off Checkstyle because the import was needed for the links in Javadoc comments, -// but Checkstyle misclassified it as unused. -import com.transloadit.sdk.Assembly; -//CHECKSTYLE:ON -import com.transloadit.sdk.MockHttpService; -import com.transloadit.sdk.exceptions.LocalOperationException; -import com.transloadit.sdk.exceptions.RequestException; -import com.transloadit.sdk.response.AssemblyResponse; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockserver.client.MockServerClient; -import org.mockserver.junit.jupiter.MockServerExtension; -import org.mockserver.junit.jupiter.MockServerSettings; -import org.mockserver.model.HttpRequest; -import org.mockserver.model.HttpResponse; - -import java.io.File; - -import static org.mockserver.model.RegexBody.regex; - -/** - * Unit Test class for {@link AsyncAssembly}. Api-Responses are simulated by mocking the server's response. - */ -@ExtendWith(MockServerExtension.class) // MockServerExtension is used to start and stop the MockServer -@MockServerSettings(ports = MockHttpService.PORT) // MockServerSettings is used to define the port of the MockServer -public class AsyncAssemblyTest extends MockHttpService { - /** - * MockServerClient makes HTTP requests to a MockServer instance. - */ - private final MockServerClient mockServerClient = new MockServerClient("localhost", PORT); - - private AsyncAssembly assembly; - private AssemblyProgressListener listener; - private boolean uploadFinished; - private boolean assemblyFinished; - private long totalUploaded; - private Exception statusUpdateError; - private Exception uploadError; - - - /** - * Sets all variables to the default values before an Assembly execution has taken place. - * Defines basic Mockserver Expectations to support Assembly creation and status updates. - * @throws Exception if Test resources "async_resumable_assembly.json" or "assembly.json" are missing. - */ - @BeforeEach - public void setUp() throws Exception { - mockServerClient.reset(); - listener = new Listener(); - assembly = new MockAsyncAssembly(transloadit, listener); - uploadFinished = false; - assemblyFinished = false; - totalUploaded = 0; - statusUpdateError = null; - uploadError = null; - - // for assembly creation - mockServerClient.when(HttpRequest.request() - .withPath("/assemblies") - .withMethod("POST") - .withBody(regex("[\\w\\W]*tus_num_expected_upload_files\"\\r\\nContent-Length: 1" - + "\\r\\n\\r\\n1[\\w\\W]*"))) - .respond(HttpResponse.response().withBody(getJson("async_resumable_assembly.json"))); - - // for assembly status check - mockServerClient.when(HttpRequest.request() - .withPath("/assemblies/76fe5df1c93a0a530f3e583805cf98b4").withMethod("GET")) - .respond(HttpResponse.response().withBody(getJson("assembly.json"))); - } - - - /** - * This test verifies the functionality of the {@link Assembly#save()} method under the special - * circumstances of an {@link AsyncAssembly}. - * @throws LocalOperationException - if local operations are going wrong - * @throws RequestException - if server communication goes wrong - * @throws InterruptedException - if an error occurs in thread handling - */ - @Test - public void save() throws LocalOperationException, RequestException, InterruptedException { - assembly.addFile(new File("LICENSE"), "file_name"); - AssemblyResponse resumableAssembly = assembly.save(); - - synchronized (listener) { - listener.wait(3000); - } - Assertions.assertEquals(resumableAssembly.json().get("assembly_id"), "76fe5df1c93a0a530f3e583805cf98b4"); - Assertions.assertTrue(uploadFinished); - Assertions.assertTrue(assemblyFinished); - Assertions.assertEquals(1077, totalUploaded); - Assertions.assertNull(statusUpdateError); - Assertions.assertNull(uploadError); - } - - /** - * This test verifies that uploads are possible even without waiting for their completion. - * @throws LocalOperationException - if local operations are going wrong - * @throws RequestException - if server communication goes wrong - * @throws InterruptedException - if an error occurs in thread handling - */ - @Test - public void saveWithoutWaitForCompletion() throws LocalOperationException, RequestException, InterruptedException { - assembly.addFile(new File("LICENSE"), "file_name"); - assembly.setShouldWaitForCompletion(false); - AssemblyResponse resumableAssembly = assembly.save(); - - synchronized (listener) { - listener.wait(3000); - } - Assertions.assertEquals(resumableAssembly.json().get("assembly_id"), "76fe5df1c93a0a530f3e583805cf98b4"); - Assertions.assertTrue(uploadFinished); - Assertions.assertFalse(assemblyFinished); - Assertions.assertEquals(1077, totalUploaded); - Assertions.assertNull(statusUpdateError); - Assertions.assertNull(uploadError); - - mockServerClient.reset(); - } - - /** - * This test checks if the error handling works for {@link AsyncAssembly#save(boolean)} method in case of an - * upload error. - * @throws LocalOperationException - if local operations are going wrong - * @throws RequestException - if server communication goes wrong - * @throws InterruptedException - if an error occurs in thread handling - */ - @Test - public void saveWithUploadError() throws LocalOperationException, RequestException, InterruptedException { - assembly = new MockUploadErrorAsyncAssembly(transloadit, listener); - assembly.addFile(new File("LICENSE"), "file_name"); - AssemblyResponse resumableAssembly = assembly.save(); - - synchronized (listener) { - listener.wait(3000); - } - Assertions.assertEquals(resumableAssembly.json().get("assembly_id"), "76fe5df1c93a0a530f3e583805cf98b4"); - Assertions.assertFalse(uploadFinished); - Assertions.assertFalse(assemblyFinished); - Assertions.assertNotEquals(1077, totalUploaded); - Assertions.assertNull(statusUpdateError); - - Assertions.assertNotNull(uploadError); - Assertions.assertEquals("some error message", uploadError.getMessage()); - } - - /** - * This test checks if the error handling works for {@link AsyncAssembly#save(boolean)} method in case of an - * status error received from the server. - * @throws LocalOperationException - if local operations are going wrong - * @throws RequestException - if server communication goes wrong - * @throws InterruptedException - if an error occurs in thread handling - */ - @Test - public void saveWithStatusError() throws LocalOperationException, RequestException, InterruptedException { - assembly = new MockStatusErrorAsyncAssembly(transloadit, listener); - assembly.addFile(new File("LICENSE"), "file_name"); - AssemblyResponse resumableAssembly = assembly.save(); - - synchronized (listener) { - listener.wait(3000); - } - Assertions.assertEquals(resumableAssembly.json().get("assembly_id"), "76fe5df1c93a0a530f3e583805cf98b4"); - Assertions.assertTrue(uploadFinished); - Assertions.assertEquals(1077, totalUploaded); - Assertions.assertNull(uploadError); - Assertions.assertFalse(assemblyFinished); - - Assertions.assertNotNull(statusUpdateError); - Assertions.assertEquals("some request exception", statusUpdateError.getMessage()); - } - - /** - * This Test verifies that uploads for {@link AsyncAssembly AsyncAssemblies} can be paused and resumed. - * @throws LocalOperationException - if local operations are going wrong - * @throws RequestException - if server communication goes wrong - * @throws InterruptedException - if an error occurs in thread handling - */ - @Test - public void pauseResumeUpload() throws LocalOperationException, RequestException, InterruptedException { - assembly.addFile(new File("LICENSE"), "file_name"); - AssemblyResponse resumableAssembly = assembly.save(); - - // ensure that uploading starts before pausing the upload - synchronized (assembly) { - assembly.wait(3000); - } - - // pause the upload - assembly.pauseUpload(); - - // wait for the listener to get triggered. This is expected to timeout, and not be triggered. - synchronized (listener) { - listener.wait(3000); - } - Assertions.assertEquals(resumableAssembly.json().get("assembly_id"), "76fe5df1c93a0a530f3e583805cf98b4"); - Assertions.assertEquals(MockAsyncAssembly.State.PAUSED, assembly.state); - - // expect the states to not have updated after 5 seconds of wait - Assertions.assertFalse(uploadFinished); - Assertions.assertFalse(assemblyFinished); - Assertions.assertNotEquals(1077, totalUploaded); - Assertions.assertNull(statusUpdateError); - Assertions.assertNull(uploadError); - - // resume upload and wait again - assembly.resumeUpload(); - synchronized (listener) { - listener.wait(3000); - } - - // expect the states to have changed as the upload is done this time. - Assertions.assertTrue(uploadFinished); - Assertions.assertTrue(assemblyFinished); - Assertions.assertEquals(1077, totalUploaded); - Assertions.assertNull(statusUpdateError); - Assertions.assertNull(uploadError); - } - - /** - * Nested class which provides an {@link UploadProgressListener} and {@link AssemblyProgressListener} - * implementation for jUnit Tests. This Implementation must not be used as productive implementation. - */ - class Listener implements UploadProgressListener, AssemblyProgressListener { - - /** - * Always indicates upload has been finished. - */ - @Override - public void onUploadFinished() { - uploadFinished = true; - } - - /** - * Sets upload progress to given value. - * @param uploadedBytes the number of bytes uploaded so far. - * @param totalBytes the total number of bytes to uploaded (i.e the size of all the files all together). - */ - @Override - public void onUploadProgress(long uploadedBytes, long totalBytes) { - totalUploaded = uploadedBytes; - } - - /** - * Always returns {@link AsyncAssemblyTest#assemblyFinished} {@code = true}. - * @param response {@link AssemblyResponse} response with the updated status of the assembly. - */ - @Override - public void onAssemblyFinished(AssemblyResponse response) { - assemblyFinished = true; - synchronized (this) { - notifyAll(); - } - } - - /** - * Hands over Upload exception object to {@link AsyncAssemblyTest#uploadError}. - * @param exception the error that causes the failure. - */ - @Override - public void onUploadFailed(Exception exception) { - uploadError = exception; - synchronized (this) { - notifyAll(); - } - } - - - /** - * Hands over AssemblyStatusUpdate exception object to {@link AsyncAssemblyTest#statusUpdateError}. - * @param exception the error that causes the failure. - */ - @Override - public void onAssemblyStatusUpdateFailed(Exception exception) { - statusUpdateError = exception; - synchronized (this) { - notifyAll(); - } - } - - @Override - public void onParallelUploadsStarting(int parallelUploads, int uploadNumber) { - - } - } -} diff --git a/src/test/java/com/transloadit/sdk/async/MockAsyncAssembly.java b/src/test/java/com/transloadit/sdk/async/MockAsyncAssembly.java deleted file mode 100644 index 816b40c..0000000 --- a/src/test/java/com/transloadit/sdk/async/MockAsyncAssembly.java +++ /dev/null @@ -1,74 +0,0 @@ -package com.transloadit.sdk.async; - -import com.transloadit.sdk.Transloadit; -import io.tus.java.client.ProtocolException; -import io.tus.java.client.TusClient; -import io.tus.java.client.TusUpload; -import io.tus.java.client.TusUploader; -import org.jetbrains.annotations.NotNull; - -import org.mockito.Mockito; - -import java.io.IOException; - -/** - * This class serves as a Mock to {@link AsyncAssembly}, which can be used in tests. -*/ -public class MockAsyncAssembly extends AsyncAssembly { - - /** - * Instantiates a new {@link com.transloadit.sdk.MockTusAssembly} object. - * @param transloadit The {@link Transloadit} client. - * @param listener An {@link UploadProgressListener} - */ - public MockAsyncAssembly(Transloadit transloadit, UploadProgressListener listener) { - super(transloadit, listener); - tusClient = new MockTusClient(); - assemblyId = ""; - } - - /** - * Instantiates a new {@link com.transloadit.sdk.MockTusAssembly} object. - * @param transloadit The {@link Transloadit} client. - * @param listener An {@link AssemblyProgressListener} - */ - public MockAsyncAssembly(Transloadit transloadit, AssemblyProgressListener listener) { - super(transloadit, listener); - tusClient = new MockTusClient(); - assemblyId = ""; - } - - /** - * This method provides functionality to Mock progress on AsyncAssembly execution. - * @param state {@link State} represents states of Assembly execution - */ - @Override - synchronized void setState(State state) { - super.setState(state); - if (this.state == State.UPLOADING) { - synchronized (this) { - this.notifyAll(); - } - } - } - - /** - * This nested class provides a Mock for the {@link TusClient} used by {@link MockAsyncAssembly}. - */ - static class MockTusClient extends TusClient { - /** - * This method returns a mocked {@link TusUploader} to simulate actual file uploads. - * @param upload {@link TusUpload}, not null - * @return a mocked {@link TusUploader} - * @throws ProtocolException if the server sends a request that cannot be processed. - * @throws IOException if source cannot be read or writing to the HTTP request fails. - */ - @Override - public TusUploader resumeOrCreateUpload(@NotNull TusUpload upload) throws ProtocolException, IOException { - TusUploader uploader = Mockito.mock(TusUploader.class); - // 1077 / 3 = 359 i.e size of the LICENSE file - Mockito.when(uploader.uploadChunk()).thenReturn(359, 359, 359, 0, -1); - return uploader; - } - } -} diff --git a/src/test/java/com/transloadit/sdk/async/MockStatusErrorAsyncAssembly.java b/src/test/java/com/transloadit/sdk/async/MockStatusErrorAsyncAssembly.java deleted file mode 100644 index 365889b..0000000 --- a/src/test/java/com/transloadit/sdk/async/MockStatusErrorAsyncAssembly.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.transloadit.sdk.async; - -import com.transloadit.sdk.Transloadit; -import com.transloadit.sdk.exceptions.RequestException; -import com.transloadit.sdk.response.AssemblyResponse; - -/** - * This class Mocks an {@link AsyncAssembly}, which has an error during execution. - */ -public class MockStatusErrorAsyncAssembly extends AsyncAssembly { - - /** - * Instantiates an {@link AsyncAssembly} object which always throws an error if {@link AsyncAssembly#watchStatus()} - * is called. - * @param transloadit The {@link Transloadit} client. - * @param listener An {@link UploadProgressListener} - */ - public MockStatusErrorAsyncAssembly(Transloadit transloadit, UploadProgressListener listener) { - super(transloadit, listener); - tusClient = new MockAsyncAssembly.MockTusClient(); - assemblyId = ""; - } - - /** - * Instantiates an {@link AsyncAssembly} object which always throws an error if {@link AsyncAssembly#watchStatus()} - * is called. - * @param transloadit The {@link Transloadit} client. - * @param listener An {@link AssemblyProgressListener} - */ - public MockStatusErrorAsyncAssembly(Transloadit transloadit, AssemblyProgressListener listener) { - super(transloadit, listener); - tusClient = new MockAsyncAssembly.MockTusClient(); - assemblyId = ""; - } - - /** - * Always throws an Exception if status gets observed. - * @return only throws Exception - * @throws RequestException always - */ - @Override - protected AssemblyResponse watchStatus() throws RequestException { - throw new RequestException("some request exception"); - } -} diff --git a/src/test/java/com/transloadit/sdk/async/MockUploadErrorAsyncAssembly.java b/src/test/java/com/transloadit/sdk/async/MockUploadErrorAsyncAssembly.java deleted file mode 100644 index ffbcfa4..0000000 --- a/src/test/java/com/transloadit/sdk/async/MockUploadErrorAsyncAssembly.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.transloadit.sdk.async; - -import com.transloadit.sdk.Transloadit; -import io.tus.java.client.ProtocolException; -import io.tus.java.client.TusClient; -import io.tus.java.client.TusUpload; -import io.tus.java.client.TusUploader; -import org.jetbrains.annotations.NotNull; -import org.mockito.Mockito; - -import java.io.IOException; - -/** - * This class Mocks an {@link AsyncAssembly}, which has an error during upload. - */ -public class MockUploadErrorAsyncAssembly extends AsyncAssembly { - /** - * Instantiates an {@link AsyncAssembly} object which always throws an error if a file upload attempt is undertaken. - * @param transloadit The {@link Transloadit} client. - * @param listener An {@link UploadProgressListener} - */ - public MockUploadErrorAsyncAssembly(Transloadit transloadit, UploadProgressListener listener) { - super(transloadit, listener); - tusClient = new MockTusClient(); - assemblyId = ""; - } - - /** - * Instantiates an {@link AsyncAssembly} object which always throws an error if a file upload attempt is undertaken. - * @param transloadit The {@link Transloadit} client. - * @param listener An {@link AssemblyProgressListener} - */ - public MockUploadErrorAsyncAssembly(Transloadit transloadit, AssemblyProgressListener listener) { - super(transloadit, listener); - tusClient = new MockTusClient(); - assemblyId = ""; - } - - /** - * Nested class which provides a mocked {@link TusUploader}, which always throws an exception if - * {@link TusUploader#uploadChunk()} gets called. - */ - class MockTusClient extends TusClient { - /** - * Instantiates a a mocked {@link TusUploader}, which always throws an exception if - * {@link TusUploader#uploadChunk()} gets called. - * @param upload {@link TusUpload} - * @return {@link TusUploader}, which always throws an exception if {@link TusUploader#uploadChunk()} gets - * called. - * @throws ProtocolException if {@link TusUploader#uploadChunk()} gets called. - * @throws IOException if an IOError occurs. - */ - @Override - public TusUploader resumeOrCreateUpload(@NotNull TusUpload upload) throws ProtocolException, IOException { - TusUploader uploader = Mockito.mock(TusUploader.class); - Mockito.when(uploader.uploadChunk()).thenThrow(new ProtocolException("some error message")); - return uploader; - } - } -} diff --git a/src/test/java/com/transloadit/sdk/async/package-info.java b/src/test/java/com/transloadit/sdk/async/package-info.java deleted file mode 100644 index 032410b..0000000 --- a/src/test/java/com/transloadit/sdk/async/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Contains jUNIT test classes for checking the functionality of the Async-Assembly classes. - */ -package com.transloadit.sdk.async;