1   /*
2    * Copyright 2020 LINE Corporation
3    *
4    * LINE Corporation licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  
17  package com.linecorp.centraldogma.testing.junit4;
18  
19  import java.io.IOException;
20  import java.net.InetSocketAddress;
21  import java.util.concurrent.CompletableFuture;
22  
23  import org.junit.Rule;
24  import org.junit.rules.TemporaryFolder;
25  
26  import com.spotify.futures.CompletableFutures;
27  
28  import com.linecorp.armeria.client.WebClient;
29  import com.linecorp.armeria.client.WebClientBuilder;
30  import com.linecorp.centraldogma.client.CentralDogma;
31  import com.linecorp.centraldogma.client.armeria.ArmeriaCentralDogmaBuilder;
32  import com.linecorp.centraldogma.client.armeria.legacy.LegacyCentralDogmaBuilder;
33  import com.linecorp.centraldogma.server.CentralDogmaBuilder;
34  import com.linecorp.centraldogma.server.MirroringService;
35  import com.linecorp.centraldogma.server.storage.project.ProjectManager;
36  import com.linecorp.centraldogma.testing.internal.CentralDogmaRuleDelegate;
37  
38  /**
39   * A JUnit {@link Rule} that starts an embedded Central Dogma server.
40   *
41   * <pre>{@code
42   * > public class MyTest {
43   * >     @ClassRule
44   * >     public static final CentralDogmaRule rule = new CentralDogmaRule();
45   * >
46   * >     @Test
47   * >     public void test() throws Exception {
48   * >         CentralDogma dogma = rule.client();
49   * >         dogma.push(...).join();
50   * >         ...
51   * >     }
52   * > }
53   * }</pre>
54   */
55  public class CentralDogmaRule extends TemporaryFolder {
56  
57      private final CentralDogmaRuleDelegate delegate;
58  
59      /**
60       * Creates a new instance with TLS disabled.
61       */
62      public CentralDogmaRule() {
63          this(false);
64      }
65  
66      /**
67       * Creates a new instance.
68       */
69      public CentralDogmaRule(boolean useTls) {
70          delegate = new CentralDogmaRuleDelegate(useTls) {
71              @Override
72              protected void configure(CentralDogmaBuilder builder) {
73                  CentralDogmaRule.this.configure(builder);
74              }
75  
76              @Override
77              protected void configureClient(ArmeriaCentralDogmaBuilder builder) {
78                  CentralDogmaRule.this.configureClient(builder);
79              }
80  
81              @Override
82              protected void configureClient(LegacyCentralDogmaBuilder builder) {
83                  CentralDogmaRule.this.configureClient(builder);
84              }
85  
86              @Override
87              protected void configureHttpClient(WebClientBuilder builder) {
88                  CentralDogmaRule.this.configureHttpClient(builder);
89              }
90  
91              @Override
92              protected void scaffold(CentralDogma client) {
93                  CentralDogmaRule.this.scaffold(client);
94              }
95          };
96      }
97  
98      /**
99       * Starts an embedded server and calls {@link #scaffold(CentralDogma)}.
100      */
101     @Override
102     protected void before() throws Throwable {
103         super.before();
104         delegate.setUp(getRoot());
105     }
106 
107     /**
108      * Stops the server and deletes the temporary files created by the server.
109      */
110     @Override
111     protected void after() {
112         stopAsync().whenComplete((unused1, unused2) -> delete());
113     }
114 
115     /**
116      * Creates a new server, configures it with {@link #configure(CentralDogmaBuilder)} and starts the server.
117      * Note that you don't need to call this method if you did not stop the server with {@link #stop()},
118      * because the server is automatically started up by JUnit.
119      */
120     public final void start() {
121         startAsync().join();
122     }
123 
124     /**
125      * Creates a new server, configures it with {@link #configure(CentralDogmaBuilder)},
126      * and starts the server asynchronously.
127      */
128     public final CompletableFuture<Void> startAsync() {
129         // Create the root folder first if it doesn't exist.
130         try {
131             getRoot();
132         } catch (IllegalStateException unused) {
133             try {
134                 create();
135             } catch (IOException e) {
136                 return CompletableFutures.exceptionallyCompletedFuture(e);
137             }
138         }
139 
140         return delegate.startAsync(getRoot());
141     }
142 
143     /**
144      * Stops the server and deletes the temporary files created by the server. Note that you don't usually need
145      * to call this method manually because the server is automatically stopped at the end by JUnit.
146      */
147     public final void stop() {
148         stopAsync().join();
149     }
150 
151     /**
152      * Stops the server and deletes the temporary files created by the server. Note that you don't usually need
153      * to call this method manually because the server is automatically stopped at the end by JUnit.
154      */
155     public final CompletableFuture<Void> stopAsync() {
156         return delegate.stopAsync();
157     }
158 
159     /**
160      * Returns whether the server is running over TLS or not.
161      */
162     public boolean useTls() {
163         return delegate.useTls();
164     }
165 
166     /**
167      * Returns the server.
168      *
169      * @throws IllegalStateException if Central Dogma did not start yet
170      */
171     public final com.linecorp.centraldogma.server.CentralDogma dogma() {
172         return delegate.dogma();
173     }
174 
175     /**
176      * Returns the {@link ProjectManager} of the server.
177      *
178      * @throws IllegalStateException if Central Dogma did not start yet
179      */
180     public ProjectManager projectManager() {
181         return delegate.projectManager();
182     }
183 
184     /**
185      * Returns the {@link MirroringService} of the server.
186      *
187      * @throws IllegalStateException if Central Dogma did not start yet
188      */
189     public final MirroringService mirroringService() {
190         return delegate.mirroringService();
191     }
192 
193     /**
194      * Returns the HTTP-based {@link CentralDogma} client.
195      *
196      * @throws IllegalStateException if Central Dogma did not start yet
197      */
198     public final CentralDogma client() {
199         return delegate.client();
200     }
201 
202     /**
203      * Returns the Thrift-based {@link CentralDogma} client.
204      *
205      * @throws IllegalStateException if Central Dogma did not start yet
206      */
207     public final CentralDogma legacyClient() {
208         return delegate.legacyClient();
209     }
210 
211     /**
212      * Returns the HTTP client.
213      *
214      * @throws IllegalStateException if Central Dogma did not start yet
215      */
216     public final WebClient httpClient() {
217         return delegate.httpClient();
218     }
219 
220     /**
221      * Returns the server address.
222      *
223      * @throws IllegalStateException if Central Dogma did not start yet
224      */
225     public final InetSocketAddress serverAddress() {
226         return delegate.serverAddress();
227     }
228 
229     /**
230      * Override this method to configure the server.
231      */
232     protected void configure(CentralDogmaBuilder builder) {}
233 
234     /**
235      * Override this method to configure the HTTP-based {@link CentralDogma} client builder.
236      */
237     protected void configureClient(ArmeriaCentralDogmaBuilder builder) {}
238 
239     /**
240      * Override this method to configure the Thrift-based {@link CentralDogma} client builder.
241      */
242     protected void configureClient(LegacyCentralDogmaBuilder builder) {}
243 
244     /**
245      * Override this method to configure the {@link WebClient} builder.
246      */
247     protected void configureHttpClient(WebClientBuilder builder) {}
248 
249     /**
250      * Override this method to perform the initial updates on the server,
251      * such as creating a repository and populating sample data.
252      */
253     protected void scaffold(CentralDogma client) {}
254 }