View Javadoc
1   package it.perproduct;
2   
3   import com.atlassian.plugin.spring.scanner.annotation.export.ExportAsService;
4   import com.atlassian.plugin.spring.scanner.annotation.imports.ComponentImport;
5   import com.atlassian.plugin.spring.scanner.test.servlet.ComponentStatusServlet;
6   import com.atlassian.plugin.spring.scanner.test.servlet.ManageDynamicContextServlet;
7   import com.google.common.collect.ImmutableList;
8   import it.allproducts.ComponentExpectations;
9   import it.allproducts.ComponentExpectations.AbstractExpectedComponent;
10  import org.hamcrest.Matcher;
11  import org.hamcrest.Matchers;
12  import org.junit.Test;
13  import org.springframework.stereotype.Component;
14  
15  import java.io.IOException;
16  import java.util.Collection;
17  import java.util.List;
18  import java.util.stream.Collectors;
19  
20  import static org.junit.Assert.assertThat;
21  
22  /**
23   * Base class for integration tests of component-related functionality common to all products,
24   * such as
25   * {@link ComponentImport},
26   * {@link ExportAsService},
27   * and the dynamic context creation / profile support.
28   * (i.e. everything that's not a product-specific component or import)
29   *
30   * See also product-specific subclasses.
31   * See {@link it.allproducts.TestCustomModuleType}.
32   */
33  public abstract class AbstractComponentsInProductTest extends AbstractInProductTest {
34  
35      /**
36       * @see ComponentStatusServlet
37       */
38      private static final String COMPONENT_STATUS_URL = BASEURL + "/plugins/servlet/component-status?components";
39  
40      /**
41       * @see ComponentStatusServlet
42       */
43      private static final String SERVICE_STATUS_URL = BASEURL + "/plugins/servlet/component-status?services";
44  
45      /**
46       * @see ManageDynamicContextServlet
47       */
48      private static final String START_DYNAMIC_CONTEXT_URL = BASEURL + "/plugins/servlet/manage-dynamic-contexts?startup";
49      private static final String STOP_DYNAMIC_CONTEXT_URL = BASEURL + "/plugins/servlet/manage-dynamic-contexts?shutdown";
50  
51      /**
52       * Test that {@link Component}, {@link ComponentImport} etc. are working in atlassian-spring-scanner-maven-test.
53       */
54      @Test
55      public void testComponents() throws Exception {
56          List<String> actualComponentsInProduct = readStringList(COMPONENT_STATUS_URL);
57          List<AbstractExpectedComponent> expected = getExpectedComponentsWithDefaultProfile();
58  
59          assertThat(actualComponentsInProduct, hasComponents(expected));
60      }
61  
62      /**
63       * Test that {@link ExportAsService} etc. are working in atlassian-spring-scanner-maven-test.
64       */
65      @Test
66      public void testServices() throws Exception {
67          List<String> actualServicesInProduct = readStringList(SERVICE_STATUS_URL);
68          List<AbstractExpectedComponent> expected = getExpectedServiceExportsWithDefaultProfile();
69  
70          assertThat(actualServicesInProduct, hasComponents(expected));
71      }
72  
73      /**
74       * Test dynamic creation and shutdown of inner spring context (profiles)
75       */
76      @Test
77      public void testDynamicContext() throws Exception {
78          // Initially, we're running with the default profile, so we get the default profile's components and services (same as other tests)
79  
80          List<AbstractExpectedComponent> expectedComponentsDefaultProfile = getExpectedComponentsWithDefaultProfile();
81          List<AbstractExpectedComponent> expectedServicesDefaultProfile = getExpectedServiceExportsWithDefaultProfile();
82  
83          assertComponentsAndServices(expectedComponentsDefaultProfile, expectedServicesDefaultProfile);
84  
85          // Enable the dynamic context. This should load DynamicComponent.
86          getUrl(START_DYNAMIC_CONTEXT_URL);
87  
88          // When the dynamic profile is activated, we expect a new component and a new import to appear.
89          // No change in exported services.
90          List<AbstractExpectedComponent> expectedDynamicComponents =
91                  ImmutableList.<AbstractExpectedComponent>builder()
92                          .addAll(expectedComponentsDefaultProfile)
93                          .addAll(ComponentExpectations.COMMON.getExpectedScannerCreatedDynamicComponents())
94                          .addAll(ComponentExpectations.COMMON.getExpectedScannerCreatedDynamicComponentImports())
95                          .build();
96  
97          assertComponentsAndServices(expectedDynamicComponents, expectedServicesDefaultProfile);
98  
99          // Stop the dynamic context - we should then return to the starting state - only default profile's components and services
100         getUrl(STOP_DYNAMIC_CONTEXT_URL);
101 
102         assertComponentsAndServices(expectedComponentsDefaultProfile, expectedServicesDefaultProfile);
103     }
104 
105     private void assertComponentsAndServices(List<AbstractExpectedComponent> expectedComponents,
106                                              List<AbstractExpectedComponent> expectedServices)
107             throws IOException {
108         List<String> actualComponents = readStringList(COMPONENT_STATUS_URL);
109         List<String> actualServices = readStringList(SERVICE_STATUS_URL);
110 
111         assertThat(actualComponents, hasComponents(expectedComponents));
112         assertThat(actualServices, hasComponents(expectedServices));
113     }
114 
115     abstract ComponentExpectations getProductSpecificExpectations();
116 
117     private List<AbstractExpectedComponent> getExpectedComponentsWithDefaultProfile() {
118         final ComponentExpectations productSpecificExpectations = getProductSpecificExpectations();
119 
120         return ImmutableList.<AbstractExpectedComponent>builder()
121                 // Common to all products
122                 .addAll(productSpecificExpectations.getExpectedScannerCreatedComponents()) // includes those exported
123                 .addAll(productSpecificExpectations.getExpectedScannerCreatedComponentImports())
124                 .addAll(productSpecificExpectations.getExpectedAutoAddedComponents())
125                 // Product-specific
126                 .addAll(productSpecificExpectations.getProductSpecificScannerCreatedComponents())
127                 .addAll(productSpecificExpectations.getProductSpecificScannerCreatedComponentImports())
128                 .addAll(productSpecificExpectations.getProductSpecificAutoAddedComponents())
129                 .build();
130     }
131 
132     private List<AbstractExpectedComponent> getExpectedServiceExportsWithDefaultProfile() {
133         // Our test plugin current has the same exports in all products
134         final ComponentExpectations expectations = ComponentExpectations.COMMON;
135 
136         final ImmutableList.Builder<AbstractExpectedComponent> builder =
137                 ImmutableList.<AbstractExpectedComponent>builder()
138                     .addAll(expectations.getExpectedScannerCreatedExports())
139                     .addAll(expectations.getExpectedAutoAddedExports());
140         // If we're running in dev mode (which is the AMPS default if this property isn't set), the dev exports should be present, else not
141         if (Boolean.parseBoolean(System.getProperty("atlassian.dev.mode", "true"))) {
142             builder.addAll(expectations.getExpectedScannerCreatedDevExports());
143         }
144         return builder.build();
145     }
146 
147     private static Matcher<Iterable<? extends String>> hasComponents(List<AbstractExpectedComponent> expectedComponents) {
148         Collection<Matcher<? super String>> componentMatchers =
149                 expectedComponents.stream()
150                         .map(AbstractExpectedComponent::getRuntimeComponentEntryMatcher)
151                         .collect(Collectors.toList());
152         return Matchers.containsInAnyOrder(componentMatchers);
153     }
154 }