Line data Source code
1 : // Copyright (C) 2017 The Android Open Source Project
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 :
15 : package com.google.gerrit.acceptance;
16 :
17 : import static com.google.common.truth.Truth.assertWithMessage;
18 : import static java.nio.charset.StandardCharsets.UTF_8;
19 : import static java.util.stream.Collectors.joining;
20 : import static org.junit.Assert.fail;
21 :
22 : import com.google.common.base.Joiner;
23 : import com.google.common.collect.ImmutableList;
24 : import com.google.common.collect.ImmutableMap;
25 : import com.google.common.collect.Streams;
26 : import com.google.common.io.ByteStreams;
27 : import com.google.gerrit.common.Nullable;
28 : import com.google.gerrit.extensions.api.GerritApi;
29 : import com.google.gerrit.extensions.api.groups.GroupInput;
30 : import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
31 : import com.google.gerrit.launcher.GerritLauncher;
32 : import com.google.gerrit.server.CurrentUser;
33 : import com.google.gerrit.server.config.SitePaths;
34 : import com.google.gerrit.server.util.ManualRequestContext;
35 : import com.google.gerrit.server.util.OneOffRequestContext;
36 : import com.google.gerrit.server.util.RequestContext;
37 : import com.google.gerrit.server.util.git.DelegateSystemReader;
38 : import com.google.gerrit.testing.ConfigSuite;
39 : import com.google.inject.Injector;
40 : import com.google.inject.Module;
41 : import java.io.File;
42 : import java.io.IOException;
43 : import java.io.InputStream;
44 : import java.io.InterruptedIOException;
45 : import java.nio.file.Path;
46 : import java.util.Arrays;
47 : import java.util.Collections;
48 : import org.eclipse.jgit.lib.Config;
49 : import org.eclipse.jgit.storage.file.FileBasedConfig;
50 : import org.eclipse.jgit.util.FS;
51 : import org.eclipse.jgit.util.SystemReader;
52 : import org.junit.Rule;
53 : import org.junit.rules.RuleChain;
54 : import org.junit.rules.TemporaryFolder;
55 : import org.junit.rules.TestRule;
56 : import org.junit.runner.Description;
57 : import org.junit.runner.RunWith;
58 : import org.junit.runners.model.Statement;
59 :
60 : @RunWith(ConfigSuite.class)
61 : @UseLocalDisk
62 7 : public abstract class StandaloneSiteTest {
63 : protected class ServerContext implements RequestContext, AutoCloseable {
64 : private final GerritServer server;
65 : private final ManualRequestContext ctx;
66 :
67 7 : private ServerContext(GerritServer server) throws Exception {
68 7 : this.server = server;
69 7 : Injector i = server.getTestInjector();
70 7 : if (admin == null) {
71 7 : admin = i.getInstance(AccountCreator.class).admin();
72 : }
73 7 : ctx = i.getInstance(OneOffRequestContext.class).openAs(admin.id());
74 7 : GerritApi gApi = i.getInstance(GerritApi.class);
75 :
76 : try {
77 : // ServerContext ctor is called multiple times but the group can be only created once
78 1 : gApi.groups().id("Group");
79 7 : } catch (ResourceNotFoundException e) {
80 7 : GroupInput in = new GroupInput();
81 7 : in.members = Collections.singletonList("admin");
82 7 : in.name = "Group";
83 7 : gApi.groups().create(in);
84 1 : }
85 7 : }
86 :
87 : @Override
88 : public CurrentUser getUser() {
89 0 : return ctx.getUser();
90 : }
91 :
92 : public Injector getInjector() {
93 7 : return server.getTestInjector();
94 : }
95 :
96 : @Override
97 : public void close() throws Exception {
98 : try {
99 7 : ctx.close();
100 : } finally {
101 7 : server.close();
102 : }
103 7 : }
104 : }
105 :
106 : @ConfigSuite.Parameter public Config baseConfig;
107 : @ConfigSuite.Name private String configName;
108 :
109 7 : private final TemporaryFolder tempSiteDir = new TemporaryFolder();
110 :
111 7 : private final TestRule testRunner =
112 : (base, description) ->
113 7 : new Statement() {
114 : @Override
115 : public void evaluate() throws Throwable {
116 : try {
117 7 : beforeTest(description);
118 7 : base.evaluate();
119 : } finally {
120 7 : afterTest();
121 : }
122 7 : }
123 : };
124 :
125 7 : @Rule public RuleChain ruleChain = RuleChain.outerRule(tempSiteDir).around(testRunner);
126 :
127 : protected SitePaths sitePaths;
128 : protected TestAccount admin;
129 :
130 : private GerritServer.Description serverDesc;
131 : private SystemReader oldSystemReader;
132 :
133 : private void beforeTest(Description description) throws Exception {
134 : // SystemReader must be overridden before creating any repos, since they read the user/system
135 : // configs at initialization time, and are then stored in the RepositoryCache forever.
136 7 : oldSystemReader = setFakeSystemReader(tempSiteDir.getRoot());
137 :
138 7 : serverDesc = GerritServer.Description.forTestMethod(description, configName);
139 7 : sitePaths = new SitePaths(tempSiteDir.getRoot().toPath());
140 7 : GerritServer.init(serverDesc, baseConfig, sitePaths.site_path);
141 7 : }
142 :
143 : private static SystemReader setFakeSystemReader(File tempDir) {
144 7 : SystemReader oldSystemReader = SystemReader.getInstance();
145 7 : SystemReader.setInstance(
146 7 : new DelegateSystemReader(oldSystemReader) {
147 : @Override
148 : public FileBasedConfig openJGitConfig(Config parent, FS fs) {
149 7 : return new FileBasedConfig(parent, new File(tempDir, "jgit.config"), FS.detect());
150 : }
151 :
152 : @Override
153 : public FileBasedConfig openUserConfig(Config parent, FS fs) {
154 7 : return new FileBasedConfig(parent, new File(tempDir, "user.config"), FS.detect());
155 : }
156 :
157 : @Override
158 : public FileBasedConfig openSystemConfig(Config parent, FS fs) {
159 7 : return new FileBasedConfig(parent, new File(tempDir, "system.config"), FS.detect());
160 : }
161 : });
162 7 : return oldSystemReader;
163 : }
164 :
165 : private void afterTest() throws Exception {
166 7 : SystemReader.setInstance(oldSystemReader);
167 7 : oldSystemReader = null;
168 7 : }
169 :
170 : protected ServerContext startServer() throws Exception {
171 7 : return startServer(null);
172 : }
173 :
174 : protected ServerContext startServer(@Nullable Module testSysModule, String... additionalArgs)
175 : throws Exception {
176 7 : return new ServerContext(startImpl(testSysModule, additionalArgs));
177 : }
178 :
179 : protected void assertServerStartupFails() throws Exception {
180 0 : try (GerritServer server = startImpl(null)) {
181 0 : fail("expected server startup to fail");
182 1 : } catch (GerritServer.StartupException e) {
183 : // Expected.
184 0 : }
185 1 : }
186 :
187 : private GerritServer startImpl(@Nullable Module testSysModule, String... additionalArgs)
188 : throws Exception {
189 7 : return GerritServer.start(
190 : serverDesc,
191 : baseConfig,
192 : sitePaths.site_path,
193 : testSysModule,
194 : null,
195 : null,
196 : null,
197 : additionalArgs);
198 : }
199 :
200 : protected static void runGerrit(String... args) throws Exception {
201 : // Use invokeProgram with the current classloader, rather than mainImpl, which would create a
202 : // new classloader. This is necessary so that static state, particularly the SystemReader, is
203 : // shared with the test method.
204 1 : assertWithMessage("gerrit.war " + Arrays.stream(args).collect(joining(" ")))
205 1 : .that(GerritLauncher.invokeProgram(StandaloneSiteTest.class.getClassLoader(), args))
206 1 : .isEqualTo(0);
207 1 : }
208 :
209 : @SafeVarargs
210 : protected static void runGerrit(Iterable<String>... multiArgs) throws Exception {
211 0 : runGerrit(Arrays.stream(multiArgs).flatMap(Streams::stream).toArray(String[]::new));
212 0 : }
213 :
214 : protected static String execute(
215 : ImmutableList<String> cmd, File dir, ImmutableMap<String, String> env) throws IOException {
216 5 : return execute(cmd, dir, env, null);
217 : }
218 :
219 : protected static String execute(
220 : ImmutableList<String> cmd,
221 : File dir,
222 : ImmutableMap<String, String> env,
223 : @Nullable Path outputPath)
224 : throws IOException {
225 5 : ProcessBuilder pb = new ProcessBuilder(cmd);
226 5 : pb.directory(dir);
227 5 : if (outputPath != null) {
228 1 : pb.redirectOutput(outputPath.toFile());
229 : } else {
230 5 : pb.redirectErrorStream(true);
231 : }
232 5 : pb.environment().putAll(env);
233 5 : Process p = pb.start();
234 : byte[] out;
235 5 : try (InputStream in = p.getInputStream()) {
236 5 : out = ByteStreams.toByteArray(in);
237 : } finally {
238 5 : p.getOutputStream().close();
239 : }
240 :
241 : int status;
242 : try {
243 5 : status = p.waitFor();
244 0 : } catch (InterruptedException e) {
245 0 : InterruptedIOException iioe =
246 : new InterruptedIOException(
247 0 : "interrupted waiting for: " + Joiner.on(' ').join(pb.command()));
248 0 : iioe.initCause(e);
249 0 : throw iioe;
250 5 : }
251 :
252 5 : String result = new String(out, UTF_8);
253 5 : if (status != 0) {
254 5 : throw new IOException(result);
255 : }
256 :
257 5 : return result.trim();
258 : }
259 : }
|