Code review comment: I would prefer hamcrest for a proper failure message:  ``` import static org.hamcrest.Matchers.containsString; import static org.junit.Assert.assertThat; ... assertThat(expected.get().getMessage(), containsString("ZipException")) ```

Code under review:
public void testRunJar() throws Exception {
		Path uploadDir = TMP.newFolder().toPath();

		Path actualUploadDir = uploadDir.resolve("flink-web-upload");
		Files.createDirectory(actualUploadDir);

		Path emptyJar = actualUploadDir.resolve("empty.jar");
		Files.createFile(emptyJar);

		Configuration config = new Configuration();
		config.setString(WebOptions.UPLOAD_DIR, uploadDir.toString());

		MiniClusterResource clusterResource = new MiniClusterResource(
			new MiniClusterResourceConfiguration.Builder()
				.setConfiguration(config)
				.setNumberTaskManagers(1)
				.setNumberSlotsPerTaskManager(1)
				.build());
		clusterResource.before();

		try {
			Configuration clientConfig = clusterResource.getClientConfiguration();
			RestClient client = new RestClient(RestClientConfiguration.fromConfiguration(clientConfig), TestingUtils.defaultExecutor());

			try {
				JarRunHeaders headers = JarRunHeaders.getInstance();
				JarRunMessageParameters parameters = headers.getUnresolvedMessageParameters();
				parameters.jarIdPathParameter.resolve(emptyJar.getFileName().toString());

				String host = clientConfig.getString(RestOptions.ADDRESS);
				int port = clientConfig.getInteger(RestOptions.PORT);

				try {
					client.sendRequest(host, port, headers, parameters, new JarRunRequestBody())
						.get();
				} catch (Exception e) {
					Optional<RestClientException> expected = ExceptionUtils.findThrowable(e, RestClientException.class);
					if (expected.isPresent()) {
						
						assertTrue(expected.get().getMessage().contains("ProgramInvocationException"));
						
						assertTrue(expected.get().getMessage().contains("ZipException"));
						
						
						assertTrue(expected.get().getMessage().contains("empty.jar'. zip file is empty"));
					} else {
						throw e;
					}
				}
			} finally {
				client.shutdown(Time.milliseconds(10));
			}
		} finally {
			clusterResource.after();
		}
	}

Line commented on: assertTrue(expected.get().getMessage().contains("ZipException"));

Revised code:
public void testRunJar() throws Exception {
		Path uploadDir = TMP.newFolder().toPath();

		Path actualUploadDir = uploadDir.resolve("flink-web-upload");
		Files.createDirectory(actualUploadDir);

		Path emptyJar = actualUploadDir.resolve("empty.jar");
		Files.createFile(emptyJar);

		Configuration config = new Configuration();
		config.setString(WebOptions.UPLOAD_DIR, uploadDir.toString());

		MiniClusterResource clusterResource = new MiniClusterResource(
			new MiniClusterResourceConfiguration.Builder()
				.setConfiguration(config)
				.setNumberTaskManagers(1)
				.setNumberSlotsPerTaskManager(1)
				.build());
		clusterResource.before();

		try {
			Configuration clientConfig = clusterResource.getClientConfiguration();
			RestClient client = new RestClient(RestClientConfiguration.fromConfiguration(clientConfig), TestingUtils.defaultExecutor());

			try {
				JarRunHeaders headers = JarRunHeaders.getInstance();
				JarRunMessageParameters parameters = headers.getUnresolvedMessageParameters();
				parameters.jarIdPathParameter.resolve(emptyJar.getFileName().toString());

				String host = clientConfig.getString(RestOptions.ADDRESS);
				int port = clientConfig.getInteger(RestOptions.PORT);

				try {
					client.sendRequest(host, port, headers, parameters, new JarRunRequestBody())
						.get();
				} catch (Exception e) {
					Optional<RestClientException> expected = ExceptionUtils.findThrowable(e, RestClientException.class);
					if (expected.isPresent()) {
						
						assertTrue(expected.get().getMessage().contains("ProgramInvocationException"));
						
						assertThat(expected.get().getMessage(), containsString("ZipException"));
						
						
						assertTrue(expected.get().getMessage().contains("empty.jar'. zip file is empty"));
					} else {
						throw e;
					}
				}
			} finally {
				client.shutdown(Time.milliseconds(10));
			}
		} finally {
			clusterResource.after();
		}
	}