|
15 | 15 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ |
16 | 16 | package com.adobe.cq.forms.core.components.util; |
17 | 17 |
|
| 18 | +import java.lang.reflect.Field; |
18 | 19 | import java.util.HashMap; |
| 20 | +import java.util.List; |
19 | 21 | import java.util.Map; |
20 | 22 |
|
| 23 | +import org.apache.http.StatusLine; |
| 24 | +import org.apache.http.client.methods.CloseableHttpResponse; |
| 25 | +import org.apache.http.entity.StringEntity; |
| 26 | +import org.apache.http.impl.client.CloseableHttpClient; |
| 27 | +import org.apache.http.impl.client.HttpClientBuilder; |
| 28 | +import org.apache.http.osgi.services.HttpClientBuilderFactory; |
21 | 29 | import org.apache.jackrabbit.JcrConstants; |
22 | 30 | import org.apache.sling.api.resource.Resource; |
23 | 31 | import org.apache.sling.api.resource.ResourceResolver; |
|
29 | 37 | import com.adobe.cq.forms.core.components.internal.form.FormConstants; |
30 | 38 |
|
31 | 39 | import static org.junit.jupiter.api.Assertions.*; |
| 40 | +import static org.mockito.ArgumentMatchers.any; |
| 41 | +import static org.mockito.Mockito.mock; |
| 42 | +import static org.mockito.Mockito.times; |
| 43 | +import static org.mockito.Mockito.verify; |
| 44 | +import static org.mockito.Mockito.when; |
32 | 45 |
|
33 | 46 | public class ComponentUtilsTest { |
34 | 47 | @Test |
@@ -96,4 +109,68 @@ public void testParseNumber() { |
96 | 109 | assertNull(ComponentUtils.parseNumber(null)); |
97 | 110 | } |
98 | 111 |
|
| 112 | + @Test |
| 113 | + public void testSubmitActionsCaching() throws Exception { |
| 114 | + // Clear cache before test |
| 115 | + resetCache(); |
| 116 | + |
| 117 | + // Set up mocks |
| 118 | + HttpClientBuilderFactory mockClientFactory = mock(HttpClientBuilderFactory.class); |
| 119 | + HttpClientBuilder mockHttpClientBuilder = mock(HttpClientBuilder.class); |
| 120 | + CloseableHttpClient mockHttpClient = mock(CloseableHttpClient.class); |
| 121 | + CloseableHttpResponse mockResponse = mock(CloseableHttpResponse.class); |
| 122 | + StatusLine mockStatusLine = mock(StatusLine.class); |
| 123 | + |
| 124 | + // Configure mock response |
| 125 | + when(mockStatusLine.getStatusCode()).thenReturn(200); |
| 126 | + when(mockResponse.getStatusLine()).thenReturn(mockStatusLine); |
| 127 | + when(mockResponse.getEntity()).thenReturn( |
| 128 | + new StringEntity("{\"supported\":[\"spreadsheet\",\"email\"]}")); |
| 129 | + |
| 130 | + // Wire up mock chain |
| 131 | + when(mockClientFactory.newBuilder()).thenReturn(mockHttpClientBuilder); |
| 132 | + when(mockHttpClientBuilder.build()).thenReturn(mockHttpClient); |
| 133 | + when(mockHttpClient.execute(any())).thenReturn(mockResponse); |
| 134 | + |
| 135 | + // First call should execute HTTP request |
| 136 | + List<String> actions1 = ComponentUtils.getSupportedSubmitActions(mockClientFactory); |
| 137 | + |
| 138 | + // Second call should use cached result |
| 139 | + List<String> actions2 = ComponentUtils.getSupportedSubmitActions(mockClientFactory); |
| 140 | + |
| 141 | + // Verify HTTP call only happened once |
| 142 | + verify(mockHttpClient, times(1)).execute(any()); |
| 143 | + |
| 144 | + // Verify returned actions are the same |
| 145 | + assertEquals(actions1, actions2); |
| 146 | + assertEquals(2, actions1.size()); |
| 147 | + assertTrue(actions1.contains("spreadsheet")); |
| 148 | + assertTrue(actions1.contains("email")); |
| 149 | + |
| 150 | + // Simulate TTL expiry and verify HTTP call happens again |
| 151 | + setCacheTimestampToExpired(); |
| 152 | + List<String> actions3 = ComponentUtils.getSupportedSubmitActions(mockClientFactory); |
| 153 | + verify(mockHttpClient, times(2)).execute(any()); |
| 154 | + } |
| 155 | + |
| 156 | + // Helper methods to access private cache fields via reflection |
| 157 | + private void resetCache() throws Exception { |
| 158 | + Field cacheField = CacheManager.class.getDeclaredField("SUBMIT_ACTIONS_CACHE"); |
| 159 | + cacheField.setAccessible(true); |
| 160 | + ((Map) cacheField.get(null)).clear(); |
| 161 | + |
| 162 | + Field timestampsField = CacheManager.class.getDeclaredField("CACHE_TIMESTAMPS"); |
| 163 | + timestampsField.setAccessible(true); |
| 164 | + ((Map) timestampsField.get(null)).clear(); |
| 165 | + } |
| 166 | + |
| 167 | + private void setCacheTimestampToExpired() throws Exception { |
| 168 | + Field timestampsField = CacheManager.class.getDeclaredField("CACHE_TIMESTAMPS"); |
| 169 | + timestampsField.setAccessible(true); |
| 170 | + Map<String, Long> timestamps = (Map<String, Long>) timestampsField.get(null); |
| 171 | + |
| 172 | + // Set timestamp to 25 hours ago (beyond TTL of 24 hours) |
| 173 | + timestamps.put(CacheManager.SUPPORTED_SUBMIT_ACTIONS_CACHE_KEY, |
| 174 | + System.currentTimeMillis() - 25 * 60 * 60 * 1000); |
| 175 | + } |
99 | 176 | } |
0 commit comments