/
PrefetchingTest.java
238 lines (197 loc) · 8.16 KB
/
PrefetchingTest.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
package hudson.remoting;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import org.apache.commons.io.FileUtils;
import org.apache.tools.ant.AntClassLoader;
import org.junit.Assert;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.concurrent.ExecutionException;
import static org.hamcrest.core.AllOf.allOf;
import static org.hamcrest.core.StringContains.containsString;
import static org.hamcrest.core.StringEndsWith.endsWith;
import static org.hamcrest.core.StringStartsWith.startsWith;
/**
* @author Kohsuke Kawaguchi
*/
public class PrefetchingTest extends RmiTestBase implements Serializable {
private transient AntClassLoader cl;
private File dir;
// checksum of the jar files to force loading
private Checksum sum1,sum2;
@Override
protected void setUp() throws Exception {
super.setUp();
URL jar1 = getClass().getClassLoader().getResource("remoting-test-client.jar");
URL jar2 = getClass().getClassLoader().getResource("remoting-test-client-tests.jar");
cl = new AntClassLoader(this.getClass().getClassLoader(),true);
cl.addPathComponent(toFile(jar1));
cl.addPathComponent(toFile(jar2));
dir = File.createTempFile("remoting", "cache");
dir.delete();
dir.mkdirs();
channel.setJarCache(new FileSystemJarCache(dir, true));
channel.call(new CallableBase<Void, IOException>() {
public Void call() throws IOException {
Channel.currentOrFail().setJarCache(new FileSystemJarCache(dir, true));
return null;
}
});
sum1 = channel.jarLoader.calcChecksum(jar1);
sum2 = channel.jarLoader.calcChecksum(jar2);
}
private File toFile(URL url) {
try {
return new File(url.toURI());
} catch (URISyntaxException e) {
return new File(url.getPath());
}
}
@Override
protected void tearDown() throws Exception {
cl.cleanup();
super.tearDown();
if (Launcher.isWindows()) {
// Current Resource loader implementation keep files open even if we close the classloader.
// This check has been never working correctly in Windows.
// TODO: Fix it as a part of JENKINS-38696
return;
}
// because the dir is used by FIleSystemJarCache to asynchronously load stuff
// we might fail to shut it down right away
for (int i=0; ; i++) {
try {
FileUtils.deleteDirectory(dir);
return;
} catch (IOException e) {
if (i==3) throw e;
Thread.sleep(1000);
}
}
}
/**
* This should cause the jar file to be sent to the other side
*/
public void testJarLoadingTest() throws Exception {
channel.call(new ForceJarLoad(sum1));
channel.call(new ForceJarLoad(sum2));
Callable<Void,IOException> sc = (Callable)cl.loadClass("test.ClassLoadingFromJarTester").newInstance();
((Function)sc).apply(new Verifier());
assertNull(channel.call(sc));
}
private static class Verifier implements Function<Object,Object>, Serializable {
public Object apply(Object o) {
try {
// verify that 'o' is loaded from a jar file
String loc = Which.classFileUrl(o.getClass()).toExternalForm();
System.out.println(loc);
assertTrue(loc, loc.startsWith("jar:"));
return null;
} catch (IOException e) {
throw new Error(e);
}
}
}
public void testGetResource() throws Exception {
channel.call(new ForceJarLoad(sum1));
channel.call(new ForceJarLoad(sum2));
Callable<String,IOException> c = (Callable<String,IOException>)cl.loadClass("test.HelloGetResource").newInstance();
String v = channel.call(c);
System.out.println(v);
verifyResource(v);
}
public void testGetResource_precache() throws Exception {
Callable<String,IOException> c = (Callable<String,IOException>)cl.loadClass("test.HelloGetResource").newInstance();
String v = channel.call(c);
System.out.println(v);
verifyResourcePrecache(v);
}
public void testGetResourceAsStream() throws Exception {
Callable<String,IOException> c = (Callable<String,IOException>)cl.loadClass("test.HelloGetResourceAsStream").newInstance();
String v = channel.call(c);
assertEquals("hello",v);
}
/**
* Validates that the resource is coming from a jar.
*/
private void verifyResource(String v) throws IOException, InterruptedException {
Assert.assertThat(v, allOf(startsWith("jar:file:"),
containsString(dir.toURI().getPath()),
endsWith("::hello")));
}
/**
* Validates that the resource is coming from a file path.
*/
private void verifyResourcePrecache(String v) throws IOException, InterruptedException {
assertTrue(v, v.startsWith("file:"));
assertTrue(v, v.endsWith("::hello"));
}
/**
* Once the jar files are cached, ClassLoader.getResources() should return jar URLs.
*/
public void testGetResources() throws Exception {
channel.call(new ForceJarLoad(sum1));
channel.call(new ForceJarLoad(sum2));
Callable<String,IOException> c = (Callable<String,IOException>)cl.loadClass("test.HelloGetResources").newInstance();
String v = channel.call(c);
System.out.println(v); // should find two resources
String[] lines = v.split("\n");
verifyResource(lines[0]);
Assert.assertThat(lines[1], allOf(startsWith("jar:file:"),
containsString(dir.toURI().getPath()),
endsWith("::hello2")));
}
/**
* Unlike {@link #testGetResources()}, the URL should begin with file:... before the jar file gets cached
*/
public void testGetResources_precache() throws Exception {
Callable<String,IOException> c = (Callable<String,IOException>)cl.loadClass("test.HelloGetResources").newInstance();
String v = channel.call(c);
System.out.println(v); // should find two resources
String[] lines = v.split("\n");
assertTrue(lines[0], lines[0].startsWith("file:"));
assertTrue(lines[1], lines[1].startsWith("file:"));
assertTrue(lines[0], lines[0].endsWith("::hello"));
assertTrue(lines[1], lines[1].endsWith("::hello2"));
}
public void testInnerClass() throws Exception {
Echo<Object> e = new Echo<Object>();
e.value = cl.loadClass("test.Foo").newInstance();
Object r = channel.call(e);
((Predicate)r).apply(null); // this verifies that the object is still in a good state
}
private static final class Echo<V> extends CallableBase<V,IOException> implements Serializable {
V value;
public V call() throws IOException {
return value;
}
}
/**
* Force the remote side to fetch the retrieval of the specific jar file.
*/
private static final class ForceJarLoad extends CallableBase<Void,IOException> implements Serializable{
private final long sum1,sum2;
private ForceJarLoad(Checksum sum) {
this.sum1 = sum.sum1;
this.sum2 = sum.sum2;
}
public Void call() throws IOException {
try {
final Channel ch = Channel.currentOrFail();
final JarCache jarCache = ch.getJarCache();
if (jarCache == null) {
throw new IOException("Cannot Force JAR load, JAR cache is disabled");
}
jarCache.resolve(ch,sum1,sum2).get();
return null;
} catch (InterruptedException e) {
throw new IOException(e);
} catch (ExecutionException e) {
throw new IOException(e);
}
}
}
}