Skip to content

Commit 4d8152c

Browse files
authored
Merge pull request #121 from pierrechristinimsa/feature/verify-service-invocation
feat: add methods to verify service invocation
2 parents bb4fa6e + 6ab5d12 commit 4d8152c

File tree

4 files changed

+498
-3
lines changed

4 files changed

+498
-3
lines changed

README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,21 @@ The container provides methods for different supported API styles/protocols (Soa
121121

122122
The container also provides `getHttpEndpoint()` for raw access to those API endpoints.
123123

124+
### Verifying mock endpoint has been invoked
125+
126+
Once the mock endpoint has been invoked, you'd probably need to ensure that the mock have been really invoked.
127+
128+
You can do it like this :
129+
130+
```java
131+
Boolean serviceMockInvoked = microcks.verify("API Pastries", "0.0.1");
132+
```
133+
134+
Or like this :
135+
```java
136+
Long serviceInvocationsCount = microcks.getServiceInvocationsCount("API Pastries", "0.0.1");
137+
```
138+
124139
### Launching new contract-tests
125140

126141
If you want to ensure that your application under test is conformant to an OpenAPI contract (or other type of contract),

src/main/java/io/github/microcks/testcontainers/MicrocksContainer.java

Lines changed: 184 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package io.github.microcks.testcontainers;
1717

18+
import io.github.microcks.testcontainers.model.DailyInvocationStatistic;
1819
import io.github.microcks.testcontainers.model.RequestResponsePair;
1920
import io.github.microcks.testcontainers.model.Secret;
2021
import io.github.microcks.testcontainers.model.TestResult;
@@ -30,6 +31,7 @@
3031
import org.testcontainers.shaded.com.fasterxml.jackson.databind.ObjectMapper;
3132
import org.testcontainers.shaded.com.github.dockerjava.core.MediaType;
3233
import org.testcontainers.shaded.com.google.common.net.HttpHeaders;
34+
import org.testcontainers.shaded.com.google.common.net.UrlEscapers;
3335
import org.testcontainers.shaded.org.awaitility.Awaitility;
3436
import org.testcontainers.shaded.org.awaitility.core.ConditionTimeoutException;
3537
import org.testcontainers.utility.DockerImageName;
@@ -43,12 +45,15 @@
4345
import java.io.OutputStream;
4446
import java.io.OutputStreamWriter;
4547
import java.io.PrintWriter;
48+
import java.math.BigDecimal;
4649
import java.net.HttpURLConnection;
4750
import java.net.URL;
4851
import java.net.URLDecoder;
4952
import java.net.URLEncoder;
5053
import java.nio.charset.StandardCharsets;
54+
import java.text.SimpleDateFormat;
5155
import java.util.Arrays;
56+
import java.util.Date;
5257
import java.util.HashSet;
5358
import java.util.List;
5459
import java.util.Set;
@@ -75,6 +80,8 @@ public class MicrocksContainer extends GenericContainer<MicrocksContainer> {
7580

7681
private static ObjectMapper mapper;
7782

83+
private static SimpleDateFormat metricsApiDayFormatter = new SimpleDateFormat("yyyyMMdd");
84+
7885
private Set<String> snapshotsToImport;
7986
private Set<String> mainArtifactsToImport;
8087
private Set<String> secondaryArtifactsToImport;
@@ -561,6 +568,167 @@ public void downloadAsSecondaryRemoteArtifact(String remoteArtifactUrl) throws A
561568
downloadArtifact(remoteArtifactUrl, false);
562569
}
563570

571+
/**
572+
* Verifies that given Service has been invoked at least one time, for the current invocations' date.
573+
*
574+
* @param serviceName mandatory
575+
* @param serviceVersion mandatory
576+
* @return false if the given service was not found, or if the daily invocation's count is zero. Else, returns true if the daily invocations' count for the given service is at least one.
577+
*/
578+
public boolean verify(String serviceName, String serviceVersion) {
579+
return doVerify(getHttpEndpoint(), serviceName, serviceVersion, null);
580+
}
581+
582+
/**
583+
* Verifies that given Service has been invoked at least one time, for the current invocations' date.
584+
*
585+
* @param microcksContainerHttpEndpoint mandatory
586+
* @param serviceName mandatory
587+
* @param serviceVersion mandatory
588+
* @return false if the given service was not found, or if the daily invocation's count is zero. Else, returns true if the daily invocations' count for the given service is at least one.
589+
*/
590+
public static boolean verify(String microcksContainerHttpEndpoint, String serviceName, String serviceVersion) {
591+
return doVerify(microcksContainerHttpEndpoint, serviceName, serviceVersion, null);
592+
}
593+
594+
/**
595+
* Verifies that given Service has been invoked at least one time, for the given invocations' date.
596+
* In unit testing context, it should be useless to pass the invocations date, prefer calling {@link #verify(String, String)}`.
597+
*
598+
* @param serviceName mandatory
599+
* @param serviceVersion mandatory
600+
* @param invocationsDate nullable
601+
* @return false if the given service was not found, or if the daily invocation's count is zero. Else, returns true if the daily invocations' count for the given service is at least one.
602+
*/
603+
public boolean verify(String serviceName, String serviceVersion, Date invocationsDate) {
604+
return doVerify(getHttpEndpoint(), serviceName, serviceVersion, invocationsDate);
605+
}
606+
607+
/**
608+
* Verifies that given Service has been invoked at least one time, for the given invocations' date.
609+
* In unit testing context, it should be useless to pass the invocations date, prefer calling {@link #verify(String, String)}`.
610+
*
611+
* @param microcksContainerHttpEndpoint mandatory
612+
* @param serviceName mandatory
613+
* @param serviceVersion mandatory
614+
* @param invocationsDate nullable
615+
* @return false if the given service was not found, or if the daily invocation's count is zero. Else, returns true if the daily invocations' count for the given service is at least one.
616+
*/
617+
public static boolean verify(String microcksContainerHttpEndpoint, String serviceName, String serviceVersion, Date invocationsDate) {
618+
return doVerify(microcksContainerHttpEndpoint, serviceName, serviceVersion, invocationsDate);
619+
}
620+
621+
private static boolean doVerify(String microcksContainerHttpEndpoint, String serviceName, String serviceVersion, Date invocationsDate) {
622+
DailyInvocationStatistic dailyInvocationStatistic = getServiceInvocations(microcksContainerHttpEndpoint, serviceName, serviceVersion, invocationsDate);
623+
624+
if (dailyInvocationStatistic == null) {
625+
return false;
626+
}
627+
628+
BigDecimal count = dailyInvocationStatistic.getDailyCount();
629+
630+
return count != null && count.intValue() != 0;
631+
}
632+
633+
/**
634+
* Get the invocations' count for a given service, identified by its name and version, for the current invocations' date.
635+
*
636+
* @param serviceName mandatory
637+
* @param serviceVersion mandatory
638+
* @return zero if the given service was not found, or has never been invoked. Else, returns the daily count of invocations for the given service.
639+
*/
640+
public Long getServiceInvocationsCount(String serviceName, String serviceVersion) {
641+
return doGetServiceInvocationsCount(getHttpEndpoint(), serviceName, serviceVersion, null);
642+
}
643+
644+
/**
645+
* Get the invocations' count for a given service, identified by its name and version, for the current invocations' date.
646+
*
647+
* @param microcksContainerHttpEndpoint mandatory
648+
* @param serviceName mandatory
649+
* @param serviceVersion mandatory
650+
* @return zero if the given service was not found, or has never been invoked. Else, returns the daily count of invocations for the given service.
651+
*/
652+
public static Long getServiceInvocationsCount(String microcksContainerHttpEndpoint, String serviceName, String serviceVersion) {
653+
return doGetServiceInvocationsCount(microcksContainerHttpEndpoint, serviceName, serviceVersion, null);
654+
}
655+
656+
/**
657+
* Get the invocations' count for a given service, identified by its name and version, for the given invocations' date.
658+
* In unit testing context, it should be useless to pass the invocations date, prefer calling {@link #getServiceInvocationsCount(String, String)}`.
659+
*
660+
* @param serviceName mandatory
661+
* @param serviceVersion mandatory
662+
* @param invocationsDate nullable
663+
* @return zero if the given service was not found, or has never been invoked. Else, returns the daily count of invocations for the given service.
664+
*/
665+
public Long getServiceInvocationsCount(String serviceName, String serviceVersion, Date invocationsDate) {
666+
return doGetServiceInvocationsCount(getHttpEndpoint(), serviceName, serviceVersion, invocationsDate);
667+
}
668+
669+
/**
670+
* Get the invocations' count for a given service, identified by its name and version, for the given invocations' date.
671+
* In unit testing context, it should be useless to pass the invocations date, prefer calling {@link #getServiceInvocationsCount(String, String)}`.
672+
*
673+
* @param microcksContainerHttpEndpoint mandatory
674+
* @param serviceName mandatory
675+
* @param serviceVersion mandatory
676+
* @param invocationsDate nullable
677+
* @return zero if the given service was not found, or has never been invoked. Else, returns the daily count of invocations for the given service.
678+
*/
679+
public static Long getServiceInvocationsCount(String microcksContainerHttpEndpoint, String serviceName, String serviceVersion, Date invocationsDate) {
680+
return doGetServiceInvocationsCount(microcksContainerHttpEndpoint, serviceName, serviceVersion, invocationsDate);
681+
}
682+
683+
private static Long doGetServiceInvocationsCount(String microcksContainerHttpEndpoint, String serviceName, String serviceVersion, Date invocationsDate) {
684+
DailyInvocationStatistic dailyInvocationStatistic = getServiceInvocations(microcksContainerHttpEndpoint, serviceName, serviceVersion, invocationsDate);
685+
686+
if (dailyInvocationStatistic == null) {
687+
return 0L;
688+
}
689+
690+
BigDecimal count = dailyInvocationStatistic.getDailyCount();
691+
692+
return count.longValue();
693+
}
694+
695+
696+
/**
697+
* Returns all data from Microcks Metrics REST API about the invocations of a given service.
698+
*
699+
* @param microcksContainerHttpEndpoint mandatory
700+
* @param serviceName mandatory
701+
* @param serviceVersion mandatory
702+
* @param invocationsDate nullable
703+
* @return
704+
*/
705+
private static DailyInvocationStatistic getServiceInvocations(String microcksContainerHttpEndpoint, String serviceName, String serviceVersion, Date invocationsDate) {
706+
String encodedServiceName = UrlEscapers.urlFragmentEscaper().escape(serviceName);
707+
String encodedServiceVersion = UrlEscapers.urlFragmentEscaper().escape(serviceVersion);
708+
709+
String restApiURL = String.format("%s/api/metrics/invocations/%s/%s", microcksContainerHttpEndpoint, encodedServiceName, encodedServiceVersion);
710+
711+
if (invocationsDate != null) {
712+
restApiURL += "?day=" + metricsApiDayFormatter.format(invocationsDate);
713+
}
714+
715+
try {
716+
Thread.sleep(100); // to avoid race condition issue when requesting Microcks Metrics REST API
717+
} catch (InterruptedException e) {
718+
log.warn("Failed to sleep before calling Microcks API", e);
719+
Thread.currentThread().interrupt();
720+
}
721+
722+
try {
723+
StringBuilder content = getFromRestApi(restApiURL);
724+
return content.length() == 0 ? null : getMapper().readValue(content.toString(), DailyInvocationStatistic.class);
725+
} catch (IOException e) {
726+
log.warn("Failed to get service's invocations at address " + restApiURL, e);
727+
}
728+
729+
return null;
730+
}
731+
564732
private void importArtifact(String artifactPath, boolean mainArtifact) {
565733
URL resource = Thread.currentThread().getContextClassLoader().getResource(artifactPath);
566734
if (resource == null) {
@@ -727,8 +895,21 @@ private static HttpURLConnection uploadFileToMicrocks(URL microcksApiURL, File f
727895
}
728896

729897
private static TestResult refreshTestResult(String microcksContainerHttpEndpoint, String testResultId) throws IOException {
898+
StringBuilder content = getFromRestApi(microcksContainerHttpEndpoint + "/api/tests/" + testResultId);
899+
900+
return getMapper().readValue(content.toString(), TestResult.class);
901+
}
902+
903+
/**
904+
* Does a GET HTTP call to Microcks REST API and expecting to obtain a 200 response with a `application/json` body: returns it as a StringBuilder.
905+
*
906+
* @param restApiURL mandatory
907+
* @return
908+
* @throws IOException
909+
*/
910+
private static StringBuilder getFromRestApi(String restApiURL) throws IOException {
730911
// Build a new client on correct API endpoint.
731-
URL url = new URL(microcksContainerHttpEndpoint + "/api/tests/" + testResultId);
912+
URL url = new URL(restApiURL);
732913
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
733914
httpConn.setRequestMethod("GET");
734915
httpConn.setRequestProperty("Accept", "application/json");
@@ -742,10 +923,10 @@ private static TestResult refreshTestResult(String microcksContainerHttpEndpoint
742923
content.append(inputLine);
743924
}
744925
}
926+
745927
// Disconnect Http connection.
746928
httpConn.disconnect();
747-
748-
return getMapper().readValue(content.toString(), TestResult.class);
929+
return content;
749930
}
750931

751932
public static class ArtifactLoadException extends RuntimeException {

0 commit comments

Comments
 (0)