|
41 | 41 | import java.io.IOException;
|
42 | 42 | import java.io.InputStream;
|
43 | 43 | import java.io.InputStreamReader;
|
| 44 | +import java.io.StringReader; |
44 | 45 | import java.lang.reflect.Array;
|
45 | 46 | import java.lang.reflect.Field;
|
46 | 47 | import java.nio.charset.StandardCharsets;
|
|
67 | 68 | import org.apache.bookkeeper.mledger.ManagedLedgerException;
|
68 | 69 | import org.apache.bookkeeper.mledger.impl.ManagedLedgerFactoryImpl;
|
69 | 70 | import org.apache.bookkeeper.mledger.impl.ManagedLedgerImpl;
|
| 71 | +import org.apache.commons.lang3.StringUtils; |
70 | 72 | import org.apache.http.HttpResponse;
|
71 | 73 | import org.apache.http.client.HttpClient;
|
72 | 74 | import org.apache.http.client.methods.HttpGet;
|
|
102 | 104 | import org.apache.pulsar.common.protocol.Commands;
|
103 | 105 | import org.apache.pulsar.common.util.netty.EventLoopUtil;
|
104 | 106 | import org.awaitility.Awaitility;
|
| 107 | +import org.apache.zookeeper.KeeperException; |
| 108 | +import org.apache.zookeeper.MockZooKeeper; |
| 109 | +import org.glassfish.jersey.client.JerseyClient; |
| 110 | +import org.glassfish.jersey.client.JerseyClientBuilder; |
105 | 111 | import org.testng.Assert;
|
106 | 112 | import org.testng.annotations.AfterClass;
|
107 | 113 | import org.testng.annotations.BeforeClass;
|
@@ -1461,4 +1467,117 @@ public void testDuplicateAcknowledgement() throws Exception {
|
1461 | 1467 | assertEquals(admin.topics().getStats(topicName).getSubscriptions()
|
1462 | 1468 | .get("sub-1").getUnackedMessages(), 0);
|
1463 | 1469 | }
|
| 1470 | + |
| 1471 | + @Test |
| 1472 | + public void testMetricsPersistentTopicLoadFails() throws Exception { |
| 1473 | + final String namespace = "prop/" + UUID.randomUUID().toString().replaceAll("-", ""); |
| 1474 | + String topic = "persistent://" + namespace + "/topic1_" + UUID.randomUUID(); |
| 1475 | + admin.namespaces().createNamespace(namespace); |
| 1476 | + admin.topics().createNonPartitionedTopic(topic); |
| 1477 | + admin.topics().unload(topic); |
| 1478 | + |
| 1479 | + // Inject an error that makes the topic load fails. |
| 1480 | + AtomicBoolean failMarker = new AtomicBoolean(true); |
| 1481 | + mockZooKeeper.failConditional(KeeperException.Code.NODEEXISTS, (op, path) -> { |
| 1482 | + if (failMarker.get() && op.equals(MockZooKeeper.Op.SET) && |
| 1483 | + path.endsWith(TopicName.get(topic).getPersistenceNamingEncoding())) { |
| 1484 | + return true; |
| 1485 | + } |
| 1486 | + return false; |
| 1487 | + }); |
| 1488 | + |
| 1489 | + // Do test |
| 1490 | + Thread.sleep(1000 * 3); |
| 1491 | + CompletableFuture<Producer<byte[]>> producer = pulsarClient.newProducer().topic(topic).createAsync(); |
| 1492 | + JerseyClient httpClient = JerseyClientBuilder.createClient(); |
| 1493 | + Awaitility.await().until(() -> { |
| 1494 | + String response = httpClient.target(pulsar.getWebServiceAddress()).path("/metrics/") |
| 1495 | + .request().get(String.class); |
| 1496 | + BufferedReader reader = new BufferedReader(new StringReader(response)); |
| 1497 | + String line; |
| 1498 | + String metricsLine = null; |
| 1499 | + while ((line = reader.readLine()) != null) { |
| 1500 | + if (StringUtils.isBlank(line)) { |
| 1501 | + continue; |
| 1502 | + } |
| 1503 | + if (line.startsWith("#")) { |
| 1504 | + continue; |
| 1505 | + } |
| 1506 | + if (line.contains("topic_load_failed")) { |
| 1507 | + metricsLine = line; |
| 1508 | + break; |
| 1509 | + } |
| 1510 | + } |
| 1511 | + log.info("topic_load_failed: {}", metricsLine); |
| 1512 | + if (metricsLine == null) { |
| 1513 | + return false; |
| 1514 | + } |
| 1515 | + reader.close(); |
| 1516 | + String[] parts = metricsLine.split(" "); |
| 1517 | + Double value = Double.valueOf(parts[parts.length - 1]); |
| 1518 | + return value >= 1D; |
| 1519 | + }); |
| 1520 | + |
| 1521 | + // Remove the injection. |
| 1522 | + failMarker.set(false); |
| 1523 | + // cleanup. |
| 1524 | + httpClient.close(); |
| 1525 | + producer.join().close(); |
| 1526 | + admin.topics().delete(topic); |
| 1527 | + admin.namespaces().deleteNamespace(namespace); |
| 1528 | + } |
| 1529 | + |
| 1530 | + @Test |
| 1531 | + public void testMetricsNonPersistentTopicLoadFails() throws Exception { |
| 1532 | + final String namespace = "prop/" + UUID.randomUUID().toString().replaceAll("-", ""); |
| 1533 | + String topic = "non-persistent://" + namespace + "/topic1_" + UUID.randomUUID(); |
| 1534 | + admin.namespaces().createNamespace(namespace); |
| 1535 | + |
| 1536 | + // Inject an error that makes the topic load fails. |
| 1537 | + pulsar.getConfiguration().setEnableNonPersistentTopics(false); |
| 1538 | + |
| 1539 | + // Do test. |
| 1540 | + CompletableFuture<Producer<byte[]>> producer = pulsarClient.newProducer().topic(topic).createAsync(); |
| 1541 | + JerseyClient httpClient = JerseyClientBuilder.createClient(); |
| 1542 | + Awaitility.await().until(() -> { |
| 1543 | + String response = httpClient.target(pulsar.getWebServiceAddress()).path("/metrics/") |
| 1544 | + .request().get(String.class); |
| 1545 | + BufferedReader reader = new BufferedReader(new StringReader(response)); |
| 1546 | + String line; |
| 1547 | + String metricsLine = null; |
| 1548 | + while ((line = reader.readLine()) != null) { |
| 1549 | + if (StringUtils.isBlank(line)) { |
| 1550 | + continue; |
| 1551 | + } |
| 1552 | + if (line.startsWith("#")) { |
| 1553 | + continue; |
| 1554 | + } |
| 1555 | + if (line.contains("topic_load_failed")) { |
| 1556 | + metricsLine = line; |
| 1557 | + break; |
| 1558 | + } |
| 1559 | + } |
| 1560 | + log.info("topic_load_failed: {}", metricsLine); |
| 1561 | + if (metricsLine == null) { |
| 1562 | + return false; |
| 1563 | + } |
| 1564 | + reader.close(); |
| 1565 | + String[] parts = metricsLine.split(" "); |
| 1566 | + Double value = Double.valueOf(parts[parts.length - 1]); |
| 1567 | + return value >= 1D; |
| 1568 | + }); |
| 1569 | + |
| 1570 | + // Remove the injection. |
| 1571 | + pulsar.getConfiguration().setEnableNonPersistentTopics(true); |
| 1572 | + |
| 1573 | + // cleanup. |
| 1574 | + httpClient.close(); |
| 1575 | + try { |
| 1576 | + producer.join().close(); |
| 1577 | + } catch (Exception ex) { |
| 1578 | + // The producer creation failed, so skip to close it. |
| 1579 | + } |
| 1580 | + admin.topics().delete(topic); |
| 1581 | + admin.namespaces().deleteNamespace(namespace); |
| 1582 | + } |
1464 | 1583 | }
|
0 commit comments