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 package com.aragost.javahg.internals;
27
28 import java.io.File;
29 import java.io.IOException;
30 import java.io.InputStream;
31 import java.lang.reflect.Field;
32 import java.util.Collections;
33 import java.util.List;
34
35 import org.junit.Assert;
36 import org.junit.Ignore;
37 import org.junit.Test;
38
39 import com.aragost.javahg.BaseRepository;
40 import com.aragost.javahg.Bundle;
41 import com.aragost.javahg.Changeset;
42 import com.aragost.javahg.Repository;
43 import com.aragost.javahg.RepositoryConfiguration;
44 import com.aragost.javahg.commands.AddCommand;
45 import com.aragost.javahg.commands.CommitCommand;
46 import com.aragost.javahg.commands.ExecutionException;
47 import com.aragost.javahg.commands.IncomingCommand;
48 import com.aragost.javahg.commands.LogCommand;
49 import com.aragost.javahg.commands.VersionCommand;
50 import com.aragost.javahg.test.AbstractTestCase;
51 import com.aragost.javahg.test.JavaHgTestExtension;
52 import com.google.common.base.Strings;
53 import com.google.common.collect.Lists;
54 import com.google.common.io.Files;
55
56 public class ServerTest extends AbstractTestCase {
57
58 private List<String> empty = Collections.emptyList();
59
60 @Test
61 public void testStartStop() throws IOException {
62 File dir = Files.createTempDir();
63 Server server = new Server(RepositoryConfiguration.DEFAULT.getHgBin(),
64 RepositoryConfiguration.DEFAULT.getEncoding());
65 server.initMecurialRepository(dir);
66 server.start(dir, null, empty, null, null);
67 server.stop();
68 deleteTempDir(dir);
69 }
70
71 @Test
72 public void testStopWhileProducingOutput() throws IOException {
73 Repository repo = getTestRepository();
74 Server server = getFirstServer(repo);
75 InputStream stdout = server.runCommand(Lists.newArrayList("version"), VersionCommand.on(repo));
76
77
78
79
80 server.stop();
81 try {
82 stdout.read();
83 Assert.fail("IOException expected");
84 } catch (IOException e) {
85
86 }
87
88 server.start(repo.getDirectory(), null, empty, null, null);
89
90 VersionCommand.on(repo).execute();
91 }
92
93 @Test
94 public void testLock() throws IOException, InterruptedException {
95 Repository repo = getTestRepository();
96 TestableCommand command = new TestableCommand(repo, "version");
97
98
99
100
101
102 InputStream stdout = command.executeToStream();
103 try {
104 Server server = getFirstServer(repo);
105 server.runCommand(Lists.newArrayList("version"), command);
106
107 Assert.fail("Exception expected");
108 } catch (IllegalStateException e) {
109 Utils.consumeAll(stdout);
110 }
111
112 command.executeToStream();
113 }
114
115 @Test
116 public void testServerRefCount() throws IOException {
117 BaseRepository repo = getTestRepository();
118 BaseRepository repo2 = getTestRepository2();
119 writeFile("a");
120 commit();
121 Bundle bundle = IncomingCommand.on(repo2).execute(repo);
122 Repository repo3 = bundle.getOverlayRepository();
123 Assert.assertSame(repo2.getServerPool(), repo3.getServerPool());
124 ServerPool pool = repo2.getServerPool();
125 Assert.assertEquals(1, pool.getServers().size());
126 Assert.assertNotNull(pool.getServers().get(0).getProcess());
127 repo2.close();
128 Assert.assertNotNull(pool.getServers().get(0).getProcess());
129 Server server = pool.getServers().get(0);
130 bundle.close();
131 Assert.assertNull(server.getProcess());
132 Assert.assertTrue(pool.getServers().isEmpty());
133 }
134
135 @Test
136 public void testConfigChanges() throws IOException {
137 BaseRepository repo = getTestRepository();
138 GenericCommand cmd = new GenericCommand(repo, "version") {
139 {
140 {
141 cmdAppend("--config", "ui.username=xxx");
142 }
143 }
144 };
145 cmd.execute();
146 writeFile("A");
147 repo.workingCopy().add("A");
148 try {
149
150 CommitCommand commit = CommitCommand.on(repo).message("m");
151 Changeset cs = commit.execute();
152 assertFailedExecution(commit, "Username is " + cs.getUser());
153 } catch (ExecutionException e) {
154 Assert.assertTrue(e.getMessage().startsWith("no username supplied "));
155 }
156 }
157
158 @Test
159 public void testKillServerProcess() throws IOException {
160 File dir = Files.createTempDir();
161 RepositoryConfiguration repoConfig = new RepositoryConfiguration();
162 repoConfig.addExtension(JavaHgTestExtension.class);
163 Repository repo = Repository.create(repoConfig, dir);
164 Process process = getFirstServer(repo).getProcess();
165 process.destroy();
166
167 try {
168 VersionCommand cmd = VersionCommand.on(repo);
169 cmd.execute();
170 assertFailedExecution(cmd);
171 } catch (UnexpectedServerTerminationException e) {
172
173 }
174 repo.close();
175
176 repo = Repository.open(repoConfig, dir);
177 String longStringThatDoesntFitInBuffers = Strings.repeat("x", 10 * 1000 * 1000);
178 GenericCommand cmd = new GenericCommand(repo, "javahg-write");
179 HgInputStream stream = cmd.launchStream("o", longStringThatDoesntFitInBuffers);
180 boolean killed = killProcess(process);
181 if (killed) {
182
183 try {
184
185 Utils.readStream(stream, repo.getServerPool().newDecoder());
186
187
188
189 } catch (UnexpectedServerTerminationException e) {
190 System.err.println("Exit value in testKillServerProcess: " + e.getExitValue());
191
192 }
193 }
194 repo.close();
195
196 deleteTempDir(dir);
197 }
198
199 @Test
200 @Ignore
201 public void testStderrDuringStartup() throws IOException {
202 RepositoryConfiguration conf = new RepositoryConfiguration();
203 String stderr = retrieveStartupStderr(conf);
204 Assert.assertTrue("stderr=" + stderr,
205 stderr.startsWith("*** failed to import extension javahgmissing from javahgmissing: [Errno 2]"));
206 }
207
208 @Test
209 public void testStderrDuringStartupWillFullBuffer() throws IOException {
210 RepositoryConfiguration conf = new RepositoryConfiguration();
211 conf.setStderrBufferSize(1);
212 String stderr = retrieveStartupStderr(conf);
213 Assert.assertEquals("*", stderr);
214 }
215
216
217 @Test
218 public void testCloneRequiringAuth() throws Exception {
219 BaseRepository repoA = getTestRepository();
220
221 writeFile(repoA, "x", "abc");
222 AddCommand.on(repoA).execute();
223 CommitCommand.on(repoA).message("added x").user("user").execute();
224
225
226 String extConfig = "extensions.ra="
227 + Utils.resourceAsFile("/require-auth.py").getPath();
228
229
230
231 ServeState serveState = startServing(repoA, "--config", extConfig);
232
233 try {
234 int port = serveState.getPort();
235
236
237 File cloneDir = Files.createTempDir();
238 Server server = new Server(
239 RepositoryConfiguration.DEFAULT.getHgBin(),
240 RepositoryConfiguration.DEFAULT.getEncoding());
241 server.cloneMercurialRepository(cloneDir,
242 Utils.resourceAsFile("/test-hgrc-auth").getPath(),
243 "http://localhost:" + port);
244 String xContents = Files.readFirstLine(new File(cloneDir, "x"),
245 utf8());
246 Assert.assertEquals("abc", xContents);
247 deleteTempDir(cloneDir);
248
249
250 File cloneDir2 = Files.createTempDir();
251 Server server2 = new Server(
252 RepositoryConfiguration.DEFAULT.getHgBin(),
253 RepositoryConfiguration.DEFAULT.getEncoding());
254 try {
255 server2.cloneMercurialRepository(cloneDir, "",
256 "http://localhost:" + port);
257 Assert.fail("Didn't get expected http authorization exception");
258 } catch (Exception e) {
259 if (!e.getMessage().contains("http authorization required")) {
260 Assert.fail("Didn't get expected http authorization exception. Got "
261 + e);
262 }
263 }
264 deleteTempDir(cloneDir2);
265 } finally {
266 serveState.stop();
267 }
268 }
269
270
271
272
273
274
275
276
277 private String retrieveStartupStderr(RepositoryConfiguration conf) throws IOException {
278 conf.setHgrcPath(Utils.resourceAsFile("/missing-extension.hgrc").getPath());
279 File dir = Files.createTempDir();
280 BaseRepository repo = Repository.create(conf, dir);
281 String stderr = getFirstServer(repo).getStartupStderr();
282 repo.close();
283 deleteTempDir(dir);
284 return stderr;
285 }
286
287
288
289
290
291
292
293
294
295
296
297
298
299 private boolean killProcess(Process process) {
300 int pid = readPid(process);
301 if (pid != 0) {
302 killProcess(pid);
303 return true;
304 }
305 return false;
306 }
307
308
309
310
311
312
313
314
315 private static int readPid(Process process) {
316 try {
317 Field pidField = process.getClass().getDeclaredField("pid");
318 pidField.setAccessible(true);
319 if (pidField.getType().equals(Integer.TYPE)) {
320 String osName = System.getProperty("os.name");
321 int pid = pidField.getInt(process);
322 if (osName.startsWith("Mac OS X")) {
323
324
325
326 pid++;
327 }
328 return pid;
329 }
330 } catch (NoSuchFieldException e) {
331 return 0;
332 } catch (Exception e) {
333 throw Utils.asRuntime(e);
334 }
335 return 0;
336 }
337
338 @Test
339 public void testServerIdle() throws InterruptedException {
340 RepositoryConfiguration conf = makeRepoConf();
341 conf.setServerIdleTime(1);
342 BaseRepository repo = Repository.create(conf, Files.createTempDir());
343
344 Assert.assertEquals(1, repo.getServerPool().getNumIdleServers());
345
346 Thread.sleep(2000);
347
348 Assert.assertEquals(0, repo.getServerPool().getNumIdleServers());
349 LogCommand.on(repo).execute();
350 Assert.assertEquals(1, repo.getServerPool().getNumIdleServers());
351 }
352 }