/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.falcon.hive;
import org.apache.falcon.cluster.util.EmbeddedCluster;
import org.apache.falcon.hadoop.JailedFileSystem;
import org.apache.falcon.hive.exception.HiveReplicationException;
import org.apache.falcon.hive.util.DRStatusStore;
import org.apache.falcon.hive.util.HiveDRStatusStore;
import org.apache.falcon.hive.util.ReplicationStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.LocalFileSystem;
import org.apache.hadoop.fs.LocatedFileStatus;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.fs.RemoteIterator;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
/**
* Unit tests for HiveDRStatusStore.
*/
@Test
public class HiveDRStatusStoreTest {
private HiveDRStatusStore drStatusStore;
private FileSystem fileSystem = new JailedFileSystem();
public HiveDRStatusStoreTest() throws Exception {
EmbeddedCluster cluster = EmbeddedCluster.newCluster("hiveReplTest");
Path storePath = new Path(DRStatusStore.BASE_DEFAULT_STORE_PATH);
fileSystem.initialize(LocalFileSystem.getDefaultUri(cluster.getConf()), cluster.getConf());
if (fileSystem.exists(storePath)) {
fileSystem.delete(storePath, true);
}
FileSystem.mkdirs(fileSystem, storePath, DRStatusStore.DEFAULT_STORE_PERMISSION);
drStatusStore = new HiveDRStatusStore(fileSystem, fileSystem.getFileStatus(storePath).getGroup());
}
@BeforeClass
public void updateReplicationStatusTest() throws Exception {
ReplicationStatus dbStatus = new ReplicationStatus("source", "target", "jobname",
"Default1", null, ReplicationStatus.Status.SUCCESS, 20L);
ReplicationStatus table1 = new ReplicationStatus("source", "target", "jobname",
"Default1", "table1", ReplicationStatus.Status.SUCCESS, 20L);
ReplicationStatus table2 = new ReplicationStatus("source", "target", "jobname",
"default1", "Table2", ReplicationStatus.Status.INIT, -1L);
ReplicationStatus table3 = new ReplicationStatus("source", "target", "jobname",
"Default1", "Table3", ReplicationStatus.Status.FAILURE, 15L);
ReplicationStatus table4 = new ReplicationStatus("source", "target", "jobname",
"default1", "table4", ReplicationStatus.Status.FAILURE, 18L);
ArrayList<ReplicationStatus> replicationStatusList = new ArrayList<ReplicationStatus>();
replicationStatusList.add(table1);
replicationStatusList.add(table2);
replicationStatusList.add(table3);
replicationStatusList.add(table4);
replicationStatusList.add(dbStatus);
drStatusStore.updateReplicationStatus("jobname", replicationStatusList);
}
@Test(expectedExceptions = IOException.class,
expectedExceptionsMessageRegExp = ".*does not have correct ownership/permissions.*")
public void testDrStatusStoreWithFakeUser() throws IOException {
new HiveDRStatusStore(fileSystem, "fakeGroup");
}
public void updateReplicationStatusNewTablesTest() throws Exception {
ReplicationStatus dbStatus = new ReplicationStatus("source", "target", "jobname2",
"default2", null, ReplicationStatus.Status.SUCCESS, 20L);
ReplicationStatus table1 = new ReplicationStatus("source", "target", "jobname2",
"Default2", "table1", ReplicationStatus.Status.SUCCESS, 20L);
ReplicationStatus table2 = new ReplicationStatus("source", "target", "jobname2",
"default2", "Table2", ReplicationStatus.Status.INIT, -1L);
ReplicationStatus table3 = new ReplicationStatus("source", "target", "jobname2",
"default2", "table3", ReplicationStatus.Status.FAILURE, 15L);
ReplicationStatus table4 = new ReplicationStatus("source", "target", "jobname2",
"Default2", "Table4", ReplicationStatus.Status.FAILURE, 18L);
ArrayList<ReplicationStatus> replicationStatusList = new ArrayList<ReplicationStatus>();
replicationStatusList.add(table1);
replicationStatusList.add(table2);
replicationStatusList.add(table3);
replicationStatusList.add(table4);
replicationStatusList.add(dbStatus);
drStatusStore.updateReplicationStatus("jobname2", replicationStatusList);
ReplicationStatus status = drStatusStore.getReplicationStatus("source", "target", "jobname2", "default2");
Assert.assertEquals(status.getEventId(), 15);
Assert.assertEquals(status.getStatus(), ReplicationStatus.Status.FAILURE);
Assert.assertEquals(status.getJobName(), "jobname2");
Assert.assertEquals(status.getTable(), null);
Assert.assertEquals(status.getSourceUri(), "source");
Iterator<ReplicationStatus> iter = drStatusStore.getTableReplicationStatusesInDb("source", "target",
"jobname2", "default2");
int size = 0;
while(iter.hasNext()) {
iter.next();
size++;
}
Assert.assertEquals(4, size);
table3 = new ReplicationStatus("source", "target", "jobname2",
"default2", "table3", ReplicationStatus.Status.SUCCESS, 25L);
table4 = new ReplicationStatus("source", "target", "jobname2",
"Default2", "table4", ReplicationStatus.Status.SUCCESS, 22L);
ReplicationStatus table5 = new ReplicationStatus("source", "target", "jobname2",
"default2", "Table5", ReplicationStatus.Status.SUCCESS, 18L);
ReplicationStatus db1table1 = new ReplicationStatus("source", "target", "jobname2",
"Default1", "Table1", ReplicationStatus.Status.SUCCESS, 18L);
replicationStatusList = new ArrayList<ReplicationStatus>();
replicationStatusList.add(table5);
replicationStatusList.add(table3);
replicationStatusList.add(table4);
replicationStatusList.add(db1table1);
drStatusStore.updateReplicationStatus("jobname2", replicationStatusList);
status = drStatusStore.getReplicationStatus("source", "target", "jobname2", "default1");
Assert.assertEquals(status.getEventId(), 18);
Assert.assertEquals(status.getStatus(), ReplicationStatus.Status.SUCCESS);
status = drStatusStore.getReplicationStatus("source", "target", "jobname2", "default2");
Assert.assertEquals(status.getEventId(), 25);
Assert.assertEquals(status.getStatus(), ReplicationStatus.Status.SUCCESS);
iter = drStatusStore.getTableReplicationStatusesInDb("source", "target",
"jobname2", "default2");
size = 0;
while(iter.hasNext()) {
iter.next();
size++;
}
Assert.assertEquals(5, size);
}
public void getReplicationStatusDBTest() throws HiveReplicationException {
ReplicationStatus status = drStatusStore.getReplicationStatus("source", "target", "jobname", "Default1");
Assert.assertEquals(status.getEventId(), 15);
Assert.assertEquals(status.getStatus(), ReplicationStatus.Status.FAILURE);
Assert.assertEquals(status.getJobName(), "jobname");
Assert.assertEquals(status.getTable(), null);
Assert.assertEquals(status.getSourceUri(), "source");
}
public void checkReplicationConflictTest() throws HiveReplicationException {
try {
//same source, same job, same DB, null table : pass
drStatusStore.checkForReplicationConflict("source", "jobname", "default1", null);
//same source, same job, same DB, same table : pass
drStatusStore.checkForReplicationConflict("source", "jobname", "default1", "table1");
//same source, same job, different DB, null table : pass
drStatusStore.checkForReplicationConflict("source", "jobname", "diffDB", null);
//same source, same job, different DB, different table : pass
drStatusStore.checkForReplicationConflict("source", "jobname", "diffDB", "diffTable");
// same source, different job, same DB, diff table : pass
drStatusStore.checkForReplicationConflict("source", "diffJob", "default1", "diffTable");
} catch (Exception e) {
Assert.fail(e.getMessage());
}
try {
// different source, same job, same DB, null table : fail
drStatusStore.checkForReplicationConflict("diffSource", "jobname", "default1", null);
Assert.fail();
} catch (HiveReplicationException e) {
Assert.assertEquals(e.getMessage(),
"Two different sources are attempting to replicate to same db default1."
+ " New Source = diffSource, Existing Source = source");
}
try {
// same source, different job, same DB, null table : fail
drStatusStore.checkForReplicationConflict("source", "diffJob", "default1", null);
Assert.fail();
} catch (HiveReplicationException e) {
Assert.assertEquals(e.getMessage(),
"Two different jobs are attempting to replicate to same db default1."
+ " New Job = diffJob, Existing Job = jobname");
}
try {
// same source, different job, same DB, same table : fail
drStatusStore.checkForReplicationConflict("source", "diffJob", "default1", "table1");
Assert.fail();
} catch (HiveReplicationException e) {
Assert.assertEquals(e.getMessage(),
"Two different jobs are trying to replicate to same table table1."
+ " New job = diffJob, Existing job = jobname");
}
}
public void deleteReplicationStatusTest() throws Exception {
ReplicationStatus dbStatus = new ReplicationStatus("source", "target", "deleteJob",
"deleteDB", null, ReplicationStatus.Status.SUCCESS, 20L);
ReplicationStatus table1 = new ReplicationStatus("source", "target", "deleteJob",
"deleteDB", "Table1", ReplicationStatus.Status.SUCCESS, 20L);
ArrayList<ReplicationStatus> replicationStatusList = new ArrayList<ReplicationStatus>();
replicationStatusList.add(table1);
replicationStatusList.add(dbStatus);
drStatusStore.updateReplicationStatus("deleteJob", replicationStatusList);
ReplicationStatus status = drStatusStore.getReplicationStatus("source", "target", "deleteJob", "deleteDB");
Path statusPath = drStatusStore.getStatusDirPath(status.getDatabase(), status.getJobName());
Assert.assertEquals(fileSystem.exists(statusPath), true);
drStatusStore.deleteReplicationStatus("deleteJob", "deleteDB");
Assert.assertEquals(fileSystem.exists(statusPath), false);
}
public void getReplicationStatusTableTest() throws HiveReplicationException {
ReplicationStatus status = drStatusStore.getReplicationStatus("source", "target",
"jobname", "default1", "table1");
Assert.assertEquals(status.getEventId(), 20);
Assert.assertEquals(status.getStatus(), ReplicationStatus.Status.SUCCESS);
Assert.assertEquals(status.getTable(), "table1");
status = drStatusStore.getReplicationStatus("source", "target",
"jobname", "Default1", "Table2");
Assert.assertEquals(status.getEventId(), -1);
Assert.assertEquals(status.getStatus(), ReplicationStatus.Status.INIT);
Assert.assertEquals(status.getTable(), "table2");
status = drStatusStore.getReplicationStatus("source", "target",
"jobname", "default1", "Table3");
Assert.assertEquals(status.getEventId(), 15);
Assert.assertEquals(status.getStatus(), ReplicationStatus.Status.FAILURE);
Assert.assertEquals(status.getTable(), "table3");
status = drStatusStore.getReplicationStatus("source", "target",
"jobname", "default1", "table4");
Assert.assertEquals(status.getEventId(), 18);
Assert.assertEquals(status.getStatus(), ReplicationStatus.Status.FAILURE);
Assert.assertEquals(status.getTable(), "table4");
}
public void getTableReplicationStatusesInDbTest() throws HiveReplicationException {
Iterator<ReplicationStatus> iter = drStatusStore.getTableReplicationStatusesInDb("source", "target",
"jobname", "Default1");
int size = 0;
while(iter.hasNext()) {
size++;
ReplicationStatus status = iter.next();
if (status.getTable().equals("table3")) {
Assert.assertEquals(status.getEventId(), 15);
Assert.assertEquals(status.getStatus(), ReplicationStatus.Status.FAILURE);
Assert.assertEquals(status.getTable(), "table3");
}
}
Assert.assertEquals(4, size);
}
public void fileRotationTest() throws Exception {
// initialize replication status store for db default3.
// This should init with eventId = -1 and status = INIT
ReplicationStatus status = drStatusStore.getReplicationStatus("source", "target",
"jobname3", "default3");
Assert.assertEquals(status.getEventId(), -1);
Assert.assertEquals(status.getStatus(), ReplicationStatus.Status.INIT);
// update status 5 times resulting in 6 files : latest.json + five rotated files
ReplicationStatus dbStatus = new ReplicationStatus("source", "target", "jobname3",
"Default3", null, ReplicationStatus.Status.SUCCESS, 20L);
ReplicationStatus table1 = new ReplicationStatus("source", "target", "jobname3",
"default3", "Table1", ReplicationStatus.Status.SUCCESS, 20L);
ArrayList<ReplicationStatus> replicationStatusList = new ArrayList<ReplicationStatus>();
replicationStatusList.add(table1);
replicationStatusList.add(dbStatus);
for(int i=0; i<5; i++) {
Thread.sleep(2000);
drStatusStore.updateReplicationStatus("jobname3", replicationStatusList);
}
status = drStatusStore.getReplicationStatus("source", "target", "jobname3", "default3");
Path statusPath = drStatusStore.getStatusDirPath(status.getDatabase(), status.getJobName());
RemoteIterator<LocatedFileStatus> iter = fileSystem.listFiles(statusPath, false);
Assert.assertEquals(getRemoteIterSize(iter), 6);
drStatusStore.rotateStatusFiles(statusPath, 3, 10000000);
iter = fileSystem.listFiles(statusPath, false);
Assert.assertEquals(getRemoteIterSize(iter), 6);
drStatusStore.rotateStatusFiles(statusPath, 3, 6000);
iter = fileSystem.listFiles(statusPath, false);
Assert.assertEquals(getRemoteIterSize(iter), 3);
}
public void wrongJobNameTest() throws Exception {
ReplicationStatus dbStatus = new ReplicationStatus("source", "target", "jobname3",
"Default3", null, ReplicationStatus.Status.SUCCESS, 20L);
ArrayList<ReplicationStatus> replicationStatusList = new ArrayList<ReplicationStatus>();
replicationStatusList.add(dbStatus);
try {
drStatusStore.updateReplicationStatus("jobname2", replicationStatusList);
Assert.fail();
} catch (HiveReplicationException e) {
// Expected exception due to jobname mismatch
}
}
@AfterClass
public void cleanUp() throws IOException {
fileSystem.delete(new Path(DRStatusStore.BASE_DEFAULT_STORE_PATH), true);
}
private int getRemoteIterSize(RemoteIterator<LocatedFileStatus> iter) throws IOException {
int size = 0;
while(iter.hasNext()) {
iter.next();
size++;
}
return size;
}
}