diff --git a/RELEASING.md b/RELEASING.md index 4aeb5b6863..85c1376852 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -33,9 +33,18 @@ to the version you've just released and publish it. ## Update the version on wiremock.org https://github.com/wiremock/wiremock.org +Publish the changes by merging to the `live-publish` branch and manually triggering the "Deploy Jekyll site to Pages" workflow. + ## Release the Docker image +Wait for the JAR version you just published to be synced to Maven Central. You can check here: +https://repo1.maven.org/maven2/org/wiremock/wiremock/ + +Run the Release workflow: https://github.com/wiremock/wiremock-docker/actions/workflows/release.yml +Then update the README manually on Docker Hub (until we get around to automating it). + + ## Post an announcement on the WireMock Community Slack Announce in the #announcments channel then link to the message from #general. diff --git a/build.gradle b/build.gradle index 22646ac62c..a8a123cce3 100644 --- a/build.gradle +++ b/build.gradle @@ -1,3 +1,6 @@ +import org.gradle.api.publish.maven.tasks.AbstractPublishToMaven +import org.gradle.plugins.signing.Sign + buildscript { repositories { maven { @@ -106,7 +109,7 @@ dependencies { } api "commons-io:commons-io:2.15.1" - api 'com.networknt:json-schema-validator:1.3.2' + api 'com.networknt:json-schema-validator:1.3.3' testImplementation "junit:junit:4.13" testImplementation("org.junit.jupiter:junit-jupiter:$versions.junitJupiter") @@ -126,7 +129,7 @@ dependencies { testImplementation 'org.awaitility:awaitility:4.2.0' testImplementation "com.googlecode.jarjar:jarjar:1.3" testImplementation "commons-io:commons-io:2.15.1" - testImplementation 'org.scala-lang:scala-library:2.13.12' + testImplementation 'org.scala-lang:scala-library:2.13.13' testImplementation 'com.tngtech.archunit:archunit-junit5:0.23.1' testImplementation "org.eclipse.jetty:jetty-client" @@ -217,7 +220,7 @@ allprojects { mavenCentral() } - version = '3.4.1.0' + version = '3.4.2.0' sourceCompatibility = 11 diff --git a/src/main/java/com/github/tomakehurst/wiremock/common/xml/XmlNode.java b/src/main/java/com/github/tomakehurst/wiremock/common/xml/XmlNode.java index 1424c183fb..e07d17eb79 100644 --- a/src/main/java/com/github/tomakehurst/wiremock/common/xml/XmlNode.java +++ b/src/main/java/com/github/tomakehurst/wiremock/common/xml/XmlNode.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020-2023 Thomas Akehurst + * Copyright (C) 2020-2024 Thomas Akehurst * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -39,44 +39,40 @@ public class XmlNode { - protected static final InheritableThreadLocal XPATH_CACHE = - new InheritableThreadLocal<>() { - @Override - protected XPath initialValue() { - final XPathFactory xPathfactory = XPathFactory.newInstance(); - return xPathfactory.newXPath(); - } - }; - - protected static final InheritableThreadLocal TRANSFORMER_CACHE = - new InheritableThreadLocal<>() { - @Override - protected Transformer initialValue() { - TransformerFactory transformerFactory; - try { - // Optimization to get likely transformerFactory directly, rather than going through - // FactoryFinder#find - transformerFactory = - (TransformerFactory) - Class.forName( - "com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl") - .getDeclaredConstructor() - .newInstance(); - } catch (Exception e) { - transformerFactory = TransformerFactory.newInstance(); - } - transformerFactory.setAttribute("indent-number", 2); - - try { - Transformer transformer = transformerFactory.newTransformer(); - transformer.setOutputProperty(INDENT, "yes"); - transformer.setOutputProperty(OMIT_XML_DECLARATION, "yes"); - return transformer; - } catch (TransformerConfigurationException e) { - return throwUnchecked(e, Transformer.class); - } - } - }; + protected static final ThreadLocal XPATH_CACHE = + ThreadLocal.withInitial( + () -> { + final XPathFactory xPathfactory = XPathFactory.newInstance(); + return xPathfactory.newXPath(); + }); + + protected static final ThreadLocal TRANSFORMER_CACHE = + ThreadLocal.withInitial( + () -> { + TransformerFactory transformerFactory; + try { + // Optimization to get likely transformerFactory directly, rather than going through + // FactoryFinder#find + transformerFactory = + (TransformerFactory) + Class.forName( + "com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl") + .getDeclaredConstructor() + .newInstance(); + } catch (Exception e) { + transformerFactory = TransformerFactory.newInstance(); + } + transformerFactory.setAttribute("indent-number", 2); + + try { + Transformer transformer = transformerFactory.newTransformer(); + transformer.setOutputProperty(INDENT, "yes"); + transformer.setOutputProperty(OMIT_XML_DECLARATION, "yes"); + return transformer; + } catch (TransformerConfigurationException e) { + return throwUnchecked(e, Transformer.class); + } + }); private static final Class DOM2SAX_XMLREADER_CLASS = getDom2SaxAvailability(); diff --git a/src/main/java/com/github/tomakehurst/wiremock/matching/MatchResult.java b/src/main/java/com/github/tomakehurst/wiremock/matching/MatchResult.java index 83274dcb92..bb8ad54ed2 100644 --- a/src/main/java/com/github/tomakehurst/wiremock/matching/MatchResult.java +++ b/src/main/java/com/github/tomakehurst/wiremock/matching/MatchResult.java @@ -21,7 +21,6 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; -import com.github.tomakehurst.wiremock.common.Lazy; import com.github.tomakehurst.wiremock.stubbing.SubEvent; import java.util.List; import java.util.Queue; @@ -91,49 +90,7 @@ public static MatchResult aggregateWeighted(WeightedMatchResult... matchResults) } public static MatchResult aggregateWeighted(final List matchResults) { - - return new MatchResult() { - - private final Lazy exactMatch = - Lazy.lazy(() -> matchResults.stream().allMatch(ARE_EXACT_MATCH)); - private final Lazy distance = - Lazy.lazy( - () -> { - double totalDistance = 0; - double sizeWithWeighting = 0; - for (WeightedMatchResult matchResult : matchResults) { - totalDistance += matchResult.getDistance(); - sizeWithWeighting += matchResult.getWeighting(); - } - - return (totalDistance / sizeWithWeighting); - }); - - private final Lazy> subEvents = - Lazy.lazy( - () -> { - isExactMatch(); // TODO: Find a less icky way to do this - return matchResults.stream() - .flatMap( - weightedResult -> weightedResult.getMatchResult().getSubEvents().stream()) - .collect(Collectors.toList()); - }); - - @Override - public boolean isExactMatch() { - return exactMatch.get(); - } - - @Override - public double getDistance() { - return distance.get(); - } - - @Override - public List getSubEvents() { - return subEvents.get(); - } - }; + return new WeightedAggregateMatchResult(matchResults); } @JsonIgnore diff --git a/src/main/java/com/github/tomakehurst/wiremock/matching/WeightedAggregateMatchResult.java b/src/main/java/com/github/tomakehurst/wiremock/matching/WeightedAggregateMatchResult.java new file mode 100644 index 0000000000..5dd49f0438 --- /dev/null +++ b/src/main/java/com/github/tomakehurst/wiremock/matching/WeightedAggregateMatchResult.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2024 Thomas Akehurst + * + * 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 com.github.tomakehurst.wiremock.matching; + +import static com.github.tomakehurst.wiremock.common.Lazy.lazy; +import static com.github.tomakehurst.wiremock.common.Pair.pair; + +import com.github.tomakehurst.wiremock.common.Lazy; +import com.github.tomakehurst.wiremock.common.Pair; +import com.github.tomakehurst.wiremock.stubbing.SubEvent; +import java.util.ArrayList; +import java.util.List; + +public class WeightedAggregateMatchResult extends MatchResult { + + private final List matchResults; + + private final Lazy>> resultAndEvents; + + public WeightedAggregateMatchResult(List matchResults) { + this.matchResults = matchResults; + resultAndEvents = + lazy( + () -> { + final List subEvents = new ArrayList<>(matchResults.size()); + return pair( + matchResults.stream() + .allMatch( + weightedMatchResult -> { + final boolean exactMatch = weightedMatchResult.isExactMatch(); + subEvents.addAll(weightedMatchResult.getMatchResult().getSubEvents()); + return exactMatch; + }), + subEvents); + }); + } + + @Override + public boolean isExactMatch() { + return resultAndEvents.get().a; + } + + @Override + public double getDistance() { + double totalDistance = 0; + double sizeWithWeighting = 0; + for (WeightedMatchResult matchResult : matchResults) { + totalDistance += matchResult.getDistance(); + sizeWithWeighting += matchResult.getWeighting(); + } + + return (totalDistance / sizeWithWeighting); + } + + @Override + public List getSubEvents() { + return resultAndEvents.get().b; + } +} diff --git a/src/main/resources/swagger/wiremock-admin-api.json b/src/main/resources/swagger/wiremock-admin-api.json index d218ba174c..c4e46699b1 100644 --- a/src/main/resources/swagger/wiremock-admin-api.json +++ b/src/main/resources/swagger/wiremock-admin-api.json @@ -2,7 +2,7 @@ "openapi": "3.0.0", "info": { "title": "WireMock", - "version": "3.4.1" + "version": "3.4.2" }, "externalDocs": { "description": "WireMock user documentation", diff --git a/src/main/resources/swagger/wiremock-admin-api.yaml b/src/main/resources/swagger/wiremock-admin-api.yaml index d42d42199b..0f74c88174 100644 --- a/src/main/resources/swagger/wiremock-admin-api.yaml +++ b/src/main/resources/swagger/wiremock-admin-api.yaml @@ -2,7 +2,7 @@ openapi: 3.0.0 info: title: WireMock - version: 3.4.1 + version: 3.4.2 externalDocs: description: WireMock user documentation diff --git a/src/main/resources/version.properties b/src/main/resources/version.properties index 5458d3e50e..350256bf7c 100644 --- a/src/main/resources/version.properties +++ b/src/main/resources/version.properties @@ -1 +1 @@ -version=3.4.1 \ No newline at end of file +version=3.4.2 \ No newline at end of file diff --git a/src/test/java/com/github/tomakehurst/wiremock/matching/MatchResultTest.java b/src/test/java/com/github/tomakehurst/wiremock/matching/MatchResultTest.java index 4dcc0dc01d..68dad9ae45 100644 --- a/src/test/java/com/github/tomakehurst/wiremock/matching/MatchResultTest.java +++ b/src/test/java/com/github/tomakehurst/wiremock/matching/MatchResultTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2023 Thomas Akehurst + * Copyright (C) 2016-2024 Thomas Akehurst * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,10 +15,13 @@ */ package com.github.tomakehurst.wiremock.matching; +import static com.github.tomakehurst.wiremock.matching.WeightedMatchResult.weight; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; +import com.github.tomakehurst.wiremock.stubbing.SubEvent; import org.junit.jupiter.api.Test; +import org.mockito.Mockito; public class MatchResultTest { @@ -33,6 +36,51 @@ public void aggregatesLazily() { result3); // Expecting no exception to be thrown because getDistance is never called } + @Test + void aggregateWeightedIsLazy() { + MatchResult match1 = Mockito.spy(MatchResult.exactMatch()); + MatchResult match2 = Mockito.spy(MatchResult.exactMatch()); + MatchResult match3 = Mockito.spy(MatchResult.exactMatch()); + MatchResult nonMatch1 = Mockito.spy(MatchResult.noMatch()); + MatchResult nonMatch2 = Mockito.spy(MatchResult.noMatch()); + + MatchResult matchResult = + MatchResult.aggregateWeighted( + weight(match1, 5), + weight(match2, 2), + weight(nonMatch1, 5), + weight(match3, 3), + weight(nonMatch2, 2)); + + boolean isExactMatch = matchResult.isExactMatch(); + + assertThat(isExactMatch, is(false)); + Mockito.verify(match1).isExactMatch(); + Mockito.verify(match2).isExactMatch(); + Mockito.verify(nonMatch1).isExactMatch(); + Mockito.verifyNoInteractions(match3); + Mockito.verifyNoInteractions(nonMatch2); + } + + @Test + void subEventsAreAggregatedForWeightedMatchResultsWhenIsNotAnOverallExactMatch() { + MatchResult match1 = MatchResult.exactMatch(SubEvent.info("1")); + MatchResult match2 = MatchResult.exactMatch(SubEvent.info("2")); + MatchResult match3 = MatchResult.exactMatch(SubEvent.info("3")); + MatchResult nonMatch1 = MatchResult.noMatch(SubEvent.info("4")); + MatchResult nonMatch2 = MatchResult.noMatch(SubEvent.info("5")); + + MatchResult matchResult = + MatchResult.aggregateWeighted( + weight(match1, 5), + weight(match2, 2), + weight(nonMatch1, 5), + weight(match3, 3), + weight(nonMatch2, 2)); + + assertThat(matchResult.getSubEvents().size(), is(3)); + } + @Test public void aggregatesDistanceCorrectly() { MatchResult matchResult = diff --git a/ui/package.json b/ui/package.json index a0ed715be2..c936c0c522 100644 --- a/ui/package.json +++ b/ui/package.json @@ -1,6 +1,6 @@ { "name": "wiremock-ui-resources", - "version": "3.4.1", + "version": "3.4.2", "description": "WireMock UI resources processor", "engines": { "node": ">= 0.10.0"