/*******************************************************************************
* (c) Copyright 2016 Hewlett-Packard Development Company, L.P.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Apache License v2.0 which accompany this distribution.
*
* The Apache License is available at
* http://www.apache.org/licenses/LICENSE-2.0
*
*******************************************************************************/
package io.cloudslang.lang.runtime.bindings.scripts;
import io.cloudslang.dependency.api.services.DependencyService;
import io.cloudslang.dependency.api.services.MavenConfig;
import io.cloudslang.dependency.impl.services.DependencyServiceImpl;
import io.cloudslang.dependency.impl.services.MavenConfigImpl;
import io.cloudslang.lang.entities.SystemProperty;
import io.cloudslang.lang.entities.bindings.ScriptFunction;
import io.cloudslang.lang.entities.bindings.values.Value;
import io.cloudslang.lang.entities.bindings.values.ValueFactory;
import io.cloudslang.runtime.api.python.PythonEvaluationResult;
import io.cloudslang.runtime.api.python.PythonRuntimeService;
import io.cloudslang.runtime.impl.python.PythonExecutionCachedEngine;
import io.cloudslang.runtime.impl.python.PythonExecutionEngine;
import io.cloudslang.runtime.impl.python.PythonExecutor;
import io.cloudslang.score.events.EventBus;
import io.cloudslang.score.events.EventBusImpl;
import junit.framework.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.python.core.PyDictionary;
import org.python.util.PythonInterpreter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.io.Serializable;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import static org.mockito.Matchers.anyMap;
import static org.mockito.Matchers.isA;
import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.python.google.common.collect.Sets.newHashSet;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = ScriptEvaluatorTest.Config.class)
public class ScriptEvaluatorTest {
private static String LINE_SEPARATOR = System.lineSeparator();
private static final String SYSTEM_PROPERTIES_MAP = "sys_prop";
private static final String GET_FUNCTION_DEFINITION =
"def get(key, default_value=None):" + LINE_SEPARATOR +
" value = globals().get(key)" + LINE_SEPARATOR +
" return default_value if value is None else value";
private static final String GET_SP_FUNCTION_DEFINITION =
"def get_sp(key, default_value=None):" + LINE_SEPARATOR +
" property_value = " + SYSTEM_PROPERTIES_MAP + ".get(key)" + LINE_SEPARATOR +
" return default_value if property_value is None else property_value";
private static final String CHECK_EMPTY_FUNCTION_DEFINITION =
"def check_empty(value_to_check, default_value=None):" + LINE_SEPARATOR +
" return default_value if value_to_check is None else value_to_check";
@Rule
public ExpectedException exception = ExpectedException.none();
@Autowired
private ScriptEvaluator scriptEvaluator;
@Autowired
private PythonInterpreter pythonInterpreter;
@Autowired
private PythonRuntimeService pythonRuntimeService;
@Test
public void testEvalExpr() throws Exception {
reset(pythonRuntimeService);
when(pythonRuntimeService.eval(anyString(), anyString(), isA(Map.class)))
.thenReturn(new PythonEvaluationResult("result", new HashMap<String, Serializable>()));
scriptEvaluator.evalExpr("", new HashMap<String, Value>(),
new HashSet<SystemProperty>(), new HashSet<ScriptFunction>());
verify(pythonRuntimeService).eval(eq(""), anyString(), anyMap());
}
@Test
public void testEvalExprError() throws Exception {
reset(pythonRuntimeService);
when(pythonRuntimeService.eval(anyString(), anyString(), anyMap()))
.thenThrow(new RuntimeException("error from interpreter"));
exception.expect(RuntimeException.class);
exception.expectMessage("input_expression");
exception.expectMessage("error from interpreter");
scriptEvaluator.evalExpr("input_expression", new HashMap<String, Value>(), new HashSet<SystemProperty>(),
new HashSet<ScriptFunction>());
}
@Test
public void testEvalFunctions() throws Exception {
reset(pythonRuntimeService);
Set<SystemProperty> props = new HashSet<>();
SystemProperty systemProperty = new SystemProperty("a.b", "c.key", "value");
props.add(systemProperty);
Set<ScriptFunction> functionDependencies = newHashSet(ScriptFunction.GET,
ScriptFunction.GET_SYSTEM_PROPERTY, ScriptFunction.CHECK_EMPTY);
final ArgumentCaptor<String> scriptCaptor = ArgumentCaptor.forClass(String.class);
Map<String, Serializable> scriptReturnContext = new HashMap<>();
scriptReturnContext.put(SYSTEM_PROPERTIES_MAP, new PyDictionary());
when(pythonRuntimeService.eval(anyString(), anyString(), isA(Map.class)))
.thenReturn(new PythonEvaluationResult("result", scriptReturnContext));
String expr = "";
scriptEvaluator.evalExpr(expr, new HashMap<String, Value>(), props, functionDependencies);
Map<String, Serializable> expectedContext = new HashMap<>();
Map<String, Value> properties = new HashMap<>();
properties.put("a.b.c.key", ValueFactory.createPyObjectValue("value", false));
verify(pythonRuntimeService).eval(scriptCaptor.capture(), eq(expr), eq(expectedContext));
final String actualScript = scriptCaptor.getValue();
String[] actualFunctionsArray = actualScript.split(LINE_SEPARATOR + LINE_SEPARATOR);
Set<String> actualFunctions = new HashSet<>();
Collections.addAll(actualFunctions, actualFunctionsArray);
Set<String> expectedFunctions = newHashSet(
GET_FUNCTION_DEFINITION,
GET_SP_FUNCTION_DEFINITION,
CHECK_EMPTY_FUNCTION_DEFINITION
);
Assert.assertEquals(expectedFunctions, actualFunctions);
}
@Configuration
static class Config {
@Bean
public ScriptExecutor scriptExecutor() {
return new ScriptExecutor();
}
@Bean
public ScriptEvaluator scriptEvaluator() {
return new ScriptEvaluator();
}
@Bean
public DependencyService mavenRepositoryService() {
return new DependencyServiceImpl();
}
@Bean
public MavenConfig mavenConfig() {
return new MavenConfigImpl();
}
@Bean
public PythonRuntimeService pythonRuntimeService() {
return mock(PythonRuntimeService.class);
}
@Bean
public PythonInterpreter pythonInterpreter() {
return mock(PythonInterpreter.class);
}
@Bean
public PythonExecutionEngine pythonExecutionEngine() {
return new PythonExecutionCachedEngine() {
protected PythonExecutor createNewExecutor(Set<String> filePaths) {
return new PythonExecutor(filePaths) {
protected PythonInterpreter initInterpreter(Set<String> dependencies) {
return pythonInterpreter();
}
};
}
};
}
@Bean
public EventBus eventBus() {
return new EventBusImpl();
}
}
}