View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *  http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.directory.server.core.integ.state;
20  
21  
22  import java.io.IOException;
23  import java.lang.reflect.Field;
24  import java.lang.reflect.InvocationTargetException;
25  import javax.naming.NamingException;
26  
27  import org.apache.directory.server.core.DirectoryService;
28  import org.apache.directory.server.core.integ.InheritableSettings;
29  import org.junit.internal.runners.MethodRoadie;
30  import org.junit.internal.runners.TestClass;
31  import org.junit.internal.runners.TestMethod;
32  import org.junit.runner.Description;
33  import org.junit.runner.notification.RunNotifier;
34  import org.slf4j.Logger;
35  import org.slf4j.LoggerFactory;
36  
37  
38  /**
39   * The context for managing the state of an integration test service.
40   * Each thread of execution driving tests manages it's own service context.
41   * Hence parallelism can be achieved while running integration tests.
42   *
43   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
44   * @version $Rev$, $Date$
45   */
46  public class TestServiceContext
47  {
48      /** The logger */
49      private static final Logger LOG = LoggerFactory.getLogger( TestServiceContext.class );
50      
51      /** The ThreadLocal containing the contexts */
52      private static final ThreadLocal<TestServiceContext> CONTEXTS = new ThreadLocal<TestServiceContext>();
53  
54      /** The NonExistant state instance */
55      private final TestServiceState nonExistentState = new NonExistentState( this );
56  
57      /** The StartedPristine state instance */
58      private final TestServiceState startedPristineState = new StartedPristineState( this );
59      
60      /** The StartedNormal state instance */
61      private final TestServiceState startedNormalState = new StartedNormalState( this );
62  
63  
64      /** current service state with respect to the testing life cycle */
65      private TestServiceState state = nonExistentState;
66  
67      /** the core directory service managed by this context */
68      private DirectoryService service;
69  
70  
71      /**
72       * A private constructor, the clas contains only static methods, 
73       * no need to construct an instance.
74       */
75      private TestServiceContext()
76      {
77          
78      }
79  
80  
81      /**
82       * Gets the TestServiceContext associated with the current thread of
83       * execution.  If one does not yet exist it will be created.
84       *
85       * @return the context associated with the calling thread
86       */
87      public static TestServiceContext get()
88      {
89          TestServiceContext context = CONTEXTS.get();
90  
91          if ( context == null )
92          {
93              context = new TestServiceContext();
94              CONTEXTS.set( context );
95          }
96  
97          return context;
98      }
99      
100 
101     /**
102      * Sets the TestServiceContext for this current thread
103      *
104      * @param context the context associated with the calling thread
105      */
106     public static void set( TestServiceContext context )
107     {
108         CONTEXTS.set( context );
109     }
110 
111 
112     /**
113      * Action where an attempt is made to create the service.  Service
114      * creation in this system is the combined instantiation and
115      * configuration which takes place when the factory is used to get
116      * a new instance of the service.
117      *
118      * @param settings the settings for this test
119      * @throws NamingException if we can't create the service
120      */
121     public static void create( InheritableSettings settings ) throws NamingException
122     {
123         get().state.create( settings );
124     }
125 
126 
127     /**
128      * Action where an attempt is made to destroy the service.  This
129      * entails nulling out reference to it and triggering garbage
130      * collection.
131      */
132     public static void destroy()
133     {
134         get().state.destroy();
135     }
136 
137 
138     /**
139      * Action where an attempt is made to erase the contents of the
140      * working directory used by the service for various files including
141      * partition database files.
142      *
143      * @throws IOException on errors while deleting the working directory
144      */
145     public static void cleanup() throws IOException
146     {
147         get().state.cleanup();
148     }
149 
150 
151     /**
152      * Action where an attempt is made to start up the service.
153      *
154      * @throws Exception on failures to start the core directory service
155      */
156     public static void startup() throws Exception
157     {
158         get().state.startup();
159     }
160 
161 
162     /**
163      * Action where an attempt is made to shutdown the service.
164      *
165      * @throws Exception on failures to stop the core directory service
166      */
167     public static void shutdown() throws Exception
168     {
169         get().state.shutdown();
170     }
171 
172 
173     /**
174      * Action where an attempt is made to run a test against the service.
175      *
176      * @param testClass the class whose test method is to be run
177      * @param testMethod the test method which is to be run
178      * @param notifier a notifier to report failures to
179      * @param settings the inherited settings and annotations associated with
180      * the test method
181      */
182     public static void test( TestClass testClass, TestMethod testMethod, RunNotifier notifier,
183                              InheritableSettings settings )
184     {
185         LOG.debug( "calling test(): {}", settings.getDescription().getDisplayName() );
186         get().getState().test( testClass, testMethod, notifier, settings );
187     }
188 
189 
190     /**
191      * Action where an attempt is made to revert the service to it's
192      * initial start up state by using a previous snapshot.
193      *
194      * @throws Exception on failures to revert the state of the core
195      * directory service
196      */
197     public static void revert() throws Exception
198     {
199         get().state.revert();
200     }
201 
202 
203     static void invokeTest( TestClass testClass, TestMethod testMethod, RunNotifier notifier, Description description )
204     {
205         try
206         {
207             Object test = testClass.getConstructor().newInstance();
208             Field field = testClass.getJavaClass().getDeclaredField( "service" );
209             field.set( testClass.getJavaClass(), get().getService() );
210             new MethodRoadie( test, testMethod, notifier, description ).run();
211         }
212         catch ( InvocationTargetException e )
213         {
214             LOG.error( "Failed to invoke test method: " + description.getDisplayName(), e.getCause() );
215             notifier.testAborted( description, e.getCause() );
216             return;
217         }
218         catch ( InstantiationException ie )
219         {
220             LOG.error( "Failed to invoke test method: " + description.getDisplayName(), ie );
221             notifier.testAborted( description, ie );
222             return;
223         }
224         catch ( IllegalAccessException iae )
225         {
226             LOG.error( "Failed to invoke test method: " + description.getDisplayName(), iae );
227             notifier.testAborted( description, iae );
228             return;
229         }
230         catch ( NoSuchMethodException nsme )
231         {
232             LOG.error( "Failed to invoke test method: " + description.getDisplayName(), nsme );
233             notifier.testAborted( description, nsme );
234             return;
235         }
236         catch ( NoSuchFieldException nsfe )
237         {
238             LOG.error( "Failed to invoke test method: " + description.getDisplayName(), nsfe );
239             notifier.testAborted( description, nsfe );
240             return;
241         }
242     }
243 
244 
245     // -----------------------------------------------------------------------
246     // Package Friendly Instance Methods
247     // -----------------------------------------------------------------------
248 
249 
250     void setState( TestServiceState state )
251     {
252         this.state = state;
253     }
254 
255 
256     TestServiceState getState()
257     {
258         return state;
259     }
260 
261 
262     TestServiceState getNonExistentState()
263     {
264         return nonExistentState;
265     }
266 
267 
268     TestServiceState getStartedPristineState()
269     {
270         return startedPristineState;
271     }
272 
273 
274     TestServiceState getStartedNormalState()
275     {
276         return startedNormalState;
277     }
278 
279 
280     DirectoryService getService()
281     {
282         return service;
283     }
284 
285 
286     void setService( DirectoryService service )
287     {
288         this.service = service;
289     }
290 }