/* * This file is part of a module with proprietary Enterprise Features. * * Licensed to Crate.io Inc. ("Crate.io") under one or more contributor * license agreements. See the NOTICE file distributed with this work for * additional information regarding copyright ownership. * * Unauthorized copying of this file, via any medium is strictly prohibited. * * To use this file, Crate.io must have given you permission to enable and * use such Enterprise Features and you must have a valid Enterprise or * Subscription Agreement with Crate.io. If you enable or use the Enterprise * Features, you represent and warrant that you have a valid Enterprise or * Subscription Agreement with Crate.io. Your use of the Enterprise Features * if governed by the terms and conditions of your Enterprise or Subscription * Agreement with Crate.io. */ package io.crate.operation.language; import com.google.common.collect.ImmutableList; import io.crate.integrationtests.SQLTransportIntegrationTest; import io.crate.metadata.Schemas; import io.crate.module.JavaScriptLanguageModule; import io.crate.settings.SharedSettings; import io.crate.testing.TestingHelpers; import io.crate.types.DataTypes; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.plugins.Plugin; import org.elasticsearch.test.ESIntegTestCase; import org.junit.Before; import org.junit.Test; import java.util.ArrayList; import java.util.Collection; import static org.hamcrest.CoreMatchers.is; @ESIntegTestCase.ClusterScope(numDataNodes = 2, numClientNodes = 0, randomDynamicTemplates = false) public class JavaScriptUDFIntegrationTest extends SQLTransportIntegrationTest { @Override protected Settings nodeSettings(int nodeOrdinal) { return Settings.builder() .put(super.nodeSettings(nodeOrdinal)) .put(JavaScriptLanguageModule.LANG_JS_ENABLED.getKey(), true) .put(SharedSettings.ENTERPRISE_LICENSE_SETTING.getKey(), true).build(); } @Override protected Collection<Class<? extends Plugin>> nodePlugins() { ArrayList<Class<? extends Plugin>> plugins = new ArrayList<>(super.nodePlugins()); plugins.add(JavaScriptProxyTestPlugin.class); return plugins; } @Before public void beforeTest() { execute("create table test (a long, b long) clustered by(a) into 2 shards"); execute("insert into test (a, b) values (?, ?)", new Object[][]{ new Object[]{5L, 3L}, new Object[]{10L, 7L} }); refresh(); } @Test public void testJavascriptFunction() throws Exception { execute("CREATE FUNCTION subtract_js(LONG, LONG) " + "RETURNS LONG LANGUAGE JAVASCRIPT AS 'function subtract_js(x, y) { return x-y; }'"); assertFunctionIsCreatedOnAll(Schemas.DEFAULT_SCHEMA_NAME, "subtract_js", ImmutableList.of(DataTypes.LONG, DataTypes.LONG)); execute("SELECT SUBTRACT_JS(a, b) FROM test ORDER BY a ASC"); assertThat(response.rowCount(), is(2L)); assertThat(response.rows()[0][0], is(2L)); assertThat(response.rows()[1][0], is(3L)); } @Test public void testBuiltinFunctionOverloadWithOrderBy() throws Exception { // this is a regression test that shows that the correct user-defined function implementations are returned // and not the built-in ones // the query got stuck because we used on built-in function lookup (return type long) and one udf lookup (return type int) // which caused a type mismatch when comparing values in ORDER BY execute("CREATE TABLE test.t (a INTEGER, b INTEGER) WITH (number_of_replicas=0)"); execute("INSERT INTO test.t (a, b) VALUES (1, 1), (2, 1), (3, 1)"); refresh("test.t"); execute("CREATE FUNCTION test.subtract(integer, integer) RETURNS INTEGER LANGUAGE javascript AS 'function subtract(x, y){ return x-y; }'"); assertFunctionIsCreatedOnAll("test", "subtract", ImmutableList.of(DataTypes.INTEGER, DataTypes.INTEGER)); execute("SELECT test.subtract(a, b) FROM test.t ORDER BY 1"); assertThat(TestingHelpers.printedTable(response.rows()), is("0\n1\n2\n")); } }