未验证 提交 e1b55db7 编写于 作者: E Eric Gao 提交者: GitHub

[Improvement][Test] Give an example on replacing Powermock with Mockito (#11588)

* Give an example on replacing powermock with mockito

* Remove redundant comments

* Refactoring related UTs for better readability.
上级 b3bbf69b
......@@ -17,70 +17,38 @@
package org.apache.dolphinscheduler.plugin.task.jupyter;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.apache.dolphinscheduler.plugin.task.api.model.ResourceInfo;
import org.apache.dolphinscheduler.plugin.task.api.parameters.AbstractParameters;
import org.apache.dolphinscheduler.spi.utils.StringUtils;
import java.util.List;
/**
* jupyter parameters
*/
@Getter
@Setter
@ToString
import lombok.Data;
@Data
public class JupyterParameters extends AbstractParameters {
/**
* conda env name
*/
private String condaEnvName;
/**
* input note path
*/
private String inputNotePath;
/**
* output note path
*/
private String outputNotePath;
/**
* parameters to pass into jupyter note cells
*/
// parameters to pass into jupyter note cells
private String parameters;
/**
* jupyter kernel
*/
private String kernel;
/**
* the execution engine name to use in evaluating the notebook
*/
// the execution engine name to use in evaluating the notebook
private String engine;
/**
* time in seconds to wait for each cell before failing execution (default: forever)
*/
// time in seconds to wait for each cell before failing execution (default: forever)
private String executionTimeout;
/**
* time in seconds to wait for kernel to start
*/
// time in seconds to wait for kernel to start
private String startTimeout;
/**
* other arguments
*/
private String others;
/**
* resource list
*/
private List<ResourceInfo> resourceList;
@Override
......@@ -90,7 +58,9 @@ public class JupyterParameters extends AbstractParameters {
@Override
public boolean checkParameters() {
return condaEnvName != null && inputNotePath != null && outputNotePath != null;
return StringUtils.isNotEmpty(condaEnvName) &&
StringUtils.isNotEmpty(inputNotePath) &&
StringUtils.isNotEmpty(outputNotePath);
}
}
......@@ -43,14 +43,8 @@ import com.fasterxml.jackson.databind.ObjectMapper;
public class JupyterTask extends AbstractRemoteTask {
/**
* jupyter parameters
*/
private JupyterParameters jupyterParameters;
/**
* taskExecutionContext
*/
private TaskExecutionContext taskExecutionContext;
private ShellCommandExecutor shellCommandExecutor;
......@@ -88,7 +82,6 @@ public class JupyterTask extends AbstractRemoteTask {
@Override
public void handle(TaskCallBack taskCallBack) throws TaskException {
try {
// SHELL task exit code
TaskResponse response = shellCommandExecutor.run(buildCommand());
setExitStatusCode(response.getExitStatusCode());
setAppIds(String.join(TaskConstants.COMMA, getApplicationIds()));
......@@ -116,16 +109,12 @@ public class JupyterTask extends AbstractRemoteTask {
}
/**
* create command
*
* @return command
* command will be like: papermill [OPTIONS] NOTEBOOK_PATH [OUTPUT_PATH]
*/
protected String buildCommand() throws IOException {
/**
* papermill [OPTIONS] NOTEBOOK_PATH [OUTPUT_PATH]
*/
List<String> args = new ArrayList<>();
final String condaPath = PropertyUtils.getString(TaskConstants.CONDA_PATH);
final String condaPath = readCondaPath();
final String timestamp = DateUtils.getTimestampString();
String condaEnvName = jupyterParameters.getCondaEnvName();
if (condaEnvName.endsWith(JupyterConstants.TXT_SUFFIX)) {
......@@ -149,11 +138,7 @@ public class JupyterTask extends AbstractRemoteTask {
args.add(JupyterConstants.PAPERMILL);
args.add(jupyterParameters.getInputNotePath());
args.add(jupyterParameters.getOutputNotePath());
// populate jupyter parameterization
args.addAll(populateJupyterParameterization());
// populate jupyter options
args.addAll(populateJupyterOptions());
// remove tmp conda env, if created from requirements.txt
......@@ -164,7 +149,6 @@ public class JupyterTask extends AbstractRemoteTask {
// replace placeholder, and combining local and global parameters
Map<String, Property> paramsMap = taskExecutionContext.getPrepareParamsMap();
String command = ParameterUtils
.convertParameterPlaceholders(String.join(" ", args), ParamUtils.convert(paramsMap));
......@@ -173,12 +157,11 @@ public class JupyterTask extends AbstractRemoteTask {
return command;
}
/**
* build jupyter parameterization
*
* @return argument list
*/
private List<String> populateJupyterParameterization() throws IOException {
protected String readCondaPath() {
return PropertyUtils.getString(TaskConstants.CONDA_PATH);
}
protected List<String> populateJupyterParameterization() throws IOException {
List<String> args = new ArrayList<>();
String parameters = jupyterParameters.getParameters();
if (StringUtils.isNotEmpty(parameters)) {
......@@ -200,12 +183,7 @@ public class JupyterTask extends AbstractRemoteTask {
return args;
}
/**
* build jupyter options
*
* @return argument list
*/
private List<String> populateJupyterOptions() {
protected List<String> populateJupyterOptions() {
List<String> args = new ArrayList<>();
String kernel = jupyterParameters.getKernel();
if (StringUtils.isNotEmpty(kernel)) {
......
......@@ -17,121 +17,112 @@
package org.apache.dolphinscheduler.plugin.task.jupyter;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import org.apache.dolphinscheduler.plugin.task.api.TaskExecutionContext;
import org.apache.dolphinscheduler.spi.utils.DateUtils;
import org.apache.dolphinscheduler.spi.utils.JSONUtils;
import org.apache.dolphinscheduler.spi.utils.PropertyUtils;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.core.classloader.annotations.SuppressStaticInitializationFor;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.mockito.ArgumentMatchers.any;
import static org.powermock.api.mockito.PowerMockito.spy;
import static org.powermock.api.mockito.PowerMockito.when;
@RunWith(PowerMockRunner.class)
@PrepareForTest({
JSONUtils.class,
PropertyUtils.class,
DateUtils.class
})
@PowerMockIgnore({"javax.*"})
@SuppressStaticInitializationFor("org.apache.dolphinscheduler.spi.utils.PropertyUtils")
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class JupyterTaskTest {
private static final String EXPECTED_JUPYTER_TASK_COMMAND_USE_LOCAL_CONDA_ENV =
"source /opt/anaconda3/etc/profile.d/conda.sh && " +
"conda activate jupyter-lab && " +
"papermill " +
"/test/input_note.ipynb " +
"/test/output_note.ipynb " +
"--parameters city Shanghai " +
"--parameters factor 0.01 " +
"--kernel python3 " +
"--engine default_engine " +
"--execution-timeout 10 " +
"--start-timeout 3 " +
"--version " +
"--inject-paths " +
"--progress-bar";
private static final String EXPECTED_JUPYTER_TASK_COMMAND_USE_PACKED_CONDA_ENV =
"source /opt/anaconda3/etc/profile.d/conda.sh && " +
"mkdir jupyter_env && " +
"tar -xzf jupyter.tar.gz -C jupyter_env && " +
"source jupyter_env/bin/activate && " +
"papermill " +
"/test/input_note.ipynb " +
"/test/output_note.ipynb " +
"--parameters city Shanghai " +
"--parameters factor 0.01 " +
"--kernel python3 " +
"--engine default_engine " +
"--execution-timeout 10 " +
"--start-timeout 3 " +
"--version " +
"--inject-paths " +
"--progress-bar";
private static final String EXPECTED_JUPYTER_TASK_COMMAND_USE_PIP_REQUIREMENTS =
"set +e \n " +
"source /opt/anaconda3/etc/profile.d/conda.sh && " +
"conda create -n jupyter-tmp-env-123456789 -y && " +
"conda activate jupyter-tmp-env-123456789 && " +
"pip install -r requirements.txt && " +
"papermill " +
"/test/input_note.ipynb " +
"/test/output_note.ipynb " +
"--parameters city Shanghai " +
"--parameters factor 0.01 " +
"--kernel python3 " +
"--engine default_engine " +
"--execution-timeout 10 " +
"--start-timeout 3 " +
"--version " +
"--inject-paths " +
"--progress-bar \n " +
"conda deactivate && conda remove --name jupyter-tmp-env-123456789 --all -y";
@Test
public void testBuildJupyterCommandWithLocalEnv() throws Exception {
String parameters = buildJupyterCommandWithLocalEnv();
TaskExecutionContext taskExecutionContext = PowerMockito.mock(TaskExecutionContext.class);
when(taskExecutionContext.getTaskParams()).thenReturn(parameters);
PowerMockito.mockStatic(PropertyUtils.class);
when(PropertyUtils.getString(any())).thenReturn("/opt/anaconda3/etc/profile.d/conda.sh");
JupyterTask jupyterTask = spy(new JupyterTask(taskExecutionContext));
public void jupyterTaskUseLocalCondaEnv() throws Exception {
String jupyterTaskParameters = buildJupyterTaskUseLocalCondaEnvCommand();
JupyterTask jupyterTask = prepareJupyterTaskForTest(jupyterTaskParameters);
jupyterTask.init();
Assert.assertEquals(jupyterTask.buildCommand(),
"source /opt/anaconda3/etc/profile.d/conda.sh && " +
"conda activate jupyter-lab && " +
"papermill " +
"/test/input_note.ipynb " +
"/test/output_note.ipynb " +
"--parameters city Shanghai " +
"--parameters factor 0.01 " +
"--kernel python3 " +
"--engine default_engine " +
"--execution-timeout 10 " +
"--start-timeout 3 " +
"--version " +
"--inject-paths " +
"--progress-bar");
Assert.assertEquals(jupyterTask.buildCommand(), EXPECTED_JUPYTER_TASK_COMMAND_USE_LOCAL_CONDA_ENV);
}
@Test
public void testBuildJupyterCommandWithPackedEnv() throws Exception {
String parameters = buildJupyterCommandWithPackedEnv();
TaskExecutionContext taskExecutionContext = PowerMockito.mock(TaskExecutionContext.class);
when(taskExecutionContext.getTaskParams()).thenReturn(parameters);
PowerMockito.mockStatic(PropertyUtils.class);
when(PropertyUtils.getString(any())).thenReturn("/opt/anaconda3/etc/profile.d/conda.sh");
JupyterTask jupyterTask = spy(new JupyterTask(taskExecutionContext));
public void jupyterTaskUsePackedCondaEnv() throws Exception {
String jupyterTaskParameters = buildJupyterTaskUsePackedCondaEnvCommand();
JupyterTask jupyterTask = prepareJupyterTaskForTest(jupyterTaskParameters);
jupyterTask.init();
Assert.assertEquals(jupyterTask.buildCommand(),
"source /opt/anaconda3/etc/profile.d/conda.sh && " +
"mkdir jupyter_env && " +
"tar -xzf jupyter.tar.gz -C jupyter_env && " +
"source jupyter_env/bin/activate && " +
"papermill " +
"/test/input_note.ipynb " +
"/test/output_note.ipynb " +
"--parameters city Shanghai " +
"--parameters factor 0.01 " +
"--kernel python3 " +
"--engine default_engine " +
"--execution-timeout 10 " +
"--start-timeout 3 " +
"--version " +
"--inject-paths " +
"--progress-bar");
Assert.assertEquals(jupyterTask.buildCommand(), EXPECTED_JUPYTER_TASK_COMMAND_USE_PACKED_CONDA_ENV);
}
@Test
public void testBuildJupyterCommandWithRequirements() throws Exception {
String parameters = buildJupyterCommandWithRequirements();
TaskExecutionContext taskExecutionContext = PowerMockito.mock(TaskExecutionContext.class);
when(taskExecutionContext.getTaskParams()).thenReturn(parameters);
PowerMockito.mockStatic(PropertyUtils.class);
when(PropertyUtils.getString(any())).thenReturn("/opt/anaconda3/etc/profile.d/conda.sh");
PowerMockito.mockStatic(DateUtils.class);
public void jupyterTaskUsePipRequirements() throws Exception {
String jupyterTaskParameters = buildJupyterTaskUsePipRequirementsCommand();
JupyterTask jupyterTask = prepareJupyterTaskForTest(jupyterTaskParameters);
Mockito.mockStatic(DateUtils.class);
when(DateUtils.getTimestampString()).thenReturn("123456789");
JupyterTask jupyterTask = spy(new JupyterTask(taskExecutionContext));
jupyterTask.init();
Assert.assertEquals(jupyterTask.buildCommand(),
"set +e \n " +
"source /opt/anaconda3/etc/profile.d/conda.sh && " +
"conda create -n jupyter-tmp-env-123456789 -y && " +
"conda activate jupyter-tmp-env-123456789 && " +
"pip install -r requirements.txt && " +
"papermill " +
"/test/input_note.ipynb " +
"/test/output_note.ipynb " +
"--parameters city Shanghai " +
"--parameters factor 0.01 " +
"--kernel python3 " +
"--engine default_engine " +
"--execution-timeout 10 " +
"--start-timeout 3 " +
"--version " +
"--inject-paths " +
"--progress-bar \n " +
"conda deactivate && conda remove --name jupyter-tmp-env-123456789 --all -y"
);
Assert.assertEquals(jupyterTask.buildCommand(), EXPECTED_JUPYTER_TASK_COMMAND_USE_PIP_REQUIREMENTS);
}
private JupyterTask prepareJupyterTaskForTest(final String jupyterTaskParameters) {
TaskExecutionContext taskExecutionContext = Mockito.mock(TaskExecutionContext.class);
when(taskExecutionContext.getTaskParams()).thenReturn(jupyterTaskParameters);
JupyterTask jupyterTask = spy(new JupyterTask(taskExecutionContext));
doReturn("/opt/anaconda3/etc/profile.d/conda.sh").when(jupyterTask).readCondaPath();
return jupyterTask;
}
private String buildJupyterCommandWithLocalEnv() {
private String buildJupyterTaskUseLocalCondaEnvCommand() {
JupyterParameters jupyterParameters = new JupyterParameters();
jupyterParameters.setCondaEnvName("jupyter-lab");
jupyterParameters.setInputNotePath("/test/input_note.ipynb");
......@@ -145,7 +136,7 @@ public class JupyterTaskTest {
return JSONUtils.toJsonString(jupyterParameters);
}
private String buildJupyterCommandWithPackedEnv() {
private String buildJupyterTaskUsePackedCondaEnvCommand() {
JupyterParameters jupyterParameters = new JupyterParameters();
jupyterParameters.setCondaEnvName("jupyter.tar.gz");
jupyterParameters.setInputNotePath("/test/input_note.ipynb");
......@@ -159,7 +150,7 @@ public class JupyterTaskTest {
return JSONUtils.toJsonString(jupyterParameters);
}
private String buildJupyterCommandWithRequirements() {
private String buildJupyterTaskUsePipRequirementsCommand() {
JupyterParameters jupyterParameters = new JupyterParameters();
jupyterParameters.setCondaEnvName("requirements.txt");
jupyterParameters.setInputNotePath("/test/input_note.ipynb");
......
......@@ -15,15 +15,14 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>dolphinscheduler-task-plugin</artifactId>
<groupId>org.apache.dolphinscheduler</groupId>
<artifactId>dolphinscheduler-task-plugin</artifactId>
<version>dev-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>dolphinscheduler-task-zeppelin</artifactId>
<packaging>jar</packaging>
......
......@@ -165,7 +165,7 @@ public class ZeppelinTask extends AbstractRemoteTask {
*
* @return ZeppelinClient
*/
private ZeppelinClient getZeppelinClient() {
protected ZeppelinClient getZeppelinClient() {
final String restEndpoint = zeppelinParameters.getRestEndpoint();
final ClientConfig clientConfig = new ClientConfig(restEndpoint);
ZeppelinClient zClient = null;
......
......@@ -20,14 +20,11 @@ package org.apache.dolphinscheduler.plugin.task.zeppelin;
import static org.apache.dolphinscheduler.plugin.task.api.TaskConstants.EXIT_CODE_FAILURE;
import static org.apache.dolphinscheduler.plugin.task.api.TaskConstants.EXIT_CODE_KILL;
import static org.apache.dolphinscheduler.plugin.task.api.TaskConstants.EXIT_CODE_SUCCESS;
import static org.mockito.ArgumentMatchers.any;
import static org.powermock.api.mockito.PowerMockito.doReturn;
import static org.powermock.api.mockito.PowerMockito.mock;
import static org.powermock.api.mockito.PowerMockito.spy;
import static org.powermock.api.mockito.PowerMockito.when;
import com.fasterxml.jackson.databind.ObjectMapper;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import org.apache.dolphinscheduler.plugin.task.api.TaskCallBack;
import org.apache.dolphinscheduler.plugin.task.api.TaskException;
......@@ -35,32 +32,23 @@ import org.apache.dolphinscheduler.plugin.task.api.TaskExecutionContext;
import org.apache.dolphinscheduler.spi.utils.DateUtils;
import org.apache.dolphinscheduler.spi.utils.JSONUtils;
import org.apache.zeppelin.client.ParagraphResult;
import org.apache.zeppelin.client.NoteResult;
import org.apache.zeppelin.client.ParagraphResult;
import org.apache.zeppelin.client.Status;
import org.apache.zeppelin.client.ZeppelinClient;
import java.util.Map;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import java.util.Map;
import org.mockito.junit.MockitoJUnitRunner;
import com.fasterxml.jackson.databind.ObjectMapper;
@RunWith(PowerMockRunner.class)
@PrepareForTest({
ZeppelinTask.class,
ZeppelinClient.class,
ObjectMapper.class,
DateUtils.class
})
@PowerMockIgnore({"javax.*"})
@RunWith(MockitoJUnitRunner.class)
public class ZeppelinTaskTest {
private static final String MOCK_NOTE_ID = "2GYJR92R7";
......@@ -82,16 +70,14 @@ public class ZeppelinTaskTest {
@Before
public void before() throws Exception {
String zeppelinParameters = buildZeppelinTaskParameters();
TaskExecutionContext taskExecutionContext = PowerMockito.mock(TaskExecutionContext.class);
TaskExecutionContext taskExecutionContext = mock(TaskExecutionContext.class);
when(taskExecutionContext.getTaskParams()).thenReturn(zeppelinParameters);
this.zeppelinTask = spy(new ZeppelinTask(taskExecutionContext));
// mock zClient and paragraph result
this.zClient = mock(ZeppelinClient.class);
this.paragraphResult = mock(ParagraphResult.class);
// use mocked zClient in zeppelinTask
doReturn(this.zClient).when(this.zeppelinTask, "getZeppelinClient");
doReturn(this.zClient).when(this.zeppelinTask).getZeppelinClient();
when(this.zClient.executeParagraph(any(), any(), any(Map.class))).thenReturn(this.paragraphResult);
when(paragraphResult.getResultInText()).thenReturn("mock-zeppelin-paragraph-execution-result");
this.zeppelinTask.init();
......@@ -135,10 +121,10 @@ public class ZeppelinTaskTest {
@Test(expected = TaskException.class)
public void testHandleWithParagraphExecutionException() throws Exception {
when(this.zClient.executeParagraph(any(), any(), any(Map.class))).
thenThrow(new TaskException("Something wrong happens from zeppelin side"));
// when(this.paragraphResult.getStatus()).thenReturn(Status.ERROR);
when(this.zClient.executeParagraph(any(), any(), any(Map.class)))
.thenThrow(new TaskException("Something wrong happens from zeppelin side"));
this.zeppelinTask.handle(taskCallBack);
Mockito.verify(this.zClient).executeParagraph(MOCK_NOTE_ID,
MOCK_PARAGRAPH_ID,
(Map<String, String>) mapper.readValue(MOCK_PARAMETERS, Map.class));
......@@ -150,21 +136,18 @@ public class ZeppelinTaskTest {
@Test
public void testHandleWithNoteExecutionSuccess() throws Exception {
String zeppelinParametersWithNoParagraphId = buildZeppelinTaskParametersWithNoParagraphId();
TaskExecutionContext taskExecutionContext= PowerMockito.mock(TaskExecutionContext.class);
TaskExecutionContext taskExecutionContext = mock(TaskExecutionContext.class);
when(taskExecutionContext.getTaskParams()).thenReturn(zeppelinParametersWithNoParagraphId);
this.zeppelinTask = spy(new ZeppelinTask(taskExecutionContext));
// mock zClient and note result
this.zClient = mock(ZeppelinClient.class);
this.noteResult = mock(NoteResult.class);
// use mocked zClient in zeppelinTask
doReturn(this.zClient).when(this.zeppelinTask, "getZeppelinClient");
doReturn(this.zClient).when(this.zeppelinTask).getZeppelinClient();
when(this.zClient.executeNote(any(), any(Map.class))).thenReturn(this.noteResult);
when(paragraphResult.getResultInText()).thenReturn("mock-zeppelin-paragraph-execution-result");
this.zeppelinTask.init();
when(this.paragraphResult.getStatus()).thenReturn(Status.FINISHED);
this.zeppelinTask.handle(taskCallBack);
Mockito.verify(this.zClient).executeNote(MOCK_NOTE_ID,
(Map<String, String>) mapper.readValue(MOCK_PARAMETERS, Map.class));
Mockito.verify(this.noteResult).getParagraphResultList();
......@@ -174,22 +157,18 @@ public class ZeppelinTaskTest {
@Test
public void testHandleWithNoteExecutionSuccessWithProductionSetting() throws Exception {
String zeppelinParametersWithNoParagraphId = buildZeppelinTaskParametersWithProductionSetting();
TaskExecutionContext taskExecutionContext = PowerMockito.mock(TaskExecutionContext.class);
PowerMockito.mockStatic(DateUtils.class);
TaskExecutionContext taskExecutionContext = mock(TaskExecutionContext.class);
Mockito.mockStatic(DateUtils.class);
when(taskExecutionContext.getTaskParams()).thenReturn(zeppelinParametersWithNoParagraphId);
this.zeppelinTask = spy(new ZeppelinTask(taskExecutionContext));
// mock zClient and note result
this.zClient = mock(ZeppelinClient.class);
this.noteResult = mock(NoteResult.class);
// use mocked zClient in zeppelinTask
doReturn(this.zClient).when(this.zeppelinTask, "getZeppelinClient");
doReturn(this.zClient).when(this.zeppelinTask).getZeppelinClient();
when(this.zClient.cloneNote(any(String.class), any(String.class))).thenReturn(MOCK_CLONE_NOTE_ID);
when(this.zClient.executeNote(any(), any(Map.class))).thenReturn(this.noteResult);
when(paragraphResult.getResultInText()).thenReturn("mock-zeppelin-paragraph-execution-result");
this.zeppelinTask.init();
when(this.paragraphResult.getStatus()).thenReturn(Status.FINISHED);
when(DateUtils.getTimestampString()).thenReturn("123456789");
this.zeppelinTask.handle(taskCallBack);
Mockito.verify(this.zClient).cloneNote(
......@@ -231,4 +210,4 @@ public class ZeppelinTaskTest {
return JSONUtils.toJsonString(zeppelinParameters);
}
}
\ No newline at end of file
}
......@@ -75,4 +75,14 @@
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>3.12.4</version>
<!-- TODO: move this dependency to root pom after removing powermock in the whole project -->
<scope>test</scope>
</dependency>
</dependencies>
</project>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册