|
8 | 8 | import static com.linkedin.venice.ConfigKeys.KAFKA_LINGER_MS; |
9 | 9 | import static com.linkedin.venice.ConfigKeys.SERVER_AA_WC_WORKLOAD_PARALLEL_PROCESSING_ENABLED; |
10 | 10 | import static com.linkedin.venice.ConfigKeys.ZOOKEEPER_ADDRESS; |
| 11 | +import static com.linkedin.venice.integration.utils.IntegrationTestUtils.pollChangeEventsFromSpecificChangeCaptureConsumer; |
11 | 12 | import static com.linkedin.venice.integration.utils.VeniceClusterWrapperConstants.DEFAULT_PARENT_DATA_CENTER_REGION_NAME; |
12 | 13 | import static com.linkedin.venice.integration.utils.VeniceControllerWrapper.D2_SERVICE_NAME; |
13 | 14 | import static com.linkedin.venice.stats.ClientType.CHANGE_DATA_CAPTURE_CLIENT; |
|
59 | 60 | import com.linkedin.venice.controllerapi.MultiStoreTopicsResponse; |
60 | 61 | import com.linkedin.venice.controllerapi.UpdateStoreQueryParams; |
61 | 62 | import com.linkedin.venice.endToEnd.TestChangelogValue; |
| 63 | +import com.linkedin.venice.exceptions.StoreDisabledException; |
62 | 64 | import com.linkedin.venice.integration.utils.IntegrationTestUtils; |
63 | 65 | import com.linkedin.venice.integration.utils.PubSubBrokerWrapper; |
64 | 66 | import com.linkedin.venice.integration.utils.ServiceFactory; |
@@ -188,6 +190,130 @@ public void cleanUp() { |
188 | 190 | TestView.resetCounters(); |
189 | 191 | } |
190 | 192 |
|
| 193 | + @Test(timeOut = TEST_TIMEOUT, priority = 3) |
| 194 | + public void testDisabledStoreVeniceChangelogConsumer() throws Exception { |
| 195 | + File inputDir = getTempDataDirectory(); |
| 196 | + Schema recordSchema = TestWriteUtils.writeSimpleAvroFileWithStringToNameRecordV1Schema(inputDir); |
| 197 | + String inputDirPath = "file://" + inputDir.getAbsolutePath(); |
| 198 | + String storeName = Utils.getUniqueString("store"); |
| 199 | + Properties props = TestWriteUtils.defaultVPJProps( |
| 200 | + parentControllers.get(0).getControllerUrl(), |
| 201 | + inputDirPath, |
| 202 | + storeName, |
| 203 | + clusterWrapper.getPubSubClientProperties()); |
| 204 | + String keySchemaStr = recordSchema.getField(DEFAULT_KEY_FIELD_PROP).schema().toString(); |
| 205 | + String valueSchemaStr = NAME_RECORD_V2_SCHEMA.toString(); |
| 206 | + UpdateStoreQueryParams storeParms = new UpdateStoreQueryParams().setActiveActiveReplicationEnabled(true) |
| 207 | + .setHybridRewindSeconds(500) |
| 208 | + .setHybridOffsetLagThreshold(8) |
| 209 | + .setChunkingEnabled(true) |
| 210 | + .setNativeReplicationEnabled(true) |
| 211 | + .setPartitionCount(3); |
| 212 | + MetricsRepository metricsRepository = |
| 213 | + getVeniceMetricsRepository(CHANGE_DATA_CAPTURE_CLIENT, CONSUMER_METRIC_ENTITIES, true); |
| 214 | + ControllerClient setupControllerClient = |
| 215 | + createStoreForJob(clusterName, keySchemaStr, valueSchemaStr, props, storeParms); |
| 216 | + TestUtils.assertCommand( |
| 217 | + setupControllerClient |
| 218 | + .retryableRequest(5, controllerClient1 -> setupControllerClient.updateStore(storeName, storeParms))); |
| 219 | + // Registering real data schema as schema v2. |
| 220 | + for (Schema schema: SCHEMA_HISTORY) { |
| 221 | + TestUtils.assertCommand( |
| 222 | + setupControllerClient.retryableRequest( |
| 223 | + 5, |
| 224 | + controllerClient1 -> setupControllerClient.addValueSchema(storeName, schema.toString())), |
| 225 | + "Failed to add schema: " + schema.toString() + " to store " + storeName); |
| 226 | + } |
| 227 | + |
| 228 | + IntegrationTestPushUtils.runVPJ(props); |
| 229 | + ZkServerWrapper localZkServer = multiRegionMultiClusterWrapper.getChildRegions().get(0).getZkServerWrapper(); |
| 230 | + PubSubBrokerWrapper localKafka = multiRegionMultiClusterWrapper.getChildRegions().get(0).getPubSubBrokerWrapper(); |
| 231 | + Properties consumerProperties = new Properties(); |
| 232 | + String localKafkaUrl = localKafka.getAddress(); |
| 233 | + consumerProperties.put(KAFKA_BOOTSTRAP_SERVERS, localKafkaUrl); |
| 234 | + consumerProperties.put(CLUSTER_NAME, clusterName); |
| 235 | + consumerProperties.put(ZOOKEEPER_ADDRESS, localZkServer.getAddress()); |
| 236 | + consumerProperties.putAll(multiRegionMultiClusterWrapper.getPubSubClientProperties()); |
| 237 | + ChangelogClientConfig globalChangelogClientConfig = |
| 238 | + new ChangelogClientConfig().setConsumerProperties(consumerProperties) |
| 239 | + .setControllerD2ServiceName(D2_SERVICE_NAME) |
| 240 | + .setD2ServiceName(VeniceRouterWrapper.CLUSTER_DISCOVERY_D2_SERVICE_NAME) |
| 241 | + .setD2Client(IntegrationTestPushUtils.getD2Client(localZkServer.getAddress())) |
| 242 | + .setLocalD2ZkHosts(localZkServer.getAddress()) |
| 243 | + .setControllerRequestRetryCount(3) |
| 244 | + .setVersionSwapDetectionIntervalTimeInSeconds(1L) |
| 245 | + .setSpecificValue(TestChangelogValue.class) |
| 246 | + .setBootstrapFileSystemPath(Utils.getUniqueString(inputDirPath)); |
| 247 | + VeniceChangelogConsumerClientFactory veniceChangelogConsumerClientFactory = |
| 248 | + new VeniceChangelogConsumerClientFactory(globalChangelogClientConfig, metricsRepository); |
| 249 | + VeniceChangelogConsumer<Utf8, TestChangelogValue> specificChangelogConsumer = |
| 250 | + veniceChangelogConsumerClientFactory.getChangelogConsumer(storeName, "0", TestChangelogValue.class); |
| 251 | + |
| 252 | + TestUtils.assertCommand( |
| 253 | + setupControllerClient.retryableRequest( |
| 254 | + 5, |
| 255 | + controllerClient1 -> setupControllerClient |
| 256 | + .updateStore(storeName, new UpdateStoreQueryParams().setEnableReads(false)))); |
| 257 | + |
| 258 | + // Wait for store update to propagate |
| 259 | + TestUtils.waitForNonDeterministicAssertion( |
| 260 | + globalChangelogClientConfig.getVersionSwapDetectionIntervalTimeInSeconds(), |
| 261 | + TimeUnit.SECONDS, |
| 262 | + () -> Assert.assertThrows(StoreDisabledException.class, () -> specificChangelogConsumer.subscribeAll().get())); |
| 263 | + |
| 264 | + TestUtils.assertCommand( |
| 265 | + setupControllerClient.retryableRequest( |
| 266 | + 5, |
| 267 | + controllerClient1 -> setupControllerClient |
| 268 | + .updateStore(storeName, new UpdateStoreQueryParams().setEnableReads(true)))); |
| 269 | + |
| 270 | + specificChangelogConsumer.subscribeAll().get(); |
| 271 | + |
| 272 | + Map<String, PubSubMessage<Utf8, ChangeEvent<TestChangelogValue>, VeniceChangeCoordinate>> polledChangeEventsMap = |
| 273 | + new HashMap<>(); |
| 274 | + List<PubSubMessage<Utf8, ChangeEvent<TestChangelogValue>, VeniceChangeCoordinate>> polledChangeEventsList = |
| 275 | + new ArrayList<>(); |
| 276 | + |
| 277 | + TestUtils.assertCommand( |
| 278 | + setupControllerClient.retryableRequest( |
| 279 | + 5, |
| 280 | + controllerClient1 -> setupControllerClient |
| 281 | + .updateStore(storeName, new UpdateStoreQueryParams().setEnableReads(false)))); |
| 282 | + |
| 283 | + // Wait for store update to propagate |
| 284 | + TestUtils.waitForNonDeterministicAssertion( |
| 285 | + globalChangelogClientConfig.getVersionSwapDetectionIntervalTimeInSeconds(), |
| 286 | + TimeUnit.SECONDS, |
| 287 | + () -> Assert.assertThrows( |
| 288 | + StoreDisabledException.class, |
| 289 | + () -> pollChangeEventsFromSpecificChangeCaptureConsumer( |
| 290 | + polledChangeEventsMap, |
| 291 | + polledChangeEventsList, |
| 292 | + specificChangelogConsumer))); |
| 293 | + |
| 294 | + TestUtils.assertCommand( |
| 295 | + setupControllerClient.retryableRequest( |
| 296 | + 5, |
| 297 | + controllerClient1 -> setupControllerClient |
| 298 | + .updateStore(storeName, new UpdateStoreQueryParams().setEnableReads(true)))); |
| 299 | + |
| 300 | + TestUtils.waitForNonDeterministicAssertion(120, TimeUnit.SECONDS, true, () -> { |
| 301 | + pollChangeEventsFromSpecificChangeCaptureConsumer( |
| 302 | + polledChangeEventsMap, |
| 303 | + polledChangeEventsList, |
| 304 | + specificChangelogConsumer); |
| 305 | + Assert.assertEquals(polledChangeEventsList.size(), 100); |
| 306 | + Assert.assertTrue(specificChangelogConsumer.isCaughtUp()); |
| 307 | + }); |
| 308 | + |
| 309 | + Assert.assertTrue( |
| 310 | + polledChangeEventsMap.get(Integer.toString(1)).getValue().getCurrentValue() instanceof SpecificRecord); |
| 311 | + TestChangelogValue value = new TestChangelogValue(); |
| 312 | + value.firstName = "first_name_1"; |
| 313 | + value.lastName = "last_name_1"; |
| 314 | + Assert.assertEquals(polledChangeEventsMap.get(Integer.toString(1)).getValue().getCurrentValue(), value); |
| 315 | + } |
| 316 | + |
191 | 317 | // This is a beefier test, so giving it a bit more time |
192 | 318 | @Test(timeOut = TEST_TIMEOUT * 3, priority = 3) |
193 | 319 | public void testVersionSwapInALoop() throws Exception { |
|
0 commit comments