source: josm/trunk/test/unit/org/openstreetmap/josm/testutils/PluginServer.java@ 14332

Last change on this file since 14332 was 14179, checked in by Don-vip, 6 years ago

fix #16680 - Unit tests: fix for windows (patch by ris)

  • Property svn:eol-style set to native
File size: 9.1 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.testutils;
3
4import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
5
6import java.io.File;
7import java.io.IOException;
8import java.nio.file.Path;
9import java.util.HashMap;
10import java.util.List;
11import java.util.Map;
12import java.util.Objects;
13import java.util.jar.JarFile;
14import java.util.stream.Collectors;
15
16import org.junit.runner.Description;
17import org.junit.runners.model.Statement;
18import org.openstreetmap.josm.TestUtils;
19import org.openstreetmap.josm.tools.Logging;
20
21import com.github.tomakehurst.wiremock.WireMockServer;
22import com.github.tomakehurst.wiremock.client.MappingBuilder;
23import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder;
24import com.github.tomakehurst.wiremock.client.WireMock;
25import com.github.tomakehurst.wiremock.core.Options;
26import com.github.tomakehurst.wiremock.junit.WireMockRule;
27import com.google.common.collect.ImmutableList;
28import com.google.common.collect.Streams;
29
30public class PluginServer {
31 public static class RemotePlugin {
32 private final File srcJar;
33 private final Map<String, String> attrOverrides;
34 private final String pluginName;
35 private final String pluginURL;
36
37 public RemotePlugin(
38 final File srcJar
39 ) {
40 this(srcJar, null, null, null);
41 }
42
43 public RemotePlugin(
44 final File srcJar,
45 final Map<String, String> attrOverrides
46 ) {
47 this(srcJar, attrOverrides, null, null);
48 }
49
50 public RemotePlugin(
51 final File srcJar,
52 final Map<String, String> attrOverrides,
53 final String pluginName
54 ) {
55 this(srcJar, attrOverrides, pluginName, null);
56 }
57
58 public RemotePlugin(
59 final File srcJar,
60 final Map<String, String> attrOverrides,
61 final String pluginName,
62 final String pluginURL
63 ) {
64 this.srcJar = srcJar;
65 this.attrOverrides = attrOverrides;
66 this.pluginName = pluginName;
67 this.pluginURL = pluginURL;
68 }
69
70 @Override
71 public int hashCode() {
72 return Objects.hash(this.srcJar, this.attrOverrides, this.pluginName, this.pluginURL, this.getClass());
73 }
74
75 public String getRemotePluginsListManifestSection() {
76 final Map<String, String> attrs = new HashMap<>();
77 JarFile jarFile = null;
78
79 if (srcJar != null) {
80 try {
81 jarFile = new JarFile(srcJar, false);
82 jarFile.getManifest().getMainAttributes().entrySet().stream().forEach(
83 entry -> attrs.put(entry.getKey().toString(), entry.getValue().toString())
84 );
85 } catch (IOException e) {
86 Logging.warn(
87 "Failed to open {0} as a jar file. Using empty initial manifest. Error was: {1}",
88 srcJar,
89 e
90 );
91 } finally {
92 if (jarFile != null) {
93 try {
94 jarFile.close();
95 } catch (IOException e) {
96 Logging.warn(
97 "Somehow failed to close jar file {0}. Error was: {1}",
98 srcJar,
99 e
100 );
101 }
102 }
103 }
104 }
105
106 if (this.attrOverrides != null) {
107 attrs.putAll(this.attrOverrides);
108 }
109
110 return attrs.entrySet().stream().filter(entry -> entry.getValue() != null).map(
111 entry -> String.format("\t%s: %s\n", entry.getKey(), entry.getValue())
112 ).collect(Collectors.joining());
113 }
114
115 private String getJarPathBeneathFilesDir() {
116 if (this.srcJar != null) {
117 final Path jarPath = this.srcJar.toPath().toAbsolutePath().normalize();
118 final Path filesRootPath = new File(TestUtils.getTestDataRoot()).toPath().toAbsolutePath().resolve("__files").normalize();
119
120 if (jarPath.startsWith(filesRootPath)) {
121 // would just use .toString() but need to force use of *forward slash* path separators on all platforms
122 return Streams.stream(filesRootPath.relativize(jarPath)).map(p -> p.toString()).collect(Collectors.joining("/"));
123 }
124 }
125 return null;
126 }
127
128 protected String getPluginURLPath() {
129 final String jarPathBeneathFilesDir = this.getJarPathBeneathFilesDir();
130
131 if (jarPathBeneathFilesDir != null) {
132 return "/" + jarPathBeneathFilesDir;
133 }
134
135 return String.format("/%h/%s.jar", this.hashCode(), pluginName != null ? pluginName : Integer.toHexString(this.hashCode()));
136 }
137
138 public String getPluginURL(Integer port) {
139 if (this.pluginURL != null) {
140 return this.pluginURL;
141 } else if (port != null && this.getJarPathBeneathFilesDir() != null) {
142 return String.format("http://localhost:%s%s", port, this.getPluginURLPath());
143 }
144 return "http://example.com" + this.getPluginURLPath();
145 }
146
147 public String getName() {
148 if (this.pluginName != null) {
149 return this.pluginName;
150 } else if (this.srcJar != null) {
151 return this.srcJar.getName().split("\\.", 2)[0];
152 }
153 return Integer.toHexString(this.hashCode());
154 }
155
156 public String getRemotePluginsListSection(Integer port) {
157 return String.format(
158 "%s.jar;%s\n%s",
159 this.getName(),
160 this.getPluginURL(port),
161 this.getRemotePluginsListManifestSection()
162 );
163 }
164
165 public MappingBuilder getMappingBuilder() {
166 final String jarPathBeneathFilesDir = this.getJarPathBeneathFilesDir();
167
168 if (jarPathBeneathFilesDir != null) {
169 return WireMock.get(WireMock.urlMatching(this.getPluginURLPath()));
170 }
171 return null;
172 }
173
174 public ResponseDefinitionBuilder getResponseDefinitionBuilder() {
175 final String jarPathBeneathFilesDir = this.getJarPathBeneathFilesDir();
176
177 if (jarPathBeneathFilesDir != null) {
178 return WireMock.aResponse().withStatus(200).withHeader("Content-Type", "application/java-archive").withBodyFile(
179 jarPathBeneathFilesDir
180 );
181 }
182 return null;
183 }
184 }
185
186 protected final List<RemotePlugin> pluginList;
187
188 public PluginServer(RemotePlugin... remotePlugins) {
189 this.pluginList = ImmutableList.copyOf(remotePlugins);
190 }
191
192 public void applyToWireMockServer(WireMockServer wireMockServer) {
193 // first add the plugins list
194 wireMockServer.stubFor(
195 WireMock.get(WireMock.urlEqualTo("/plugins")).willReturn(
196 WireMock.aResponse().withStatus(200).withHeader("Content-Type", "text/plain").withBody(
197 this.pluginList.stream().map(
198 remotePlugin -> remotePlugin.getRemotePluginsListSection(wireMockServer.port())
199 ).collect(Collectors.joining())
200 )
201 )
202 );
203
204 // now add each file that we're able to serve
205 for (final RemotePlugin remotePlugin : this.pluginList) {
206 final MappingBuilder mappingBuilder = remotePlugin.getMappingBuilder();
207 final ResponseDefinitionBuilder responseDefinitionBuilder = remotePlugin.getResponseDefinitionBuilder();
208
209 if (mappingBuilder != null && responseDefinitionBuilder != null) {
210 wireMockServer.stubFor(
211 remotePlugin.getMappingBuilder().willReturn(remotePlugin.getResponseDefinitionBuilder())
212 );
213 }
214 }
215 }
216
217 public PluginServerRule asWireMockRule() {
218 return this.asWireMockRule(
219 options().dynamicPort().usingFilesUnderDirectory(TestUtils.getTestDataRoot()),
220 true
221 );
222 }
223
224 public PluginServerRule asWireMockRule(Options ruleOptions, boolean failOnUnmatchedRequests) {
225 return new PluginServerRule(ruleOptions, failOnUnmatchedRequests);
226 }
227
228 public class PluginServerRule extends WireMockRule {
229 public PluginServerRule(Options ruleOptions, boolean failOnUnmatchedRequests) {
230 super(ruleOptions, failOnUnmatchedRequests);
231 }
232
233 public PluginServer getPluginServer() {
234 return PluginServer.this;
235 }
236
237 @Override
238 public Statement apply(Statement base, Description description) {
239 return super.apply(new Statement() {
240 @Override
241 public void evaluate() throws Throwable {
242 PluginServer.this.applyToWireMockServer(PluginServerRule.this);
243 base.evaluate();
244 }
245 }, description);
246 }
247 }
248}
Note: See TracBrowser for help on using the repository browser.