/**
* 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.notification.service;
import org.apache.falcon.FalconException;
import org.apache.falcon.cluster.util.EmbeddedCluster;
import org.apache.falcon.entity.AbstractTestBase;
import org.apache.falcon.entity.v0.EntityType;
import org.apache.falcon.entity.v0.process.Process;
import org.apache.falcon.execution.NotificationHandler;
import org.apache.falcon.notification.service.event.DataEvent;
import org.apache.falcon.notification.service.impl.DataAvailabilityService;
import org.apache.falcon.notification.service.request.DataNotificationRequest;
import org.apache.falcon.state.EntityClusterID;
import org.apache.falcon.state.ID;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* Test cases for DataNotificationService.
*/
public class DataAvailabilityServiceTest extends AbstractTestBase {
private static NotificationHandler handler = Mockito.mock(NotificationHandler.class);
private static DataAvailabilityService dataAvailabilityService = Mockito.spy(new DataAvailabilityService());
private static final String BASE_PATH = "jail://testCluster:00/data/user";
@BeforeClass
public void setup() throws Exception {
this.dfsCluster = EmbeddedCluster.newCluster("testCluster");
this.conf = dfsCluster.getConf();
storeEntity(EntityType.CLUSTER, "testCluster");
dataAvailabilityService.init();
}
@Test
public void testDataNotificationServiceWithVaryingRequests() throws IOException,
FalconException, InterruptedException {
FileSystem fs = FileSystem.get(conf);
// invalid request
org.apache.falcon.entity.v0.process.Process mockProcess = new Process();
mockProcess.setName("test");
EntityClusterID id = new EntityClusterID(mockProcess, "testCluster");
DataNotificationRequest dataNotificationRequest = getDataNotificationRequest(new ArrayList<Path>(), id);
dataAvailabilityService.register(dataNotificationRequest);
Thread.sleep(1000);
Mockito.verify(handler, Mockito.times(1)).onEvent(Mockito.any(DataEvent.class));
ArgumentCaptor<DataEvent> captor = ArgumentCaptor.forClass(DataEvent.class);
Mockito.verify(handler).onEvent(captor.capture());
Assert.assertEquals(captor.getValue().getStatus(), DataEvent.STATUS.AVAILABLE);
Assert.assertEquals(captor.getValue().getTarget(), dataNotificationRequest.getCallbackId());
cleanupDir(fs, BASE_PATH);
String path1 = BASE_PATH + "/" + "2015";
String path2 = BASE_PATH + "/" + "2016";
fs.create(new Path(path1));
List<Path> paths = new ArrayList<>();
paths.add(new Path(path1));
paths.add(new Path(path2));
// Adding paths and verifying its in queue
dataNotificationRequest = getDataNotificationRequest(paths, id);
dataAvailabilityService.register(dataNotificationRequest);
Mockito.verify(handler, Mockito.times(1)).onEvent(Mockito.any(DataEvent.class));
// create path and check availability status
fs.create(new Path(path2));
Thread.sleep(1000);
Mockito.verify(handler, Mockito.times(2)).onEvent(captor.capture());
Assert.assertEquals(captor.getValue().getStatus(), DataEvent.STATUS.AVAILABLE);
Assert.assertEquals(captor.getValue().getTarget(), dataNotificationRequest.getCallbackId());
// Adding one more path and verify Unavailable case
String path3 = BASE_PATH + "/" + "2017";
paths.add(new Path(path3));
dataNotificationRequest = getDataNotificationRequest(paths, id);
dataAvailabilityService.register(dataNotificationRequest);
Thread.sleep(2000);
Mockito.verify(handler, Mockito.times(3)).onEvent(captor.capture());
Assert.assertEquals(captor.getValue().getStatus(), DataEvent.STATUS.UNAVAILABLE);
Assert.assertEquals(captor.getValue().getTarget(), dataNotificationRequest.getCallbackId());
dataNotificationRequest = getDataNotificationRequest(paths, id);
dataAvailabilityService.register(dataNotificationRequest);
dataAvailabilityService.unregister(dataNotificationRequest.getHandler(),
dataNotificationRequest.getCallbackId());
fs.create(new Path(path3));
Thread.sleep(1000);
// It wont notify as event was unregistered
Mockito.verify(handler, Mockito.times(3)).onEvent(captor.capture());
}
private void cleanupDir(FileSystem fs, String basePath) throws IOException {
fs.delete(new Path(basePath), true);
}
private DataNotificationRequest getDataNotificationRequest(List<Path> locations, ID id) {
DataAvailabilityService.DataRequestBuilder dataRequestBuilder =
new DataAvailabilityService.DataRequestBuilder(handler, id);
dataRequestBuilder.setPollingFrequencyInMillis(20).setCluster("testCluster")
.setTimeoutInMillis(100).setLocations(locations);
return dataRequestBuilder.build();
}
}