Skip to content
This repository has been archived by the owner on Oct 7, 2022. It is now read-only.

Commit

Permalink
(#145) Fail build if code coverage target is not met (#147)
Browse files Browse the repository at this point in the history
(NEW) pom.xml: cobertura configuration set to 85% target
(NEW) .travis.yml: cobertura execution now fails if target coverage
      is not met
(REF) CONTRIBUTING.md: updated documentation accordingly
(FIX) Added a few unit tests to meet target coverage:
      - BadRequestTest
      - ForbiddenResponseTest
      - InternalServerErrorResponseTest
      - PageTest
      - UnauthorizedResponseTest
(REF) Pagination: field declared as Supplier<HttpUriRequest> instead
      of PageUri so that cobertura would stop saying that the
      'Supplier' contract of PageUri was not being tested
(NEW) A few more HTTP mocks to support tests:
      - MockThrowingHttpClient
      - MockBadRequestResponse
      - MockInternalErrorResponse
      - MockUnauthorizedResponse

* (#145) Fail build if code coverage target is not met

(FIX) Build was not generating coverage report
  • Loading branch information
llorllale committed Jan 14, 2018
1 parent 0afc119 commit cd1cae2
Show file tree
Hide file tree
Showing 17 changed files with 995 additions and 31 deletions.
4 changes: 2 additions & 2 deletions .travis.yml
Expand Up @@ -17,7 +17,7 @@ jobs:
- if: type = pull_request
script:
- mvn -P release-profile -DskipTests=true clean install
- mvn -P integration-tests clean cobertura:cobertura-integration-test
- mvn -P integration-tests clean cobertura:cobertura-integration-test && mvn -DskipTests=true cobertura:check-integration-test
- bash <(curl -s https://codecov.io/bash)
- if: type = push AND tag IS present
script:
Expand All @@ -36,7 +36,7 @@ jobs:
branch: master
- if: type = push AND NOT tag IS present AND branch = master
script:
- mvn -P integration-tests clean cobertura:cobertura-integration-test
- mvn -P integration-tests clean cobertura:cobertura-integration-test && mvn -DskipTests=true cobertura:check-integration-test
- bash <(curl -s https://codecov.io/bash)
- mvn -P release-profile -DskipTests=true clean install
- openssl aes-256-cbc -K $encrypted_af28e35ab9a0_key -iv $encrypted_af28e35ab9a0_iv
Expand Down
9 changes: 5 additions & 4 deletions CONTRIBUTING.md
Expand Up @@ -40,9 +40,10 @@ integration-tests if applicable.
Coverage is reported via [CodeCov.io](https://codecov.io/gh/llorllale/youtrack-api)
and also the [project's site](https://llorllale.github.io/youtrack-api/cobertura/).

**The current minimum target coverage is 80%.**
**The current minimum target coverage is 85%.**

#### Run the tests
To run the unit tests simply run `mvn test`. To run the integration tests run
`mvn -P integration-tests clean verify` (make sure your docker environment is
setup as mentioned before).
* To run the unit tests: `mvn test`.
* To run unit and integration tests: `mvn -P integration-tests clean verify`
(make sure your docker environment is setup as mentioned before).
* To run all tests and verify coverage: `mvn -P integration-tests clean cobertura:check-integration-test`
10 changes: 9 additions & 1 deletion pom.xml
Expand Up @@ -422,7 +422,15 @@
<artifactId>cobertura-maven-plugin</artifactId>
<version>2.7</version>
<configuration>
<check/>
<check>
<branchRate>0</branchRate>
<lineRate>85</lineRate>
<haltOnFailure>true</haltOnFailure>
<totalBranchRate>85</totalBranchRate>
<totalLineRate>85</totalLineRate>
<packageLineRate>85</packageLineRate>
<packageBranchRate>85</packageBranchRate>
</check>
<formats>
<format>html</format>
<format>xml</format>
Expand Down
8 changes: 1 addition & 7 deletions src/main/java/org/llorllale/youtrack/api/BadRequest.java
Expand Up @@ -47,13 +47,7 @@ final class BadRequest implements Response {
@Override
public HttpResponse httpResponse() throws IOException, UnauthorizedException {
if (this.response.httpResponse().getStatusLine().getStatusCode() == HttpStatus.SC_BAD_REQUEST) {
throw new IOException(
String.format("Server returned 400 Bad Request. Payload: %s",
new InputStreamAsString().apply(
this.response.httpResponse().getEntity().getContent()
)
)
);
throw new IOException("400 BadRequest");
}

return this.response.httpResponse();
Expand Down
Expand Up @@ -47,12 +47,7 @@ final class InternalServerErrorResponse implements Response {
public HttpResponse httpResponse() throws IOException, UnauthorizedException {
if (this.base.httpResponse().getStatusLine().getStatusCode()
== HttpStatus.SC_INTERNAL_SERVER_ERROR) {
throw new IOException(
String.format("500 Internal Server error. Payload: %s",
new InputStreamAsString().apply(this.base.httpResponse().getEntity().getContent()
)
)
);
throw new IOException("500 Internal Server error");
}

return this.base.httpResponse();
Expand Down
5 changes: 3 additions & 2 deletions src/main/java/org/llorllale/youtrack/api/Pagination.java
Expand Up @@ -21,6 +21,7 @@
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.function.Function;
import java.util.function.Supplier;
import org.apache.http.client.HttpClient;

import org.apache.http.client.methods.HttpUriRequest;
Expand All @@ -37,7 +38,7 @@
* @since 0.7.0
*/
final class Pagination<T> implements Iterator<T> {
private final PageUri pageRequest;
private final Supplier<HttpUriRequest> pageRequest;
private final ExceptionalFunction<Response, Collection<T>, IOException> mapper;
private final HttpClient httpClient;

Expand All @@ -52,7 +53,7 @@ final class Pagination<T> implements Iterator<T> {
* @since 0.7.0
*/
Pagination(
PageUri pageRequest,
Supplier<HttpUriRequest> pageRequest,
ExceptionalFunction<Response, Collection<T>, IOException> mapper,
HttpClient httpClient
) {
Expand Down
19 changes: 10 additions & 9 deletions src/main/java/org/llorllale/youtrack/api/UncheckedUriBuilder.java
Expand Up @@ -26,7 +26,7 @@
* <p>Hides all {@link URISyntaxException}s.</p>
*
* <p>This class uses the {@link URIBuilder} internally but does not expose the aforementioned
* exception. A {@link RuntimeException} is thrown if the internal {@link URIBuilder} throws
* exception. A {@link UncheckedException} is thrown if the internal {@link URIBuilder} throws
* {@link URISyntaxException}.</p>
*
* <p>The main motivator for this class is to reduce all the {@code try...catch} noise in the
Expand All @@ -42,14 +42,14 @@ final class UncheckedUriBuilder {
* Constructs the internal {@link URIBuilder} with the given {@code baseUrl}.
*
* @param baseUrl an initial url
* @throws RuntimeException wrapping any internal {@link URISyntaxException}
* @throws UncheckedException wrapping any internal {@link URISyntaxException}
* @since 0.1.0
*/
UncheckedUriBuilder(String baseUrl) {
UncheckedUriBuilder(String baseUrl) throws UncheckedException {
try {
this.builder = new URIBuilder(baseUrl);
} catch (URISyntaxException e) {
throw new RuntimeException(
throw new UncheckedException(
String.format("This should not have happened: syntax issue with URL: %s", baseUrl),
e
);
Expand All @@ -61,10 +61,11 @@ final class UncheckedUriBuilder {
*
* @param baseUrl the URL for the YouTrack RESTful endpoint API
* @param path the resource's sub-path
* @throws UncheckedException wrapping any internal {@link URISyntaxException}
* @see <a href="https://stackoverflow.com/a/724764/1623885">StackOverflow</a>
* @since 1.0.0
*/
UncheckedUriBuilder(URL baseUrl, String path) {
UncheckedUriBuilder(URL baseUrl, String path) throws UncheckedException {
try {
this.builder = new URIBuilder(
new URI(
Expand All @@ -78,7 +79,7 @@ final class UncheckedUriBuilder {
)
);
} catch (URISyntaxException e) {
throw new RuntimeException(
throw new UncheckedException(
String.format(
"This should not have happened: syntax issue baseUrl=%s path=%s",
baseUrl.toString(), path
Expand Down Expand Up @@ -119,14 +120,14 @@ public UncheckedUriBuilder paramIfPresent(String name, Optional<String> value) {
* Builds the {@link URI}.
*
* @return the {@link URI} built by the internal {@link URIBuilder}
* @throws RuntimeException wrapping any internal {@link URISyntaxException}
* @throws UncheckedException wrapping any internal {@link URISyntaxException}
* @since 0.1.0
*/
public URI build() {
public URI build() throws UncheckedException {
try {
return this.builder.build();
} catch (URISyntaxException e) {
throw new RuntimeException("This should not have happened: syntax issue with a URL", e);
throw new UncheckedException("This should not have happened: syntax issue with a URL", e);
}
}
}
39 changes: 39 additions & 0 deletions src/test/java/org/llorllale/youtrack/api/BadRequestTest.java
@@ -0,0 +1,39 @@
/*
* Copyright 2018 George Aristy.
*
* Licensed 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 org.llorllale.youtrack.api;

import java.io.IOException;
import org.junit.Test;
import org.llorllale.youtrack.api.mock.http.response.MockBadRequestResponse;

/**
*
* @author George Aristy (george.aristy@gmail.com)
* @since 1.0.0-SNAPSHOT
*/
public class BadRequestTest {

/**
* Should throw {@link IOException} if server returns error code 400.
*
* @since 1.0.0
*/
@Test(expected = IOException.class)
public void testHttpResponse() throws Exception {
new BadRequest(() -> new MockBadRequestResponse()).httpResponse();
}
}
@@ -0,0 +1,40 @@
/*
* Copyright 2018 George Aristy.
*
* Licensed 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 org.llorllale.youtrack.api;

import org.junit.Test;
import org.llorllale.youtrack.api.mock.http.response.MockForbiddenResponse;
import org.llorllale.youtrack.api.session.UnauthorizedException;

/**
* Unit tests for {@link ForbiddenResponse}.
*
* @author George Aristy (george.aristy@gmail.com)
* @since 1.0.0
*/
public class ForbiddenResponseTest {

/**
* Should throw {@link UnauthorizedException} if server returns error code 403.
*
* @since 1.0.0
*/
@Test(expected = UnauthorizedException.class)
public void testHttpResponse() throws Exception {
new ForbiddenResponse(() -> new MockForbiddenResponse()).httpResponse();
}
}
@@ -0,0 +1,41 @@
/*
* Copyright 2018 George Aristy.
*
* Licensed 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 org.llorllale.youtrack.api;

import java.io.IOException;
import org.junit.Test;
import org.llorllale.youtrack.api.mock.http.response.MockInternalErrorResponse;

/**
* Unit tests for {@link InternalServerErrorResponse}.
*
* @author George Aristy (george.aristy@gmail.com)
* @since 1.0.0
*/
public class InternalServerErrorResponseTest {

/**
* Should throw an {@link IOException} if the YouTrack server returns an HTTP response with
* code 500.
*
* @since 1.0.0
*/
@Test(expected = IOException.class)
public void testHttpResponse() throws Exception {
new InternalServerErrorResponse(() -> new MockInternalErrorResponse()).httpResponse();
}
}
83 changes: 83 additions & 0 deletions src/test/java/org/llorllale/youtrack/api/PageTest.java
@@ -0,0 +1,83 @@
/*
* Copyright 2018 George Aristy.
*
* Licensed 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 org.llorllale.youtrack.api;

import java.util.Collections;
import java.util.NoSuchElementException;
import static org.junit.Assert.assertFalse;
import org.junit.Test;
import org.llorllale.youtrack.api.mock.http.MockHttpClient;
import org.llorllale.youtrack.api.mock.http.MockThrowingHttpClient;
import org.llorllale.youtrack.api.mock.http.response.MockOkResponse;

/**
* Unit tests for {@link Page}.
*
* @author George Aristy (george.aristy@gmail.com)
* @since 1.0.0
*/
public class PageTest {
/**
* Ctor must wrap IOExceptions in UncheckedException.
*
* @since 1.0.0
*/
@Test(expected = UncheckedException.class)
public void ctorUncheckedExceptionThrow() {
new Page<>(
null,
r -> Collections.<String>emptyList(),
new MockThrowingHttpClient()
);
}

/**
* next() must throw NoSuchElementException if contents is empty.
*
* @since 1.0.0
*/
@Test(expected = NoSuchElementException.class)
public void nextNoSuchElementException() {
new Page<>(
null,
r -> Collections.<String>emptyList(),
new MockHttpClient(new MockOkResponse())
).next();
}

/**
* Page.Empty.hasNext() should always return {@code false}.
*
* @since 1.0.0
*/
@Test
public void emptyHasNextAlwaysFalse() {
assertFalse(
new Page.Empty<>().hasNext()
);
}

/**
* Page.Empty.next() should always throw {@link NoSuchElementException}.
*
* @since 1.0.0
*/
@Test(expected = NoSuchElementException.class)
public void emptyNextAlwaysThrowsNoSuchElementException() {
new Page.Empty<>().next();
}
}

0 comments on commit cd1cae2

Please sign in to comment.