blob: e6ebcd5f95247e6042979ca4729d95d91807af7e [file] [log] [blame]
/*
* 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.metron.stellar.zeppelin;
import com.google.common.collect.Iterables;
import org.apache.commons.lang3.StringUtils;
import org.apache.metron.stellar.common.shell.VariableResult;
import org.apache.metron.stellar.dsl.Context;
import org.apache.zeppelin.interpreter.InterpreterContext;
import org.apache.zeppelin.interpreter.InterpreterResult;
import org.apache.zeppelin.interpreter.InterpreterResultMessage;
import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Properties;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.mock;
/**
* Tests the StellarInterpreter.
*/
public class StellarInterpreterTest {
private StellarInterpreter interpreter;
private InterpreterContext context;
@BeforeEach
public void setup() {
Properties props = new Properties();
interpreter = new StellarInterpreter(props);
interpreter.open();
context = mock(InterpreterContext.class);
}
/**
* Ensure that we can run Stellar code in the interpreter.
*/
@Test
public void testExecuteStellar() {
InterpreterResult result = interpreter.interpret("2 + 2", context);
// validate the result
assertEquals(InterpreterResult.Code.SUCCESS, result.code());
assertEquals(1, result.message().size());
// validate the message
InterpreterResultMessage message = result.message().get(0);
assertEquals("4", message.getData());
assertEquals(InterpreterResult.Type.TEXT, message.getType());
}
/**
* Ensure that Stellar lists are displayed correctly in Zeppelin.
*/
@Test
public void testExecuteWithStellarList() {
final String expected = "[1, 2, 3, 4, 5]";
InterpreterResult result = interpreter.interpret("[1,2,3,4,5]", context);
// validate the result
assertEquals(InterpreterResult.Code.SUCCESS, result.code());
assertEquals(1, result.message().size());
// validate the message
InterpreterResultMessage message = result.message().get(0);
assertEquals(expected, message.getData());
assertEquals(InterpreterResult.Type.TEXT, message.getType());
}
/**
* Ensure that Stellar maps are displayed correctly in Zeppelin.
*/
@Test
public void testExecuteWithStellarMap() {
final String expected = "{foo=2, key=val}";
InterpreterResult result = interpreter.interpret("{ 'foo':2, 'key':'val' }", context);
// validate the result
assertEquals(InterpreterResult.Code.SUCCESS, result.code());
assertEquals(1, result.message().size());
// validate the message
InterpreterResultMessage message = result.message().get(0);
assertEquals(expected, message.getData());
assertEquals(InterpreterResult.Type.TEXT, message.getType());
}
/**
* Ensure that 'bad' Stellar code is handled correctly by the interpreter.
*/
@Test
public void testExecuteBadStellar() {
InterpreterResult result = interpreter.interpret("2 + ", context);
// validate the result
assertEquals(InterpreterResult.Code.ERROR, result.code());
assertEquals(1, result.message().size());
// validate the message
InterpreterResultMessage message = result.message().get(0);
assertTrue(message.getData().length() > 0);
assertEquals(InterpreterResult.Type.TEXT, message.getType());
}
/**
* The interpreter should handle if no value is returned. Some Stellar expressions
* will result in no value.
*/
@Test
public void testExecuteNoop() {
// x is undefined and will have no result
InterpreterResult result = interpreter.interpret("x", context);
// validate the result
assertEquals(InterpreterResult.Code.SUCCESS, result.code());
assertEquals(1, result.message().size());
// validate the message
InterpreterResultMessage message = result.message().get(0);
assertEquals(0, message.getData().length());
assertEquals(InterpreterResult.Type.TEXT, message.getType());
}
/**
* The interpreter should support auto-completion.
*/
@Test
public void testAutoCompletion() {
// the user's input that needs auto-completed
final String buffer = "TO_";
// the cursor is at the end of the buffer
int cursor = buffer.length();
List<InterpreterCompletion> completions = interpreter.completion(buffer, cursor);
// expect some completions to be offered
assertTrue(completions.size() > 0);
for(InterpreterCompletion iCompletion: completions) {
String completion = iCompletion.getValue();
// the auto-complete should include an open paren
assertEquals("(", completion.substring(completion.length() - 1));
// the candidate should be a valid, defined function
String function = completion.substring(0, completion.length() - 1);
Iterable<String> allFunctions = interpreter.getExecutor().getFunctionResolver().getFunctions();
String definedFunction = Iterables.find(allFunctions, (fn) -> StringUtils.equals(fn, function));
assertEquals(function, definedFunction);
}
}
/**
* What happens when we have nothing useful to auto-complete?
*/
@Test
public void testAutoCompletionWithNoCompletions() {
// the user's input that needs auto-completed
final String buffer = "NOTHING_AUTOCOMPLETES_THIS_";
// the cursor is at the end of the buffer
int cursor = buffer.length();
// perform auto-completion
List<InterpreterCompletion> completions = interpreter.completion(buffer, cursor);
// expect no completions
assertEquals(0, completions.size());
}
/**
* No Zookeeper client connection should be made if the Zookeeper URL is not defined
*/
@Test
public void testOpenWithNoZookeeperURL() {
// no zookeeper URL defined
Properties props = new Properties();
// open the interpreter
interpreter = new StellarInterpreter(props);
interpreter.open();
// no zookeeper client should be defined
Optional<Object> zk = interpreter.getExecutor().getContext().getCapability(Context.Capabilities.ZOOKEEPER_CLIENT, false);
assertFalse(zk.isPresent());
}
/**
* Ensure that we can run Stellar code in the interpreter.
*/
@Test
public void testExecuteStellarMultipleLines() {
// multi-line input
String input =
"x := 2 + 2" + System.lineSeparator() +
"y := 4 + 4";
InterpreterResult result = interpreter.interpret(input, context);
// expect x == 4 and y == 8
Map<String, VariableResult> vars = interpreter.getExecutor().getState();
assertEquals(4, vars.get("x").getResult());
assertEquals(8, vars.get("y").getResult());
// validate the result
assertEquals(InterpreterResult.Code.SUCCESS, result.code());
assertEquals(1, result.message().size());
// the output is the result of only the 'last' expression
InterpreterResultMessage message = result.message().get(0);
assertEquals("8", message.getData());
assertEquals(InterpreterResult.Type.TEXT, message.getType());
}
}