Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
c422241
add jacoco plugin
YBushi Jun 8, 2024
9aa0841
Create .gitattributes
YBushi Jun 8, 2024
759e955
Normalize all line endings to LF
YBushi Jun 8, 2024
56f0a96
Normalize all line endings to LF
YBushi Jun 8, 2024
f389b08
Revert "Normalize all line endings to LF"
YBushi Jun 8, 2024
e84040a
Revert "Normalize all line endings to LF"
YBushi Jun 8, 2024
49d6ffe
.picked functions to cover
YBushi Jun 9, 2024
ac025a4
added readme which we should use for the report of our assignment
YBushi Jun 9, 2024
22ff531
Update README.md
YBushi Jun 9, 2024
30ddaf0
.added my 2 methods that I covered into the report
YBushi Jun 9, 2024
8385a7b
.disabled checkstyles so its easier to code without having to worry a…
YBushi Jun 9, 2024
99b6a14
Update README.md - Jayran 2 functions
jayran-d Jun 9, 2024
d865301
Update README.md
nikola20145 Jun 9, 2024
0983313
.disable programming mistake detector
YBushi Jun 10, 2024
c97456e
.added before/after coverage
YBushi Jun 10, 2024
8fa3da5
Update README.md
nikola20145 Jun 10, 2024
0976235
Update README.md
nikola20145 Jun 10, 2024
3884fad
Update README.md
nikola20145 Jun 10, 2024
f959b03
Update README.md
nikola20145 Jun 10, 2024
322bdc7
Update README.md
nikola20145 Jun 10, 2024
95bd2b6
Update README.md
nikola20145 Jun 10, 2024
e4efa5c
Update NingHttpClient.java
nikola20145 Jun 10, 2024
3015c50
Update pom.xml
nikola20145 Jun 10, 2024
31761ff
Update settings.json
nikola20145 Jun 10, 2024
de3bbe5
Update ArmeriaHttpClient.java
nikola20145 Jun 10, 2024
b7de5fe
Last updates for Assignment 1
nikola20145 Jun 18, 2024
d040a99
Changing Armeria file to the same as it is in master
nikola20145 Jun 20, 2024
292d26f
Update NingHttpClient.java
nikola20145 Jun 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Changing Armeria file to the same as it is in master
  • Loading branch information
nikola20145 committed Jun 20, 2024
commit d040a99c7b1087c45f94bcdd319d1f8ea4d0bdf5
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.Supplier;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;

/**
* An implementation of {@link AbstractAsyncOnlyHttpClient} based on
* <a href="https://line.github.io/armeria/">Armeria HTTP client</a>.
Expand All @@ -45,16 +44,15 @@ public class ArmeriaHttpClient extends AbstractAsyncOnlyHttpClient {
*/
private final ArmeriaWebClientBuilder clientBuilder;
/**
* A list of cached Endpoints. It helps avoiding building a new Endpoint per each request.
* A list of cached Endpoints. It helps avoiding building a new Endpoint per
* each request.
*/
private final Map<String, WebClient> httpClients = new HashMap<>();
/**
* A read/write lock to access the list of cached Endpoints concurrently.
*/
private final ReentrantReadWriteLock httpClientsLock = new ReentrantReadWriteLock();



public ArmeriaHttpClient() {
this(ArmeriaHttpClientConfig.defaultConfig());
}
Expand All @@ -63,25 +61,6 @@ public ArmeriaHttpClient(ArmeriaHttpClientConfig config) {
clientBuilder = config.createClientBuilder();
}

// data structure for info about the branches
private static final ConcurrentHashMap<String, AtomicBoolean> branchCoverage = new ConcurrentHashMap<>();

static {
branchCoverage.put("branch_1", new AtomicBoolean(false));
branchCoverage.put("branch_2", new AtomicBoolean(false));
branchCoverage.put("branch_3", new AtomicBoolean(false));
branchCoverage.put("branch_4", new AtomicBoolean(false));
branchCoverage.put("branch_5", new AtomicBoolean(false));
branchCoverage.put("branch_6", new AtomicBoolean(false));

Runtime.getRuntime().addShutdownHook(new Thread(() -> {
System.out.println("Branch coverage results:");
branchCoverage.forEach((branch, covered) -> {
System.out.println(branch + ": " + (covered.get() ? "Taken" : "Not taken"));
});
}));
}

/**
* Cleans up the list of cached Endpoints.
*/
Expand Down Expand Up @@ -125,60 +104,54 @@ public <T> Future<T> executeAsync(String userAgent, Map<String, String> headers,
converter);
}

// branch coverage: Nikola
private <T> CompletableFuture<T> doExecuteAsync(String userAgent, Map<String, String> headers, Verb httpVerb,
String completeUrl, Supplier<HttpData> contentSupplier, OAuthAsyncRequestCallback<T> callback,
OAuthRequest.ResponseConverter<T> converter) {
private <T> CompletableFuture<T> doExecuteAsync(String userAgent, Map<String, String> headers, Verb httpVerb,
String completeUrl, Supplier<HttpData> contentSupplier, OAuthAsyncRequestCallback<T> callback,
OAuthRequest.ResponseConverter<T> converter) {
// Get the URI and Path
final URI uri = URI.create(completeUrl);
final String path = getServicePath(uri);

final URI uri = URI.create(completeUrl);
final String path = getServicePath(uri);
final WebClient client = getClient(uri);
final RequestHeadersBuilder headersBuilder = RequestHeaders.of(getHttpMethod(httpVerb), path).toBuilder();
// Fetch/Create WebClient instance for a given Endpoint
final WebClient client = getClient(uri);

headersBuilder.add(headers.entrySet());
if (userAgent != null) {
headersBuilder.add(OAuthConstants.USER_AGENT_HEADER_NAME, userAgent);
}
// Build HTTP request
final RequestHeadersBuilder headersBuilder = RequestHeaders.of(getHttpMethod(httpVerb), path).toBuilder();

final HttpResponse response;
// ID: branch_1
if (httpVerb.isPermitBody()) {
branchCoverage.get("branch_1").set(true);
final HttpData contents = contentSupplier.get();
// ID: branch_2
if (httpVerb.isRequiresBody() && contents == null) {
branchCoverage.get("branch_2").set(true);
throw new IllegalArgumentException("Contents missing for request method " + httpVerb.name());
headersBuilder.add(headers.entrySet());
if (userAgent != null) {
headersBuilder.add(OAuthConstants.USER_AGENT_HEADER_NAME, userAgent);
}
// ID: branch_3
if (headersBuilder.contentType() == null) {
branchCoverage.get("branch_3").set(true);
headersBuilder.contentType(MediaType.FORM_DATA);
}
// ID: branch_4
if (contents != null) {
branchCoverage.get("branch_4").set(true);
response = client.execute(headersBuilder.build(), contents);
}
// ID: branch_5
else{
branchCoverage.get("branch_5").set(true);

// Build the request body and execute HTTP request
final HttpResponse response;
if (httpVerb.isPermitBody()) { // POST, PUT, PATCH and DELETE methods
final HttpData contents = contentSupplier.get();
if (httpVerb.isRequiresBody() && contents == null) { // POST or PUT methods
throw new IllegalArgumentException("Contents missing for request method " + httpVerb.name());
}

if (headersBuilder.contentType() == null) {
headersBuilder.contentType(MediaType.FORM_DATA);
}

if (contents != null) {
response = client.execute(headersBuilder.build(), contents);
} else {
response = client.execute(headersBuilder.build());
}
} else {
response = client.execute(headersBuilder.build());
}
} // ID: branch_6
else {
branchCoverage.get("branch_6").set(true);
response = client.execute(headersBuilder.build());
}

return response.aggregate()
.thenApply(aggregatedResponse -> whenResponseComplete(callback, converter, aggregatedResponse))
.exceptionally(throwable -> completeExceptionally(callback, throwable));
}

// Aggregate HTTP response (asynchronously) and return the result Future
return response.aggregate()
.thenApply(aggregatedResponse -> whenResponseComplete(callback, converter, aggregatedResponse))
.exceptionally(throwable -> completeExceptionally(callback, throwable));
}

/**
* Provides an instance of {@link WebClient} for a given endpoint {@link URI} based on an endpoint as
* Provides an instance of {@link WebClient} for a given endpoint {@link URI}
* based on an endpoint as
* {@code scheme://authority}.
*
* @param uri an endpoint {@link URI}
Expand Down Expand Up @@ -221,56 +194,102 @@ private WebClient getClient(URI uri) {
/**
* Extracts {@code scheme} and {@code authority} portion of the {@link URI}.
*
* Assuming the {@link URI} as the following: {@code URI = scheme:[//authority]path[?query][#fragment]}
* Assuming the {@link URI} as the following:
* {@code URI = scheme:[//authority]path[?query][#fragment]}
*/
private static String getEndPoint(URI uri) {
return requireNonNull(uri.getScheme(), "scheme") + "://" + requireNonNull(uri.getAuthority(), "authority");
}

private static boolean[] getServiceCaseCoverage = new boolean[2]; // Data structure

/**
* Extracts {@code path}, {@code query} and {@code fragment} portion of the {@link URI}.
* Extracts {@code path}, {@code query} and {@code fragment} portion of the
* {@link URI}.
*
* Assuming the {@link URI} as the following: {@code URI = scheme:[//authority]path[?query][#fragment]}
* Assuming the {@link URI} as the following:
* {@code URI = scheme:[//authority]path[?query][#fragment]}
*/
private static String getServicePath(URI uri) {
public static String getServicePath(URI uri) {
final StringBuilder builder = new StringBuilder()
.append(requireNonNull(uri.getPath(), "path"));
final String query = uri.getQuery();
if (query != null) {
getServiceCaseCoverage[0] = true; // ID: ArmeriaHttpClient.getServicePath.branch_1
builder.append('?').append(query);
}
final String fragment = uri.getFragment();
if (fragment != null) {
getServiceCaseCoverage[1] = true; // ID: ArmeriaHttpClient.getServicePath.branch_2
builder.append('#').append(fragment);
}
return builder.toString();
}

private static void printCoverage() {
System.out.println("GetHttpMethod Coverage report:");
for (int i = 0; i < getHttpCaseCoverage.length; i++) {
System.out.println("ArmeriaHttpClient.getHttpMethod.branch_" + (i + 1) + ": "
+ getHttpCaseCoverage[i]);
}

System.out.println("GetService Coverage report:");
for (int i = 0; i < getServiceCaseCoverage.length; i++) {
System.out.println("ArmeriaHttpClient.getServicePath.branch_" + (i + 1) + ":" + getServiceCaseCoverage[i]);
}
}

static {
// Ensure the coverage report is printed when the class is loaded
Runtime.getRuntime().addShutdownHook(new Thread(ArmeriaHttpClient::printCoverage));
}

/**
* Maps {@link Verb} to {@link HttpMethod}
*
* @param httpVerb a {@link Verb} to match with {@link HttpMethod}
* @return {@link HttpMethod} corresponding to the parameter
*/
private static HttpMethod getHttpMethod(Verb httpVerb) {

private static boolean[] getHttpCaseCoverage = new boolean[9];

public static HttpMethod getHttpMethod(Verb httpVerb) {
switch (httpVerb) {
case GET:
// ID: ArmeriaHttpClient.getHttpMethod.branch_1
getHttpCaseCoverage[0] = true;
return HttpMethod.GET;
case POST:
// ID: ArmeriaHttpClient.getHttpMethod.branch_2
getHttpCaseCoverage[1] = true;
return HttpMethod.POST;
case PUT:
// ID: ArmeriaHttpClient.getHttpMethod.branch_3
getHttpCaseCoverage[2] = true;
return HttpMethod.PUT;
case DELETE:
// ID: ArmeriaHttpClient.getHttpMethod.branch_4
getHttpCaseCoverage[3] = true;
return HttpMethod.DELETE;
case HEAD:
// ID: ArmeriaHttpClient.getHttpMethod.branch_5
getHttpCaseCoverage[4] = true;
return HttpMethod.HEAD;
case OPTIONS:
// ID: ArmeriaHttpClient.getHttpMethod.branch_6
getHttpCaseCoverage[5] = true;
return HttpMethod.OPTIONS;
case TRACE:
// ID: ArmeriaHttpClient.getHttpMethod.branch_7
getHttpCaseCoverage[6] = true;
return HttpMethod.TRACE;
case PATCH:
// ID: ArmeriaHttpClient.getHttpMethod.branch_8
getHttpCaseCoverage[7] = true;
return HttpMethod.PATCH;
default:
// ID: ArmeriaHttpClient.getHttpMethod.branch_9
getHttpCaseCoverage[8] = true;
throw new IllegalArgumentException(
"message build error: unsupported HTTP method: " + httpVerb.name());
}
Expand All @@ -280,7 +299,8 @@ private static HttpMethod getHttpMethod(Verb httpVerb) {
/**
* Converts {@link AggregatedHttpResponse} to {@link Response}
*
* @param aggregatedResponse an instance of {@link AggregatedHttpResponse} to convert to {@link Response}
* @param aggregatedResponse an instance of {@link AggregatedHttpResponse} to
* convert to {@link Response}
* @return a {@link Response} converted from {@link AggregatedHttpResponse}
*/
private Response convertResponse(AggregatedHttpResponse aggregatedResponse) {
Expand All @@ -294,14 +314,19 @@ private Response convertResponse(AggregatedHttpResponse aggregatedResponse) {
}

/**
* Converts {@link AggregatedHttpResponse} to {@link Response} upon its aggregation completion and invokes
* Converts {@link AggregatedHttpResponse} to {@link Response} upon its
* aggregation completion and invokes
* {@link OAuthAsyncRequestCallback} for it.
*
* @param callback a {@link OAuthAsyncRequestCallback} callback to invoke upon response completion
* @param converter an optional {@link OAuthRequest.ResponseConverter} result converter for {@link Response}
* @param callback a {@link OAuthAsyncRequestCallback} callback to
* invoke upon response completion
* @param converter an optional {@link OAuthRequest.ResponseConverter}
* result converter for {@link Response}
* @param aggregatedResponse a source {@link AggregatedHttpResponse} to handle
* @param <T> converter {@link OAuthRequest.ResponseConverter} specific type or {@link Response}
* @return either instance of {@link Response} or converted result based on {@link OAuthRequest.ResponseConverter}
* @param <T> converter {@link OAuthRequest.ResponseConverter}
* specific type or {@link Response}
* @return either instance of {@link Response} or converted result based on
* {@link OAuthRequest.ResponseConverter}
*/
private <T> T whenResponseComplete(OAuthAsyncRequestCallback<T> callback,
OAuthRequest.ResponseConverter<T> converter, AggregatedHttpResponse aggregatedResponse) {
Expand All @@ -321,9 +346,11 @@ private <T> T whenResponseComplete(OAuthAsyncRequestCallback<T> callback,
/**
* Invokes {@link OAuthAsyncRequestCallback} upon {@link Throwable} error result
*
* @param callback a {@link OAuthAsyncRequestCallback} callback to invoke upon response completion
* @param callback a {@link OAuthAsyncRequestCallback} callback to invoke upon
* response completion
* @param throwable a {@link Throwable} error result
* @param <T> converter {@link OAuthRequest.ResponseConverter} specific type or {@link Response}
* @param <T> converter {@link OAuthRequest.ResponseConverter} specific
* type or {@link Response}
* @return null
*/
private <T> T completeExceptionally(OAuthAsyncRequestCallback<T> callback, Throwable throwable) {
Expand Down Expand Up @@ -401,4 +428,4 @@ public HttpData get() {
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ protected HttpClient createNewClient() {
}


//new tests


@Test
Expand Down