blob: 5715e4d812c080febcf0afc594e8f8003b10bb9e [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.livy.repl
import org.apache.spark.SparkConf
import org.json4s.{DefaultFormats, JValue}
import org.json4s.JsonDSL._
import org.apache.livy.rsc.RSCConf
class ScalaInterpreterSpec extends BaseInterpreterSpec {
implicit val formats = DefaultFormats
override def createInterpreter(): Interpreter =
new SparkInterpreter(new SparkConf())
it should "execute `1 + 2` == 3" in withInterpreter { interpreter =>
val response = interpreter.execute("1 + 2")
response should equal (Interpreter.ExecuteSuccess(
TEXT_PLAIN -> "res0: Int = 3"
))
}
it should "execute multiple statements" in withInterpreter { interpreter =>
var response = interpreter.execute("val x = 1")
response should equal (Interpreter.ExecuteSuccess(
TEXT_PLAIN -> "x: Int = 1"
))
response = interpreter.execute("val y = 2")
response should equal (Interpreter.ExecuteSuccess(
TEXT_PLAIN -> "y: Int = 2"
))
response = interpreter.execute("x + y")
response should equal (Interpreter.ExecuteSuccess(
TEXT_PLAIN -> "res0: Int = 3"
))
}
it should "execute multiple statements in one block" in withInterpreter { interpreter =>
val response = interpreter.execute(
"""
|val x = 1
|
|val y = 2
|
|x + y
""".stripMargin)
response should equal(Interpreter.ExecuteSuccess(
TEXT_PLAIN -> "res2: Int = 3"
))
}
it should "do table magic" in withInterpreter { interpreter =>
val response = interpreter.execute(
"""val x = List(List(1, "a"), List(3, "b"))
|%table x
""".stripMargin)
response should equal(Interpreter.ExecuteSuccess(
APPLICATION_LIVY_TABLE_JSON -> (
("headers" -> List(
("type" -> "BIGINT_TYPE") ~ ("name" -> "0"),
("type" -> "STRING_TYPE") ~ ("name" -> "1")
)) ~
("data" -> List(
List[JValue](1, "a"),
List[JValue](3, "b")
))
)
))
}
it should "allow magic inside statements" in withInterpreter { interpreter =>
val response = interpreter.execute(
"""val x = List(List(1, "a"), List(3, "b"))
|%table x
|1 + 2
""".stripMargin)
response should equal(Interpreter.ExecuteSuccess(
TEXT_PLAIN -> "res0: Int = 3"
))
}
it should "capture stdout" in withInterpreter { interpreter =>
val response = interpreter.execute("println(\"Hello World\")")
response should equal(Interpreter.ExecuteSuccess(
TEXT_PLAIN -> "Hello World"
))
}
it should "report an error if accessing an unknown variable" in withInterpreter { interpreter =>
interpreter.execute("x") match {
case Interpreter.ExecuteError(ename, evalue, _) =>
ename should equal ("Error")
evalue should include ("error: not found: value x")
case other =>
fail(s"Expected error, got $other.")
}
}
it should "execute spark commands" in withInterpreter { interpreter =>
val response = interpreter.execute(
"""sc.parallelize(0 to 1).map { i => i+1 }.collect""".stripMargin)
response should equal(Interpreter.ExecuteSuccess(
TEXT_PLAIN -> "res0: Array[Int] = Array(1, 2)"
))
}
it should "handle statements ending with comments" in withInterpreter { interpreter =>
// Test statements with only comments
var response = interpreter.execute("""// comment""")
response should equal(Interpreter.ExecuteSuccess(TEXT_PLAIN -> ""))
response = interpreter.execute(
"""/*
|comment
|*/
""".stripMargin)
response should equal(Interpreter.ExecuteSuccess(TEXT_PLAIN -> ""))
// Test statements ending with comments
response = interpreter.execute(
"""val r = 1
|// comment
""".stripMargin)
response should equal(Interpreter.ExecuteSuccess(TEXT_PLAIN -> "r: Int = 1"))
response = interpreter.execute(
"""val r = 1
|/*
|comment
|comment
|*/
""".stripMargin)
response should equal(Interpreter.ExecuteSuccess(TEXT_PLAIN -> "r: Int = 1"))
// Test statements ending with a mix of single line and multi-line comments
response = interpreter.execute(
"""val r = 1
|// comment
|/*
|comment
|comment
|*/
|// comment
""".stripMargin)
response should equal(Interpreter.ExecuteSuccess(TEXT_PLAIN -> "r: Int = 1"))
response = interpreter.execute(
"""val r = 1
|/*
|comment
|// comment
|comment
|*/
""".stripMargin)
response should equal(Interpreter.ExecuteSuccess(TEXT_PLAIN -> "r: Int = 1"))
// Make sure incomplete statement is still returned as incomplete statement.
response = interpreter.execute("sc.")
response should equal(Interpreter.ExecuteIncomplete())
// Make sure incomplete statement is still returned as incomplete statement.
response = interpreter.execute(
"""sc.
|// comment
""".stripMargin)
response should equal(Interpreter.ExecuteIncomplete())
// Make sure our handling doesn't mess up a string with value like comments.
val tripleQuotes = "\"\"\""
val stringWithComment = s"/*\ncomment\n*/\n//comment"
response = interpreter.execute(s"val r = $tripleQuotes$stringWithComment$tripleQuotes")
try {
response should equal(
Interpreter.ExecuteSuccess(TEXT_PLAIN -> s"r: String = \n$stringWithComment"))
} catch {
case _: Exception =>
response should equal(
// Scala 2.11 doesn't have a " " after "="
Interpreter.ExecuteSuccess(TEXT_PLAIN -> s"r: String =\n$stringWithComment"))
}
}
it should "return code completion candidates" in withInterpreter { interpreter =>
val code =
""""a".""".stripMargin
val actual = interpreter.complete(code, code.length)
actual should contain ("+")
actual should contain ("charAt")
actual should contain ("compareTo")
}
}