/*
* The Alluxio Open Foundation licenses this work under the Apache License, version 2.0
* (the "License"). You may not use this work except in compliance with the License, which is
* available at www.apache.org/licenses/LICENSE-2.0
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied, as more fully set forth in the License.
*
* See the NOTICE file distributed with this work for information regarding copyright ownership.
*/
package alluxio.master;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import alluxio.Configuration;
import alluxio.ConfigurationTestUtils;
import alluxio.PropertyKey;
import alluxio.RuntimeConstants;
import alluxio.master.block.BlockMaster;
import alluxio.master.block.BlockMasterFactory;
import alluxio.master.file.DefaultFileSystemMaster;
import alluxio.master.journal.Journal;
import alluxio.master.journal.JournalFactory;
import alluxio.metrics.MetricsSystem;
import alluxio.underfs.UnderFileSystem;
import alluxio.underfs.UnderFileSystemConfiguration;
import alluxio.underfs.UnderFileSystemFactory;
import alluxio.underfs.UnderFileSystemFactoryRegistry;
import alluxio.web.MasterWebServer;
import alluxio.wire.WorkerInfo;
import alluxio.wire.WorkerNetAddress;
import com.codahale.metrics.Gauge;
import com.codahale.metrics.Metric;
import com.codahale.metrics.MetricSet;
import com.google.common.collect.ImmutableMap;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.mockito.Matchers;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.URI;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import javax.servlet.ServletContext;
import javax.ws.rs.core.Response;
/**
* Unit tests for {@link AlluxioMasterRestServiceHandler}.
*/
public final class AlluxioMasterRestServiceHandlerTest {
private static final WorkerNetAddress NET_ADDRESS_1 = new WorkerNetAddress().setHost("localhost")
.setRpcPort(80).setDataPort(81).setWebPort(82);
private static final WorkerNetAddress NET_ADDRESS_2 = new WorkerNetAddress().setHost("localhost")
.setRpcPort(83).setDataPort(84).setWebPort(85);
private static final Map<String, List<Long>> NO_BLOCKS_ON_TIERS = ImmutableMap.of();
private static final long UFS_SPACE_TOTAL = 100L;
private static final long UFS_SPACE_USED = 100L;
private static final long UFS_SPACE_FREE = 100L;
private static final String TEST_PATH = "test://test";
private static final Map<String, Long> WORKER1_TOTAL_BYTES_ON_TIERS = ImmutableMap.of("MEM", 10L,
"SSD", 20L);
private static final Map<String, Long> WORKER2_TOTAL_BYTES_ON_TIERS = ImmutableMap.of("MEM",
1000L, "SSD", 2000L);
private static final Map<String, Long> WORKER1_USED_BYTES_ON_TIERS = ImmutableMap.of("MEM", 1L,
"SSD", 2L);
private static final Map<String, Long> WORKER2_USED_BYTES_ON_TIERS = ImmutableMap.of("MEM", 100L,
"SSD", 200L);
private MasterProcess mMasterProcess;
private BlockMaster mBlockMaster;
private MasterRegistry mRegistry;
private AlluxioMasterRestServiceHandler mHandler;
@Rule
public TemporaryFolder mTestFolder = new TemporaryFolder();
@BeforeClass
public static void beforeClass() throws Exception {
String filesPinnedProperty =
MetricsSystem.getMasterMetricName(DefaultFileSystemMaster.Metrics.FILES_PINNED);
MetricsSystem.METRIC_REGISTRY.remove(filesPinnedProperty);
}
@Before
public void before() throws Exception {
mMasterProcess = mock(MasterProcess.class);
ServletContext context = mock(ServletContext.class);
mRegistry = new MasterRegistry();
JournalFactory factory =
new Journal.Factory(new URI(mTestFolder.newFolder().getAbsolutePath()));
mBlockMaster = new BlockMasterFactory().create(mRegistry, factory);
mRegistry.start(true);
when(mMasterProcess.getMaster(BlockMaster.class)).thenReturn(mBlockMaster);
when(context.getAttribute(MasterWebServer.ALLUXIO_MASTER_SERVLET_RESOURCE_KEY)).thenReturn(
mMasterProcess);
registerFileSystemMock();
mHandler = new AlluxioMasterRestServiceHandler(context);
// Register two workers
long worker1 = mBlockMaster.getWorkerId(NET_ADDRESS_1);
long worker2 = mBlockMaster.getWorkerId(NET_ADDRESS_2);
List<String> tiers = Arrays.asList("MEM", "SSD");
mBlockMaster.workerRegister(worker1, tiers, WORKER1_TOTAL_BYTES_ON_TIERS,
WORKER1_USED_BYTES_ON_TIERS, NO_BLOCKS_ON_TIERS);
mBlockMaster.workerRegister(worker2, tiers, WORKER2_TOTAL_BYTES_ON_TIERS,
WORKER2_USED_BYTES_ON_TIERS, NO_BLOCKS_ON_TIERS);
}
private void registerFileSystemMock() throws IOException {
Configuration.set(PropertyKey.MASTER_MOUNT_TABLE_ROOT_UFS, TEST_PATH);
UnderFileSystemFactory underFileSystemFactoryMock = mock(UnderFileSystemFactory.class);
when(underFileSystemFactoryMock.supportsPath(anyString())).thenReturn(Boolean.FALSE);
when(underFileSystemFactoryMock.supportsPath(TEST_PATH)).thenReturn(Boolean.TRUE);
UnderFileSystem underFileSystemMock = mock(UnderFileSystem.class);
when(underFileSystemMock.getSpace(TEST_PATH, UnderFileSystem.SpaceType.SPACE_FREE)).thenReturn(
UFS_SPACE_FREE);
when(underFileSystemMock.getSpace(TEST_PATH, UnderFileSystem.SpaceType.SPACE_TOTAL))
.thenReturn(UFS_SPACE_TOTAL);
when(underFileSystemMock.getSpace(TEST_PATH, UnderFileSystem.SpaceType.SPACE_USED)).thenReturn(
UFS_SPACE_USED);
when(underFileSystemFactoryMock.create(eq(TEST_PATH),
Matchers.<UnderFileSystemConfiguration>any())).thenReturn(underFileSystemMock);
UnderFileSystemFactoryRegistry.register(underFileSystemFactoryMock);
}
@After
public void after() throws Exception {
mRegistry.stop();
ConfigurationTestUtils.resetConfiguration();
}
@Test
public void getConfiguration() {
Response response = mHandler.getConfiguration();
try {
assertNotNull("Response must be not null!", response);
assertNotNull("Response must have a entry!", response.getEntity());
assertTrue("Entry must be a SortedMap!", (response.getEntity() instanceof SortedMap));
SortedMap<String, String> entry = (SortedMap<String, String>) response.getEntity();
assertFalse("Properties Map must be not empty!", (entry.isEmpty()));
} finally {
response.close();
}
}
@Test
public void getRpcAddress() {
when(mMasterProcess.getRpcAddress()).thenReturn(new InetSocketAddress("localhost", 8080));
Response response = mHandler.getRpcAddress();
try {
assertNotNull("Response must be not null!", response);
assertNotNull("Response must have a entry!", response.getEntity());
assertEquals("Entry must be a String!", String.class, response.getEntity().getClass());
String entry = (String) response.getEntity();
assertEquals("\"localhost/127.0.0.1:8080\"", entry);
} finally {
response.close();
}
}
@Test
public void getMetrics() {
final int FILES_PINNED_TEST_VALUE = 100;
String filesPinnedProperty =
MetricsSystem.getMasterMetricName(DefaultFileSystemMaster.Metrics.FILES_PINNED);
Gauge<Integer> filesPinnedGauge = new Gauge<Integer>() {
@Override
public Integer getValue() {
return FILES_PINNED_TEST_VALUE;
}
};
MetricSet mockMetricsSet = mock(MetricSet.class);
Map<String, Metric> map = new HashMap<>();
map.put(filesPinnedProperty, filesPinnedGauge);
when(mockMetricsSet.getMetrics()).thenReturn(map);
MetricsSystem.METRIC_REGISTRY.registerAll(mockMetricsSet);
Response response = mHandler.getMetrics();
try {
assertNotNull("Response must be not null!", response);
assertNotNull("Response must have a entry!", response.getEntity());
assertTrue("Entry must be a SortedMap!", (response.getEntity() instanceof SortedMap));
SortedMap<String, Long> metricsMap = (SortedMap<String, Long>) response.getEntity();
assertFalse("Metrics Map must be not empty!", (metricsMap.isEmpty()));
assertTrue("Map must contain key " + filesPinnedProperty + "!",
metricsMap.containsKey(filesPinnedProperty));
assertEquals(FILES_PINNED_TEST_VALUE, metricsMap.get(filesPinnedProperty).longValue());
} finally {
response.close();
}
}
@Test
public void getStartTimeMs() {
when(mMasterProcess.getStartTimeMs()).thenReturn(100L);
Response response = mHandler.getStartTimeMs();
try {
assertNotNull("Response must be not null!", response);
assertNotNull("Response must have a entry!", response.getEntity());
assertEquals("Entry must be a Long!", Long.class, response.getEntity().getClass());
Long entry = (Long) response.getEntity();
assertEquals(100L, entry.longValue());
} finally {
response.close();
}
}
@Test
public void getUptimeMs() {
when(mMasterProcess.getUptimeMs()).thenReturn(100L);
Response response = mHandler.getUptimeMs();
try {
assertNotNull("Response must be not null!", response);
assertNotNull("Response must have a entry!", response.getEntity());
assertEquals("Entry must be a Long!", Long.class, response.getEntity().getClass());
Long entry = (Long) response.getEntity();
assertEquals(100L, entry.longValue());
} finally {
response.close();
}
}
@Test
public void getVersion() {
Response response = mHandler.getVersion();
try {
assertNotNull("Response must be not null!", response);
assertNotNull("Response must have a entry!", response.getEntity());
assertEquals("Entry must be a String!", String.class, response.getEntity().getClass());
String entry = (String) response.getEntity();
assertEquals("\"" + RuntimeConstants.VERSION + "\"", entry);
} finally {
response.close();
}
}
@Test
public void getCapacityBytes() {
Response response = mHandler.getCapacityBytes();
try {
assertNotNull("Response must be not null!", response);
assertNotNull("Response must have a entry!", response.getEntity());
assertEquals("Entry must be a Long!", Long.class, response.getEntity().getClass());
Long entry = (Long) response.getEntity();
long sum = 0;
for (Map.Entry<String, Long> entry1 : WORKER1_TOTAL_BYTES_ON_TIERS.entrySet()) {
Long totalBytes = entry1.getValue();
sum = sum + totalBytes;
}
for (Map.Entry<String, Long> entry1 : WORKER2_TOTAL_BYTES_ON_TIERS.entrySet()) {
Long totalBytes = entry1.getValue();
sum = sum + totalBytes;
}
assertEquals(sum, entry.longValue());
} finally {
response.close();
}
}
@Test
public void getUsedBytes() {
Response response = mHandler.getUsedBytes();
try {
assertNotNull("Response must be not null!", response);
assertNotNull("Response must have a entry!", response.getEntity());
assertEquals("Entry must be a Long!", Long.class, response.getEntity().getClass());
Long entry = (Long) response.getEntity();
long sum = 0;
for (Map.Entry<String, Long> entry1 : WORKER1_USED_BYTES_ON_TIERS.entrySet()) {
Long totalBytes = entry1.getValue();
sum = sum + totalBytes;
}
for (Map.Entry<String, Long> entry1 : WORKER2_USED_BYTES_ON_TIERS.entrySet()) {
Long totalBytes = entry1.getValue();
sum = sum + totalBytes;
}
assertEquals(sum, entry.longValue());
} finally {
response.close();
}
}
@Test
public void getFreeBytes() {
Response response = mHandler.getFreeBytes();
try {
assertNotNull("Response must be not null!", response);
assertNotNull("Response must have a entry!", response.getEntity());
assertEquals("Entry must be a Long!", Long.class, response.getEntity().getClass());
Long entry = (Long) response.getEntity();
long usedSum = 0;
for (Map.Entry<String, Long> entry1 : WORKER1_USED_BYTES_ON_TIERS.entrySet()) {
Long totalBytes = entry1.getValue();
usedSum = usedSum + totalBytes;
}
for (Map.Entry<String, Long> entry1 : WORKER2_USED_BYTES_ON_TIERS.entrySet()) {
Long totalBytes = entry1.getValue();
usedSum = usedSum + totalBytes;
}
long totalSum = 0;
for (Map.Entry<String, Long> entry1 : WORKER1_TOTAL_BYTES_ON_TIERS.entrySet()) {
Long totalBytes = entry1.getValue();
totalSum = totalSum + totalBytes;
}
for (Map.Entry<String, Long> entry1 : WORKER2_TOTAL_BYTES_ON_TIERS.entrySet()) {
Long totalBytes = entry1.getValue();
totalSum = totalSum + totalBytes;
}
assertEquals(totalSum - usedSum, entry.longValue());
} finally {
response.close();
}
}
@Test
public void getUfsCapacityBytes() {
Response response = mHandler.getUfsCapacityBytes();
try {
assertNotNull("Response must be not null!", response);
assertNotNull("Response must have a entry!", response.getEntity());
assertEquals("Entry must be a Long!", Long.class, response.getEntity().getClass());
Long entry = (Long) response.getEntity();
assertEquals(UFS_SPACE_TOTAL, entry.longValue());
} finally {
response.close();
}
}
@Test
public void getUfsUsedBytes() {
Response response = mHandler.getUfsUsedBytes();
try {
assertNotNull("Response must be not null!", response);
assertNotNull("Response must have a entry!", response.getEntity());
assertEquals("Entry must be a Long!", Long.class, response.getEntity().getClass());
Long entry = (Long) response.getEntity();
assertEquals(UFS_SPACE_USED, entry.longValue());
} finally {
response.close();
}
}
@Test
public void getUfsFreeBytes() {
Response response = mHandler.getUfsFreeBytes();
try {
assertNotNull("Response must be not null!", response);
assertNotNull("Response must have a entry!", response.getEntity());
assertEquals("Entry must be a Long!", Long.class, response.getEntity().getClass());
Long entry = (Long) response.getEntity();
assertEquals(UFS_SPACE_FREE, entry.longValue());
} finally {
response.close();
}
}
@Test
public void getWorkerCount() {
Response response = mHandler.getWorkerCount();
try {
assertNotNull("Response must be not null!", response);
assertNotNull("Response must have a entry!", response.getEntity());
assertEquals("Entry must be a Integer!", Integer.class, response.getEntity().getClass());
Integer entry = (Integer) response.getEntity();
assertEquals(Integer.valueOf(2), entry);
} finally {
response.close();
}
}
@Test
public void getWorkerInfoList() {
long worker1 = mBlockMaster.getWorkerId(NET_ADDRESS_1);
long worker2 = mBlockMaster.getWorkerId(NET_ADDRESS_2);
Set<Long> expected = new HashSet<>();
expected.add(worker1);
expected.add(worker2);
Response response = mHandler.getWorkerInfoList();
try {
assertNotNull("Response must be not null!", response);
assertNotNull("Response must have a entry!", response.getEntity());
assertTrue("Entry must be a List!", (response.getEntity() instanceof List));
@SuppressWarnings("unchecked")
List<WorkerInfo> entry = (List<WorkerInfo>) response.getEntity();
Set<Long> actual = new HashSet<>();
for (WorkerInfo info : entry) {
actual.add(info.getId());
}
assertEquals(expected, actual);
} finally {
response.close();
}
}
}