We already have in test/cql-pytest various tests for UDF in the bigger context of UDA (test_uda.py), WASM (test_wasm.py) and permissions, but somehow we never had a file for simple tests only for UDF, so we add one here, test/cql-pytest/test_udf.py We add a test for checking something which was already assumed in test_permissions.py - that it is possible to create two different UDFs with the same name and different parameters, and then you must specify the parameters when you want to DROP one of them. The test confirms that ScyllaDB's and Cassandra's behavior is identical in this, as hoped. To allow the test to run on both ScyllaDB and Cassandra, it needs to support both Lua (for ScyllaDB) or Java (for Cassandra), and we introduce a fixture to make it easier to support both. This fixture can later be used in more tests added to this file. Signed-off-by: Nadav Har'El <nyh@scylladb.com>
68 lines
3.5 KiB
Python
68 lines
3.5 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Copyright 2023-present ScyllaDB
|
|
#
|
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
|
|
#############################################################################
|
|
# Tests for user-defined functions (UDF)
|
|
#############################################################################
|
|
|
|
import pytest
|
|
from util import unique_name, new_function
|
|
from cassandra.protocol import InvalidRequest
|
|
|
|
# Unfortunately, while ScyllaDB and Cassandra support the same UDF
|
|
# feature, each supports a different choice of languages. In particular,
|
|
# Cassandra supports Java and ScyllaDB doesn't - but ScyllaDB supports
|
|
# Lua. The following fixture can be used to check if the server supports
|
|
# Java UDFs - and if it doesn't, the test should use Lua.
|
|
@pytest.fixture(scope="session")
|
|
def has_java_udf(cql, test_keyspace):
|
|
try:
|
|
with new_function(cql, test_keyspace, "(i int) CALLED ON NULL INPUT RETURNS int LANGUAGE java AS 'return 42;'"):
|
|
return True
|
|
except InvalidRequest as e:
|
|
# When the language "java" is not supported, Scylla prints the
|
|
# error message "Language 'java' is not supported". Cassandra
|
|
# isn't expected to fail here because it does support Java.
|
|
# Any other error here indicates an unexpected bug.
|
|
assert "Language 'java' is not supported" in str(e)
|
|
return False
|
|
|
|
# Test that if we have an overloaded function (i.e., two functions with the
|
|
# same name, just with different parameters), DROP FUNCTION requires
|
|
# disambiguating which function you want to drop. Without parameters, the
|
|
# DROP will be an error. On the other hand, when a function is not
|
|
# overloaded and has a unique name, it's not necessary to list the
|
|
# parameters in the DROP command.
|
|
def test_drop_overloaded_udf(cql, test_keyspace, has_java_udf):
|
|
if has_java_udf:
|
|
body1 = "(i int) CALLED ON NULL INPUT RETURNS bigint LANGUAGE java AS 'return 42L;'"
|
|
body2 = "(i int, j int) CALLED ON NULL INPUT RETURNS bigint LANGUAGE java AS 'return 42L;'"
|
|
else:
|
|
body1 = "(i int) CALLED ON NULL INPUT RETURNS bigint LANGUAGE lua AS 'return 42;'"
|
|
body2 = "(i int, j int) CALLED ON NULL INPUT RETURNS bigint LANGUAGE lua AS 'return 42;'"
|
|
args1 = "int"
|
|
args2 = "int, int"
|
|
|
|
# Create two different functions with the same name fun, but a
|
|
# different signature (different parameters):
|
|
fun = unique_name()
|
|
with new_function(cql, test_keyspace, body1, name=fun, args=args1):
|
|
with new_function(cql, test_keyspace, body2, name=fun, args=args2):
|
|
# Shouldn't be able to DROP "fun" without parameters, because
|
|
# it's ambiguous.
|
|
with pytest.raises(InvalidRequest, match="multiple function"):
|
|
cql.execute(f"DROP FUNCTION {test_keyspace}.{fun}")
|
|
# Should be ok to DROP one of the "fun" instances by specifying
|
|
# its parameters explicitly
|
|
cql.execute(f"DROP FUNCTION {test_keyspace}.{fun}({args2})")
|
|
# Now there's only one function left with that name, so it
|
|
# should be fine to drop "fun" without explicit parameters:
|
|
cql.execute(f"DROP FUNCTION {test_keyspace}.{fun}")
|
|
# The new_function() context manager will expect the functions
|
|
# to exist when it ends, to drop them. But we just dropped them.
|
|
# So let's recreate them to pacify new_function():
|
|
cql.execute(f"CREATE FUNCTION {test_keyspace}.{fun} {body1}")
|
|
cql.execute(f"CREATE FUNCTION {test_keyspace}.{fun} {body2}")
|