/** * Copyright 2016 LinkedIn Corp. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ package com.github.ambry.server; import com.codahale.metrics.Meter; import com.codahale.metrics.MetricRegistry; import com.github.ambry.clustermap.MockClusterMap; import com.github.ambry.server.RouterServerTestFramework.*; import com.github.ambry.utils.SystemTime; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Queue; import java.util.Random; import org.junit.After; import org.junit.AfterClass; import org.junit.Assert; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import static com.github.ambry.server.RouterServerTestFramework.*; public class RouterServerPlaintextTest { private static MockCluster plaintextCluster; private static RouterServerTestFramework testFramework; private static MetricRegistry routerMetricRegistry; private static long plainTextSendBytesCountBeforeTest; private static long plainTextReceiveBytesCountBeforeTest; @BeforeClass public static void initializeTests() throws Exception { MockNotificationSystem notificationSystem = new MockNotificationSystem(9); plaintextCluster = new MockCluster(notificationSystem, false, SystemTime.getInstance()); plaintextCluster.startServers(); MockClusterMap routerClusterMap = plaintextCluster.getClusterMap(); // MockClusterMap returns a new registry by default. This is to ensure that each node (server, router and so on, // get a different registry. But at this point all server nodes have been initialized, and we want the router and // its components, which are going to be created, to use the same registry. routerClusterMap.createAndSetPermanentMetricRegistry(); testFramework = new RouterServerTestFramework(getRouterProperties("DC1"), routerClusterMap, notificationSystem); routerMetricRegistry = routerClusterMap.getMetricRegistry(); } @AfterClass public static void cleanup() throws IOException { testFramework.cleanup(); long start = System.currentTimeMillis(); System.out.println("About to invoke cluster.cleanup()"); if (plaintextCluster != null) { plaintextCluster.cleanup(); } System.out.println("cluster.cleanup() took " + (System.currentTimeMillis() - start) + " ms."); } @Before public void before() { Map<String, Meter> meters = routerMetricRegistry.getMeters(); plainTextSendBytesCountBeforeTest = meters.get(plaintextSendBytesMetricName).getCount(); plainTextReceiveBytesCountBeforeTest = meters.get(plaintextReceiveBytesMetricName).getCount(); } @After public void after() { Map<String, Meter> meters = routerMetricRegistry.getMeters(); Assert.assertTrue("Router should have sent over Plain Text", meters.get(plaintextSendBytesMetricName).getCount() != plainTextSendBytesCountBeforeTest); Assert.assertTrue("Router should have received over Plain Text", meters.get(plaintextReceiveBytesMetricName).getCount() != plainTextReceiveBytesCountBeforeTest); Assert.assertTrue("Router should not have sent over SSL", meters.get(sslSendBytesMetricName).getCount() == 0); Assert.assertTrue("Router should not have received over SSL", meters.get(sslReceiveBytesMetricName).getCount() == 0); } /** * Test that the non blocking router can handle a large number of concurrent (small blob) operations without errors. * This test creates chains of operations without waiting for previous operations to finish. * @throws Exception */ @Test public void interleavedOperationsTest() throws Exception { List<OperationChain> opChains = new ArrayList<>(); Random random = new Random(); for (int i = 0; i < 20; i++) { Queue<OperationType> operations = new LinkedList<>(); switch (i % 3) { case 0: operations.add(OperationType.PUT); operations.add(OperationType.AWAIT_CREATION); operations.add(OperationType.GET); operations.add(OperationType.GET_INFO); operations.add(OperationType.DELETE); operations.add(OperationType.AWAIT_DELETION); operations.add(OperationType.GET_DELETED); operations.add(OperationType.GET_INFO_DELETED); operations.add(OperationType.GET_DELETED_SUCCESS); operations.add(OperationType.GET_INFO_DELETED_SUCCESS); break; case 1: operations.add(OperationType.PUT); operations.add(OperationType.AWAIT_CREATION); operations.add(OperationType.DELETE); operations.add(OperationType.AWAIT_DELETION); operations.add(OperationType.GET_DELETED); operations.add(OperationType.GET_INFO_DELETED); operations.add(OperationType.GET_DELETED); operations.add(OperationType.GET_INFO_DELETED); operations.add(OperationType.GET_DELETED_SUCCESS); operations.add(OperationType.GET_INFO_DELETED_SUCCESS); break; case 2: operations.add(OperationType.PUT); operations.add(OperationType.AWAIT_CREATION); operations.add(OperationType.GET); operations.add(OperationType.GET); operations.add(OperationType.GET); operations.add(OperationType.GET_INFO); break; } int blobSize = random.nextInt(100 * 1024); opChains.add(testFramework.startOperationChain(blobSize, i, operations)); } testFramework.checkOperationChains(opChains); } /** * Test that the non-blocking router can handle simple operation chains where each chain is completed before * the next one runs. This means that operations on only one blob are being dealt with at a time. * @throws Exception */ @Test public void nonInterleavedOperationsTest() throws Exception { Random random = new Random(); for (int i = 0; i < 10; i++) { Queue<OperationType> operations = new LinkedList<>(); operations.add(OperationType.PUT); operations.add(OperationType.AWAIT_CREATION); operations.add(OperationType.GET_INFO); operations.add(OperationType.GET); operations.add(OperationType.DELETE); operations.add(OperationType.AWAIT_DELETION); operations.add(OperationType.GET_INFO_DELETED); operations.add(OperationType.GET_DELETED); operations.add(OperationType.GET_DELETED_SUCCESS); operations.add(OperationType.GET_INFO_DELETED_SUCCESS); int blobSize = random.nextInt(100 * 1024); testFramework.checkOperationChains( Collections.singletonList(testFramework.startOperationChain(blobSize, i, operations))); } } /** * Test that the non-blocking router can handle multi-chunk blobs. * @throws Exception */ @Test public void largeBlobTest() throws Exception { final int blobSize = RouterServerTestFramework.CHUNK_SIZE * 2 + 1; List<OperationChain> opChains = new ArrayList<>(); for (int i = 0; i < 2; i++) { Queue<OperationType> operations = new LinkedList<>(); operations.add(OperationType.PUT); operations.add(OperationType.AWAIT_CREATION); operations.add(OperationType.GET_INFO); operations.add(OperationType.GET); operations.add(OperationType.DELETE); operations.add(OperationType.AWAIT_DELETION); operations.add(OperationType.GET_INFO_DELETED); operations.add(OperationType.GET_DELETED); operations.add(OperationType.GET_DELETED_SUCCESS); operations.add(OperationType.GET_INFO_DELETED_SUCCESS); opChains.add(testFramework.startOperationChain(blobSize, i, operations)); } testFramework.checkOperationChains(opChains); } }