diff --git a/src/main/java/com/cdancy/bitbucket/rest/BitbucketApi.java b/src/main/java/com/cdancy/bitbucket/rest/BitbucketApi.java index 2c0aae47..c6272f7a 100644 --- a/src/main/java/com/cdancy/bitbucket/rest/BitbucketApi.java +++ b/src/main/java/com/cdancy/bitbucket/rest/BitbucketApi.java @@ -35,12 +35,10 @@ import com.cdancy.bitbucket.rest.features.TagApi; import com.cdancy.bitbucket.rest.features.TasksApi; import com.cdancy.bitbucket.rest.features.WebHookApi; - - +import com.cdancy.bitbucket.rest.features.SupportApi; import org.jclouds.rest.annotations.Delegate; public interface BitbucketApi extends Closeable { - @Delegate AdminApi adminApi(); @@ -83,6 +81,9 @@ public interface BitbucketApi extends Closeable { @Delegate SystemApi systemApi(); + @Delegate + SupportApi supportApi(); + @Delegate TagApi tagApi(); diff --git a/src/main/java/com/cdancy/bitbucket/rest/domain/support/SupportZip.java b/src/main/java/com/cdancy/bitbucket/rest/domain/support/SupportZip.java new file mode 100644 index 00000000..7106a81a --- /dev/null +++ b/src/main/java/com/cdancy/bitbucket/rest/domain/support/SupportZip.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.cdancy.bitbucket.rest.domain.support; + +import com.cdancy.bitbucket.rest.BitbucketUtils; +import com.cdancy.bitbucket.rest.domain.common.Error; +import com.cdancy.bitbucket.rest.domain.common.ErrorsHolder; +import com.google.auto.value.AutoValue; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; +import java.util.List; + +@AutoValue +public abstract class SupportZip implements ErrorsHolder { + public abstract String taskId(); + + public abstract Integer progressPercentage(); + + public abstract String progressMessage(); + + public abstract List warnings(); + + public abstract String status(); + + @Nullable + public abstract String fileName(); + + @SerializedNames({"taskId", "progressPercentage", "progressMessage", + "warnings", "status", "fileName", + "errors"}) + public static SupportZip create(final String taskId, + final Integer progressPercentage, + final String progressMessage, + final List warnings, + final String status, + final String fileName, + final List errors) { + return new AutoValue_SupportZip(BitbucketUtils.nullToEmpty(errors), + taskId, + progressPercentage, + progressMessage, + warnings, + status, + fileName); + } + +} diff --git a/src/main/java/com/cdancy/bitbucket/rest/fallbacks/BitbucketFallbacks.java b/src/main/java/com/cdancy/bitbucket/rest/fallbacks/BitbucketFallbacks.java index 99bd9c45..7582769a 100644 --- a/src/main/java/com/cdancy/bitbucket/rest/fallbacks/BitbucketFallbacks.java +++ b/src/main/java/com/cdancy/bitbucket/rest/fallbacks/BitbucketFallbacks.java @@ -66,6 +66,7 @@ import com.cdancy.bitbucket.rest.domain.repository.RepositoryPage; import com.cdancy.bitbucket.rest.domain.repository.WebHook; import com.cdancy.bitbucket.rest.domain.repository.WebHookPage; +import com.cdancy.bitbucket.rest.domain.support.SupportZip; import com.cdancy.bitbucket.rest.domain.sync.SyncState; import com.cdancy.bitbucket.rest.domain.sync.SyncStatus; import com.cdancy.bitbucket.rest.domain.tags.Tag; @@ -361,6 +362,16 @@ public Object createOrPropagate(final Throwable throwable) throws Exception { } } + public static final class SupportZipOnError implements Fallback { + @Override + public Object createOrPropagate(final Throwable throwable) throws Exception { + if (checkNotNull(throwable, "throwable") != null) { + return createSupportZipFromErrors(getErrors(throwable.getMessage())); + } + throw propagate(throwable); + } + } + public static final class SyncStatusOnError implements Fallback { @Override public Object createOrPropagate(final Throwable throwable) throws Exception { @@ -663,6 +674,11 @@ public static PullRequest createPullRequestFromErrors(final List errors) null, null, errors); } + public static SupportZip createSupportZipFromErrors(final List errors) { + return SupportZip.create(null, 0, null, + null, null, null, errors); + } + public static SyncState createSyncStateFromErrors(final List errors) { return SyncState.create(null, null, null, null, errors); } diff --git a/src/main/java/com/cdancy/bitbucket/rest/features/SupportApi.java b/src/main/java/com/cdancy/bitbucket/rest/features/SupportApi.java new file mode 100644 index 00000000..7d6016a9 --- /dev/null +++ b/src/main/java/com/cdancy/bitbucket/rest/features/SupportApi.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.cdancy.bitbucket.rest.features; + +import com.cdancy.bitbucket.rest.annotations.Documentation; +import com.cdancy.bitbucket.rest.domain.support.SupportZip; +import com.cdancy.bitbucket.rest.filters.BitbucketAuthenticationFilter; +import com.cdancy.bitbucket.rest.fallbacks.BitbucketFallbacks.SupportZipOnError; +import org.jclouds.rest.annotations.Fallback; +import org.jclouds.rest.annotations.RequestFilters; +import javax.inject.Named; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +@Produces(MediaType.APPLICATION_JSON) +@RequestFilters(BitbucketAuthenticationFilter.class) +@Path("/rest/troubleshooting/latest/support-zip") +@SuppressWarnings("PMD.AvoidDuplicateLiterals") +public interface SupportApi { + + @Named("support-zip:create") + @Documentation("https://confluence.atlassian.com/support/create-a-support-zip-using-the-rest-api-in-server-applications-947857090.html#CreateasupportzipusingtheRESTAPIinServerapplications-Generateasupportzip") + @Consumes(MediaType.APPLICATION_JSON) + @Path("/local") + @Fallback(SupportZipOnError.class) + @POST + SupportZip createSupportZip(); + + @Named("support-zip:status") + @Documentation("https://confluence.atlassian.com/support/create-a-support-zip-using-the-rest-api-in-server-applications-947857090.html#CreateasupportzipusingtheRESTAPIinServerapplications-Checktheprogressofthetask") + @Consumes(MediaType.APPLICATION_JSON) + @Path("/status/task/{taskId}") + @Fallback(SupportZipOnError.class) + @GET + SupportZip getSupportZipStatus(@PathParam("taskId") String taskId); +} diff --git a/src/test/java/com/cdancy/bitbucket/rest/features/SupportApiLiveTest.java b/src/test/java/com/cdancy/bitbucket/rest/features/SupportApiLiveTest.java new file mode 100644 index 00000000..66b1cf92 --- /dev/null +++ b/src/test/java/com/cdancy/bitbucket/rest/features/SupportApiLiveTest.java @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.cdancy.bitbucket.rest.features; + +import static org.assertj.core.api.Assertions.assertThat; +import com.cdancy.bitbucket.rest.BaseBitbucketApiLiveTest; +import com.cdancy.bitbucket.rest.domain.support.SupportZip; +import org.testng.annotations.Test; + +@Test(groups = "live", testName = "SupportApiLiveTest", singleThreaded = true) +public class SupportApiLiveTest extends BaseBitbucketApiLiveTest { + private String taskIdRegex = "^\\w+\\-+\\w+\\-+\\w+\\-+\\w+\\-+\\w+$"; + + private SupportApi api() { + return api.supportApi(); + } + + @Test + public void testSupportZipCreation() { + final SupportZip supportZipTask = api().createSupportZip(); + assertIntegrity(supportZipTask); + } + + @Test + public void testSupportZipStatus() { + SupportZip supportZipTask = api().createSupportZip(); + supportZipTask = api().getSupportZipStatus(supportZipTask.taskId()); + assertIntegrity(supportZipTask); + assertThat(supportZipTask.fileName()).isNotNull(); + } + + private void assertIntegrity(final SupportZip supportZipTask) { + assertTaskId(supportZipTask.taskId()); + assertTaskProgressPercentage(supportZipTask.progressPercentage()); + assertTaskProgressMessage(supportZipTask.progressMessage()); + assertTaskStatus(supportZipTask.status()); + assertErrors(supportZipTask); + } + + private void assertErrors(final SupportZip supportZip) { + assertThat(supportZip.errors().isEmpty()).isTrue(); + } + + private void assertTaskProgressMessage(final String progressMessage) { + assertThat(progressMessage).isNotNull(); + } + + private void assertTaskStatus(final String status) { + assertThat(!status.isEmpty()).isTrue(); + } + + private void assertTaskId(final String taskId) { + assertThat(taskId).isNotNull(); + assertThat(taskId.matches(taskIdRegex)).isTrue(); + } + + private void assertTaskProgressPercentage(final Integer progressPercentage) { + assertThat(progressPercentage).isNotNull(); + } +} diff --git a/src/test/java/com/cdancy/bitbucket/rest/features/SupportApiMockTest.java b/src/test/java/com/cdancy/bitbucket/rest/features/SupportApiMockTest.java new file mode 100644 index 00000000..3551b61f --- /dev/null +++ b/src/test/java/com/cdancy/bitbucket/rest/features/SupportApiMockTest.java @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.cdancy.bitbucket.rest.features; + +import static org.assertj.core.api.Assertions.assertThat; +import com.cdancy.bitbucket.rest.BaseBitbucketMockTest; +import com.cdancy.bitbucket.rest.domain.support.SupportZip; +import com.squareup.okhttp.mockwebserver.MockResponse; +import com.squareup.okhttp.mockwebserver.MockWebServer; +import org.testng.Assert; +import org.testng.annotations.Test; + +/** + * Mock tests for the {@link SupportApi} class. + */ +@Test(groups = "unit", testName = "SupportApiMockTest") +public class SupportApiMockTest extends BaseBitbucketMockTest { + + private String taskIdRegex = "^\\w+\\-+\\w+\\-+\\w+\\-+\\w+\\-+\\w+$"; + private String supportZipRestApiPath = "/rest/troubleshooting/latest/support-zip" ; + + public void testSupportZipCreation() throws Exception { + final MockWebServer mockWebServer = mockWebServer(); + mockWebServer.enqueue(new MockResponse().setBody(payloadFromResource("/support-zip-create.json")).setResponseCode(200)); + try { + final SupportApi supportApi = api(mockWebServer.getUrl("/")).supportApi() ; + final SupportZip supportZip = supportApi.createSupportZip(); + + assertSupportZipCreateRequest(mockWebServer); + assertIntegrity(supportZip); + } finally { + mockWebServer.shutdown(); + } + } + + public void testSupportZipStatus() throws Exception { + final MockWebServer mockWebServer = mockWebServer(); + mockWebServer.enqueue(new MockResponse().setBody(payloadFromResource("/support-zip-create.json")).setResponseCode(200)); + mockWebServer.enqueue(new MockResponse().setBody(payloadFromResource("/support-zip-request-status.json")).setResponseCode(200)); + try { + final SupportApi supportApi = api(mockWebServer.getUrl("/")).supportApi() ; + SupportZip supportZip = supportApi.createSupportZip(); + supportZip = supportApi.getSupportZipStatus(supportZip.taskId()); + + assertSupportZipCreateRequest(mockWebServer); + assertIntegritySupportZipStatus(supportZip); + assertSupportZipStatusRequest(mockWebServer, supportZip.taskId()); + } finally { + mockWebServer.shutdown(); + } + } + + private void assertIntegritySupportZipStatus(final SupportZip supportZip) { + assertIntegrity(supportZip); + Assert.assertNotNull(supportZip.fileName()); + } + + private void assertIntegrity(final SupportZip supportZip) { + Assert.assertNotNull(supportZip.progressMessage()); + assertThat(supportZip.taskId().matches(taskIdRegex)).isTrue(); + Assert.assertNotNull(supportZip.progressPercentage()); + Assert.assertNotNull(supportZip.status()); + } + + private void assertSupportZipCreateRequest(final MockWebServer mockWebServer) + throws InterruptedException { + assertSent(mockWebServer, "POST", supportZipRestApiPath + "/local"); + } + + private void assertSupportZipStatusRequest(final MockWebServer mockWebServer, final String taskId) + throws InterruptedException { + assertSent(mockWebServer, "GET", supportZipRestApiPath + "/status/task/" + taskId); + } +} diff --git a/src/test/java/com/cdancy/bitbucket/rest/features/SystemApiLiveTest.java b/src/test/java/com/cdancy/bitbucket/rest/features/SystemApiLiveTest.java index 9d1f7865..b7074dfc 100644 --- a/src/test/java/com/cdancy/bitbucket/rest/features/SystemApiLiveTest.java +++ b/src/test/java/com/cdancy/bitbucket/rest/features/SystemApiLiveTest.java @@ -20,7 +20,6 @@ import static org.assertj.core.api.Assertions.assertThat; import org.testng.annotations.Test; - import com.cdancy.bitbucket.rest.BaseBitbucketApiLiveTest; import com.cdancy.bitbucket.rest.domain.system.Version; diff --git a/src/test/resources/support-zip-create.json b/src/test/resources/support-zip-create.json new file mode 100644 index 00000000..50c2f529 --- /dev/null +++ b/src/test/resources/support-zip-create.json @@ -0,0 +1,7 @@ +{ + "taskId": "cf27e653-d3af-4202-bcc8-79d836432b0b", + "progressPercentage": 0, + "progressMessage": "", + "warnings": [], + "status": "IN_PROGRESS" +} \ No newline at end of file diff --git a/src/test/resources/support-zip-request-status.json b/src/test/resources/support-zip-request-status.json new file mode 100644 index 00000000..ec8291ee --- /dev/null +++ b/src/test/resources/support-zip-request-status.json @@ -0,0 +1,8 @@ +{ + "taskId": "cf27e653-d3af-4202-bcc8-79d836432b0b", + "progressPercentage": 100, + "progressMessage": "It was saved to C:\\Atlassian\\ApplicationData\\Bitbucket\\shared\\export\\Bitbucket_support_2019-06-17-00-23-13.zip.", + "fileName": "Bitbucket_support_2019-06-17-00-23-13.zip", + "warnings": [], + "status": "COMPLETE_WITH_WARNING" +} \ No newline at end of file