package com.thinkbiganalytics.spark.service;
/*-
* #%L
* thinkbig-spark-shell-client-app
* %%
* Copyright (C) 2017 ThinkBig Analytics
* %%
* 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.
* #L%
*/
import com.thinkbiganalytics.spark.SparkContextService;
import com.thinkbiganalytics.spark.dataprofiler.Profiler;
import com.thinkbiganalytics.spark.metadata.TransformScript;
import com.thinkbiganalytics.spark.repl.SparkScriptEngine;
import com.thinkbiganalytics.spark.rest.model.Datasource;
import com.thinkbiganalytics.spark.rest.model.TransformRequest;
import com.thinkbiganalytics.spark.rest.model.TransformResponse;
import com.thinkbiganalytics.spark.shell.DatasourceProvider;
import com.thinkbiganalytics.spark.shell.DatasourceProviderFactory;
import org.apache.commons.io.IOUtils;
import org.apache.spark.SparkContext;
import org.junit.Assert;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Callable;
import javax.annotation.Nonnull;
import scala.tools.nsc.interpreter.NamedParam;
public class TransformServiceTest {
/**
* Verify executing a transformation request.
*/
@Test
@SuppressWarnings("unchecked")
public void execute() throws Exception {
// Mock Spark context service
final SparkContextService sparkContextService = Mockito.mock(SparkContextService.class);
// Mock Spark script engine
final SparkScriptEngine engine = Mockito.mock(SparkScriptEngine.class);
Mockito.when(engine.eval(Mockito.anyString(), Mockito.anyListOf(NamedParam.class))).thenReturn(new MockTransformResult());
Mockito.when(engine.getSparkContext()).thenReturn(Mockito.mock(SparkContext.class));
// Test executing a request
final TransformRequest request = new TransformRequest();
request.setScript("sqlContext.range(1,10)");
final TransformService service = new TransformService(TransformScript.class, engine, sparkContextService, new MockTransformJobTracker());
final TransformResponse response = service.execute(request);
Assert.assertEquals(TransformResponse.Status.SUCCESS, response.getStatus());
// Test eval arguments
final ArgumentCaptor<String> evalScript = ArgumentCaptor.forClass(String.class);
final ArgumentCaptor<List> evalBindings = ArgumentCaptor.forClass(List.class);
Mockito.verify(engine).eval(evalScript.capture(), evalBindings.capture());
final String expectedScript = IOUtils.toString(getClass().getResourceAsStream("transform-service-script1.scala"), "UTF-8");
Assert.assertEquals(expectedScript, evalScript.getValue());
final List<NamedParam> bindings = evalBindings.getValue();
Assert.assertEquals(3, bindings.size());
Assert.assertEquals("profiler", bindings.get(0).name());
Assert.assertEquals("com.thinkbiganalytics.spark.dataprofiler.Profiler", bindings.get(0).tpe());
Assert.assertNull(bindings.get(0).value());
Assert.assertEquals("sparkContextService", bindings.get(1).name());
Assert.assertEquals("com.thinkbiganalytics.spark.SparkContextService", bindings.get(1).tpe());
Assert.assertEquals(sparkContextService, bindings.get(1).value());
Assert.assertEquals("tableName", bindings.get(2).name());
Assert.assertEquals("String", bindings.get(2).tpe());
Assert.assertTrue(((String) bindings.get(2).value()).matches("^[0-9a-f]{32}$"));
}
/**
* Verify executing a transformation request with a data source provider factory.
*/
@Test
@SuppressWarnings("unchecked")
public void executeWithDatasourceProviderFactory() throws Exception {
// Mock Spark context service
final SparkContextService sparkContextService = Mockito.mock(SparkContextService.class);
// Mock Spark script engine
final SparkScriptEngine engine = Mockito.mock(SparkScriptEngine.class);
Mockito.when(engine.eval(Mockito.anyString(), Mockito.anyListOf(NamedParam.class))).thenReturn(new MockTransformResult());
Mockito.when(engine.getSparkContext()).thenReturn(Mockito.mock(SparkContext.class));
// Mock data source provider factory
final DatasourceProvider datasourceProvider = Mockito.mock(DatasourceProvider.class);
final DatasourceProviderFactory datasourceProviderFactory = Mockito.mock(DatasourceProviderFactory.class);
Mockito.when(datasourceProviderFactory.getDatasourceProvider(Mockito.anyCollectionOf(Datasource.class))).thenReturn(datasourceProvider);
// Mock profiler
final Profiler profiler = Mockito.mock(Profiler.class);
// Test executing a request
final TransformRequest request = new TransformRequest();
request.setDatasources(Collections.singletonList(Mockito.mock(Datasource.class)));
request.setScript("sqlContext.range(1,10)");
final TransformService service = new TransformService(TransformScript.class, engine, sparkContextService, new MockTransformJobTracker());
service.setDatasourceProviderFactory(datasourceProviderFactory);
service.setProfiler(profiler);
final TransformResponse response = service.execute(request);
Assert.assertEquals(TransformResponse.Status.SUCCESS, response.getStatus());
// Test eval arguments
final ArgumentCaptor<String> evalScript = ArgumentCaptor.forClass(String.class);
final ArgumentCaptor<List> evalBindings = ArgumentCaptor.forClass(List.class);
Mockito.verify(engine).eval(evalScript.capture(), evalBindings.capture());
final String expectedScript = IOUtils.toString(getClass().getResourceAsStream("transform-service-script1.scala"), "UTF-8");
Assert.assertEquals(expectedScript, evalScript.getValue());
final List<NamedParam> bindings = evalBindings.getValue();
Assert.assertEquals(4, bindings.size());
Assert.assertEquals("profiler", bindings.get(0).name());
Assert.assertEquals("com.thinkbiganalytics.spark.dataprofiler.Profiler", bindings.get(0).tpe());
Assert.assertEquals(profiler, bindings.get(0).value());
Assert.assertEquals("sparkContextService", bindings.get(1).name());
Assert.assertEquals("com.thinkbiganalytics.spark.SparkContextService", bindings.get(1).tpe());
Assert.assertEquals(sparkContextService, bindings.get(1).value());
Assert.assertEquals("tableName", bindings.get(2).name());
Assert.assertEquals("String", bindings.get(2).tpe());
Assert.assertTrue(((String) bindings.get(2).value()).matches("^[0-9a-f]{32}$"));
Assert.assertEquals("datasourceProvider", bindings.get(3).name());
Assert.assertEquals("com.thinkbiganalytics.spark.shell.DatasourceProvider[org.apache.spark.sql.DataFrame]", bindings.get(3).tpe());
Assert.assertEquals(datasourceProvider, bindings.get(3).value());
}
/**
* Verify converting a transformation request to a Scala script.
*/
@Test
public void toScript() throws Exception {
// Build the request
final TransformRequest request = new TransformRequest();
request.setScript("sqlContext.range(1,10)");
// Test converting request to script
final TransformService service = new TransformService(TransformScript.class, Mockito.mock(SparkScriptEngine.class), Mockito.mock(SparkContextService.class),
Mockito.mock(TransformJobTracker.class));
final String expected = IOUtils.toString(getClass().getResourceAsStream("transform-service-script1.scala"), "UTF-8");
Assert.assertEquals(expected, service.toScript(request));
}
/**
* Verify converting a transformation request with a parent to a Scala script.
*/
@Test
public void toScriptWithParent() throws Exception {
// Build the request
final TransformRequest.Parent parent = new TransformRequest.Parent();
parent.setScript("sqlContext.range(1,10)");
parent.setTable("parent_table");
final TransformRequest request = new TransformRequest();
request.setParent(parent);
request.setScript("parent.withColumn(functions.expr(\"id+1\")");
// Test converting request to script
final TransformService service = new TransformService(TransformScript.class, Mockito.mock(SparkScriptEngine.class), Mockito.mock(SparkContextService.class),
Mockito.mock(TransformJobTracker.class));
final String expected = IOUtils.toString(getClass().getResourceAsStream("transform-service-script2.scala"), "UTF-8");
Assert.assertEquals(expected, service.toScript(request));
}
/**
* A mock implementation of {@link TransformJobTracker} for testing.
*/
private static class MockTransformJobTracker extends TransformJobTracker {
/**
* Constructs a {@code MockTransformJobTracker}.
*/
MockTransformJobTracker() {
super(Thread.currentThread().getContextClassLoader());
}
@Override
public void addSparkListener(@Nonnull SparkScriptEngine engine) {
// ignored
}
}
/**
* A mock result from a {@link TransformScript} for testing.
*/
private static class MockTransformResult implements Callable<TransformResponse> {
@Override
public TransformResponse call() throws Exception {
final TransformResponse response = new TransformResponse();
response.setStatus(TransformResponse.Status.SUCCESS);
return response;
}
}
}