// Copyright 2016 Twitter. 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.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.twitter.heron.statefulstorage.hdfs;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import com.twitter.heron.proto.ckptmgr.CheckpointManager;
import com.twitter.heron.proto.system.PhysicalPlans;
import com.twitter.heron.spi.statefulstorage.Checkpoint;
import com.twitter.heron.statefulstorage.StatefulStorageTestContext;
import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@RunWith(PowerMockRunner.class)
@PrepareForTest({FileSystem.class, CheckpointManager.InstanceStateCheckpoint.class})
public class HDFSStorageTest {
private PhysicalPlans.Instance instance;
private CheckpointManager.InstanceStateCheckpoint instanceCheckpointState;
private HDFSStorage hdfsStorage;
private FileSystem mockFileSystem;
@Before
public void before() throws Exception {
Map<String, Object> config = new HashMap<>();
config.put(StatefulStorageTestContext.ROOT_PATH_KEY, StatefulStorageTestContext.ROOT_PATH);
mockFileSystem = mock(FileSystem.class);
when(mockFileSystem.getUri()).thenReturn(new URI("hdfs://hdfs_home_path/ckpgmgr"));
when(mockFileSystem.getHomeDirectory()).thenReturn(new Path("hdfs_home_path"));
PowerMockito.spy(FileSystem.class);
PowerMockito.doReturn(mockFileSystem).when(FileSystem.class, "get", any(Configuration.class));
hdfsStorage = spy(HDFSStorage.class);
hdfsStorage.init(config);
instance = StatefulStorageTestContext.getInstance();
instanceCheckpointState = StatefulStorageTestContext.getInstanceStateCheckpoint();
}
@After
public void after() throws Exception {
hdfsStorage.close();
}
@Test
public void testStore() throws Exception {
PowerMockito.mockStatic(CheckpointManager.InstanceStateCheckpoint.class);
CheckpointManager.InstanceStateCheckpoint mockCheckpointState =
mock(CheckpointManager.InstanceStateCheckpoint.class);
Checkpoint checkpoint =
new Checkpoint(StatefulStorageTestContext.TOPOLOGY_NAME, instance, mockCheckpointState);
FSDataOutputStream mockFSDateOutputStream = mock(FSDataOutputStream.class);
when(mockFileSystem.create(any(Path.class))).thenReturn(mockFSDateOutputStream);
doNothing().when(hdfsStorage).createDir(anyString());
hdfsStorage.store(checkpoint);
verify(mockCheckpointState).writeTo(mockFSDateOutputStream);
}
@Test
public void testRestore() throws Exception {
Checkpoint restoreCheckpoint =
new Checkpoint(StatefulStorageTestContext.TOPOLOGY_NAME, instance, instanceCheckpointState);
FSDataInputStream mockFSDataInputStream = mock(FSDataInputStream.class);
when(mockFileSystem.open(any(Path.class))).thenReturn(mockFSDataInputStream);
PowerMockito.spy(CheckpointManager.InstanceStateCheckpoint.class);
PowerMockito.doReturn(instanceCheckpointState)
.when(CheckpointManager.InstanceStateCheckpoint.class, "parseFrom", mockFSDataInputStream);
hdfsStorage.restore(StatefulStorageTestContext.TOPOLOGY_NAME,
StatefulStorageTestContext.CHECKPOINT_ID, instance);
assertEquals(restoreCheckpoint.getCheckpoint(), instanceCheckpointState);
}
@Test
public void testDisposeAll() throws Exception {
hdfsStorage.dispose(StatefulStorageTestContext.TOPOLOGY_NAME,
StatefulStorageTestContext.CHECKPOINT_ID, true);
verify(mockFileSystem).delete(any(Path.class), eq(true));
}
@Test
public void testDisposePartial() throws Exception {
Path mockPath = mock(Path.class);
when(mockPath.getName()).thenReturn("0");
FileStatus mockFS1 = mock(FileStatus.class);
when(mockFS1.getPath()).thenReturn(mockPath);
FileStatus mockFS2 = mock(FileStatus.class);
when(mockFS2.getPath()).thenReturn(mockPath);
FileStatus[] mockFileStatus = {mockFS1, mockFS2};
FileStatus[] emptyFileStatus = new FileStatus[0];
when(mockFileSystem.listStatus(any(Path.class)))
.thenReturn(mockFileStatus)
.thenReturn(emptyFileStatus);
hdfsStorage.dispose(StatefulStorageTestContext.TOPOLOGY_NAME,
StatefulStorageTestContext.CHECKPOINT_ID, false);
verify(mockFileSystem, times(2)).delete(any(Path.class), eq(true));
}
}