Remove tests for Kotlin Script Templates

Closes gh-34030
This commit is contained in:
Sébastien Deleuze 2024-12-05 10:59:02 +01:00
parent 3eb5b8263b
commit edce3029a2
27 changed files with 28 additions and 423 deletions

View File

@ -53,14 +53,12 @@ dependencies {
testImplementation("org.eclipse.jetty:jetty-reactive-httpclient")
testImplementation("org.eclipse.jetty:jetty-server")
testImplementation("org.hibernate:hibernate-validator")
testImplementation("org.jetbrains.kotlin:kotlin-script-runtime")
testImplementation("org.jetbrains.kotlinx:kotlinx-serialization-json")
testRuntimeOnly("com.sun.xml.bind:jaxb-core")
testRuntimeOnly("com.sun.xml.bind:jaxb-impl")
testRuntimeOnly("com.sun.activation:jakarta.activation")
testRuntimeOnly("io.netty:netty5-buffer")
testRuntimeOnly("org.glassfish:jakarta.el")
testRuntimeOnly("org.jetbrains.kotlin:kotlin-scripting-jsr223")
testRuntimeOnly("org.jruby:jruby")
testRuntimeOnly("org.python:jython-standalone")
testRuntimeOnly("org.webjars:underscorejs")

View File

@ -33,7 +33,6 @@ import reactor.core.scheduler.Schedulers;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.BindingContext;
@ -53,6 +52,7 @@ import static org.springframework.web.testfixture.method.ResolvableMethod.on;
* Tests for {@link Fragment} rendering through {@link ViewResolutionResultHandler}.
*
* @author Rossen Stoyanchev
* @author Sebastien Deleuze
*/
public class FragmentViewResolutionResultHandlerTests {
@ -138,8 +138,8 @@ public class FragmentViewResolutionResultHandlerTests {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(ScriptTemplatingConfiguration.class);
String prefix = "org/springframework/web/reactive/result/view/script/kotlin/";
ScriptTemplateViewResolver viewResolver = new ScriptTemplateViewResolver(prefix, ".kts");
String prefix = "org/springframework/web/reactive/result/view/script/jython/";
ScriptTemplateViewResolver viewResolver = new ScriptTemplateViewResolver(prefix, ".html");
viewResolver.setApplicationContext(context);
viewResolver.setSupportedMediaTypes(List.of(MediaType.TEXT_HTML, MediaType.TEXT_EVENT_STREAM));
@ -166,18 +166,11 @@ public class FragmentViewResolutionResultHandlerTests {
@Bean
public ScriptTemplateConfigurer kotlinScriptConfigurer() {
ScriptTemplateConfigurer configurer = new ScriptTemplateConfigurer();
configurer.setEngineName("kotlin");
configurer.setScripts("org/springframework/web/reactive/result/view/script/kotlin/render.kts");
configurer.setEngineName("jython");
configurer.setScripts("org/springframework/web/reactive/result/view/script/jython/render.py");
configurer.setRenderFunction("render");
return configurer;
}
@Bean
public ResourceBundleMessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("org/springframework/web/reactive/result/view/script/messages");
return messageSource;
}
}
}

View File

@ -1,131 +0,0 @@
/*
* Copyright 2002-2024 the original author or authors.
*
* Licensed 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
*
* https://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.springframework.web.reactive.result.view.script;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.DisabledForJreRange;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.http.MediaType;
import org.springframework.web.testfixture.http.server.reactive.MockServerHttpRequest;
import org.springframework.web.testfixture.http.server.reactive.MockServerHttpResponse;
import org.springframework.web.testfixture.server.MockServerWebExchange;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.condition.JRE.JAVA_21;
/**
* Tests for Kotlin script templates running on Kotlin JSR-223 support.
*
* @author Sebastien Deleuze
*/
@DisabledForJreRange(min = JAVA_21, disabledReason = "Kotlin doesn't support Java 21+ yet")
class KotlinScriptTemplateTests {
@Test
void renderTemplateWithFrenchLocale() throws Exception {
Map<String, Object> model = new HashMap<>();
model.put("foo", "Foo");
String url = "org/springframework/web/reactive/result/view/script/kotlin/template.kts";
MockServerHttpResponse response = render(url, model, Locale.FRENCH, ScriptTemplatingConfiguration.class);
assertThat(response.getBodyAsString().block()).isEqualTo("<html><body>\n<p>Bonjour Foo</p>\n</body></html>");
}
@Test
void renderTemplateWithEnglishLocale() throws Exception {
Map<String, Object> model = new HashMap<>();
model.put("foo", "Foo");
String url = "org/springframework/web/reactive/result/view/script/kotlin/template.kts";
MockServerHttpResponse response = render(url, model, Locale.ENGLISH, ScriptTemplatingConfiguration.class);
assertThat(response.getBodyAsString().block()).isEqualTo("<html><body>\n<p>Hello Foo</p>\n</body></html>");
}
@Test
void renderTemplateWithoutRenderFunction() throws Exception {
Map<String, Object> model = new HashMap<>();
model.put("header", "<html><body>");
model.put("hello", "Hello");
model.put("foo", "Foo");
model.put("footer", "</body></html>");
String url = "org/springframework/web/reactive/result/view/script/kotlin/eval.kts";
Class<?> configClass = ScriptTemplatingConfigurationWithoutRenderFunction.class;
MockServerHttpResponse response = render(url, model, Locale.ENGLISH, configClass);
assertThat(response.getBodyAsString().block()).isEqualTo("<html><body>\n<p>Hello Foo</p>\n</body></html>");
}
private MockServerHttpResponse render(String viewUrl, Map<String, Object> model,
Locale locale, Class<?> configuration) throws Exception {
ScriptTemplateView view = createViewWithUrl(viewUrl, configuration);
MockServerHttpRequest request = MockServerHttpRequest.get("/").acceptLanguageAsLocales(locale).build();
MockServerWebExchange exchange = MockServerWebExchange.from(request);
view.renderInternal(model, MediaType.TEXT_HTML, exchange).block();
return exchange.getResponse();
}
private ScriptTemplateView createViewWithUrl(String viewUrl, Class<?> configuration) throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(configuration);
ctx.refresh();
ScriptTemplateView view = new ScriptTemplateView();
view.setApplicationContext(ctx);
view.setUrl(viewUrl);
view.afterPropertiesSet();
return view;
}
@Configuration
static class ScriptTemplatingConfiguration {
@Bean
public ScriptTemplateConfigurer kotlinScriptConfigurer() {
ScriptTemplateConfigurer configurer = new ScriptTemplateConfigurer();
configurer.setEngineName("kotlin");
configurer.setScripts("org/springframework/web/reactive/result/view/script/kotlin/render.kts");
configurer.setRenderFunction("render");
return configurer;
}
@Bean
public ResourceBundleMessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("org/springframework/web/reactive/result/view/script/messages");
return messageSource;
}
}
@Configuration
static class ScriptTemplatingConfigurationWithoutRenderFunction {
@Bean
public ScriptTemplateConfigurer kotlinScriptConfigurer() {
return new ScriptTemplateConfigurer("kotlin");
}
}
}

View File

@ -1,16 +0,0 @@
@file:Suppress("UNCHECKED_CAST")
package org.springframework.web.reactive.result.view.script
import kotlin.script.templates.standard.ScriptTemplateWithBindings
fun ScriptTemplateWithBindings.include(path: String) =
(bindings["include"] as (String) -> String).invoke(path)
fun ScriptTemplateWithBindings.i18n(code: String) =
(bindings["i18n"] as (String) -> String).invoke(code)
var ScriptTemplateWithBindings.foo: String
get() = bindings["foo"] as String
set(@Suppress("UNUSED_PARAMETER") value) { throw UnsupportedOperationException() }

View File

@ -1,4 +0,0 @@
// TODO Improve syntax when KT-15125 will be fixed
"""${bindings["header"]}
<p>${bindings["hello"]} ${bindings["foo"]}</p>
${bindings["footer"]}"""

View File

@ -1,6 +0,0 @@
import org.springframework.web.reactive.result.view.script.*
"""
|<p>
| ${i18n("hello")} $foo
|</p>""".trimMargin()

View File

@ -1,6 +0,0 @@
import org.springframework.web.reactive.result.view.script.*
"""
|<p>
| ${i18n("hello")} $bar
|</p>""".trimMargin()

View File

@ -1,16 +0,0 @@
import org.springframework.beans.factory.getBean
import org.springframework.context.support.ResourceBundleMessageSource
import org.springframework.web.reactive.result.view.script.RenderingContext
import javax.script.ScriptEngineManager
import javax.script.SimpleBindings
fun render(template: String, model: Map<String, Any>, renderingContext: RenderingContext): String {
val engine = ScriptEngineManager().getEngineByName("kotlin")
val bindings = SimpleBindings()
bindings.putAll(model)
var messageSource = renderingContext.applicationContext.getBean<ResourceBundleMessageSource>()
bindings.put("i18n", { code: String -> messageSource.getMessage(code, null, renderingContext.locale) })
bindings.put("include", { path: String -> renderingContext.templateLoader.apply("org/springframework/web/reactive/result/view/script/kotlin/$path.html") })
return engine.eval(template, bindings) as String
}

View File

@ -1,5 +0,0 @@
import org.springframework.web.reactive.result.view.script.*
"""${include("header") }
<p>${i18n("hello")} $foo</p>
${include("footer")}"""

View File

@ -60,7 +60,6 @@ dependencies {
exclude group: "jakarta.servlet", module: "jakarta.servlet-api"
}
testImplementation("org.hibernate:hibernate-validator")
testImplementation("org.jetbrains.kotlin:kotlin-script-runtime")
testImplementation("org.mozilla:rhino")
testImplementation("org.skyscreamer:jsonassert")
testImplementation("org.xmlunit:xmlunit-assertj")
@ -70,7 +69,6 @@ dependencies {
testRuntimeOnly("com.sun.xml.bind:jaxb-impl")
testRuntimeOnly("org.apache.httpcomponents.client5:httpclient5")
testRuntimeOnly("org.glassfish:jakarta.el")
testRuntimeOnly("org.jetbrains.kotlin:kotlin-scripting-jsr223")
testRuntimeOnly("org.jruby:jruby")
testRuntimeOnly("org.python:jython-standalone")
testRuntimeOnly("org.webjars:underscorejs")

View File

@ -26,7 +26,6 @@ import reactor.core.publisher.Flux;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.task.SyncTaskExecutor;
@ -50,7 +49,9 @@ import static org.springframework.web.testfixture.method.ResolvableMethod.on;
/**
* Tests for streaming of {@link ModelAndView} fragments.
*
* @author Rossen Stoyanchev
* @author Sebastien Deleuze
*/
public class FragmentRenderingStreamTests {
@ -72,8 +73,8 @@ public class FragmentRenderingStreamTests {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(ScriptTemplatingConfiguration.class);
String prefix = "org/springframework/web/servlet/view/script/kotlin/";
ScriptTemplateViewResolver viewResolver = new ScriptTemplateViewResolver(prefix, ".kts");
String prefix = "org/springframework/web/servlet/view/script/jython/";
ScriptTemplateViewResolver viewResolver = new ScriptTemplateViewResolver(prefix, ".html");
viewResolver.setApplicationContext(context);
this.handler = new ResponseBodyEmitterReturnValueHandler(
@ -165,18 +166,12 @@ public class FragmentRenderingStreamTests {
@Bean
ScriptTemplateConfigurer kotlinScriptConfigurer() {
ScriptTemplateConfigurer configurer = new ScriptTemplateConfigurer();
configurer.setEngineName("kotlin");
configurer.setScripts("org/springframework/web/servlet/view/script/kotlin/render.kts");
configurer.setEngineName("jython");
configurer.setScripts("org/springframework/web/servlet/view/script/jython/render.py");
configurer.setRenderFunction("render");
return configurer;
}
@Bean
ResourceBundleMessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("org/springframework/web/servlet/view/script/messages");
return messageSource;
}
}
}

View File

@ -21,26 +21,23 @@ import java.util.Locale;
import java.util.Map;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.DisabledForJreRange;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.web.servlet.view.script.ScriptTemplateConfigurer;
import org.springframework.web.servlet.view.script.ScriptTemplateViewResolver;
import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
import org.springframework.web.testfixture.servlet.MockHttpServletResponse;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.condition.JRE.JAVA_21;
/**
* Tests for rendering through {@link DefaultFragmentsRendering}.
*
* @author Rossen Stoyanchev
* @author Sebastien Deleuze
*/
@DisabledForJreRange(min = JAVA_21, disabledReason = "Kotlin doesn't support Java 21+ yet")
public class DefaultFragmentsRenderingTests {
@Test
@ -49,8 +46,8 @@ public class DefaultFragmentsRenderingTests {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(ScriptTemplatingConfiguration.class);
String prefix = "org/springframework/web/servlet/view/script/kotlin/";
ScriptTemplateViewResolver viewResolver = new ScriptTemplateViewResolver(prefix, ".kts");
String prefix = "org/springframework/web/servlet/view/script/jython/";
ScriptTemplateViewResolver viewResolver = new ScriptTemplateViewResolver(prefix, ".html");
viewResolver.setApplicationContext(context);
MockHttpServletRequest request = new MockHttpServletRequest();
@ -82,18 +79,12 @@ public class DefaultFragmentsRenderingTests {
@Bean
ScriptTemplateConfigurer kotlinScriptConfigurer() {
ScriptTemplateConfigurer configurer = new ScriptTemplateConfigurer();
configurer.setEngineName("kotlin");
configurer.setScripts("org/springframework/web/servlet/view/script/kotlin/render.kts");
configurer.setEngineName("jython");
configurer.setScripts("org/springframework/web/servlet/view/script/jython/render.py");
configurer.setRenderFunction("render");
return configurer;
}
@Bean
ResourceBundleMessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("org/springframework/web/servlet/view/script/messages");
return messageSource;
}
}
}

View File

@ -1,142 +0,0 @@
/*
* Copyright 2002-2024 the original author or authors.
*
* Licensed 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
*
* https://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.springframework.web.servlet.view.script;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import jakarta.servlet.ServletContext;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.DisabledForJreRange;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
import org.springframework.web.testfixture.servlet.MockHttpServletResponse;
import org.springframework.web.testfixture.servlet.MockServletContext;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.condition.JRE.JAVA_21;
import static org.mockito.Mockito.mock;
/**
* Tests for Kotlin script templates running on Kotlin JSR-223 support.
*
* @author Sebastien Deleuze
* @author Sam Brannen
*/
@DisabledForJreRange(min = JAVA_21, disabledReason = "Kotlin doesn't support Java 21+ yet")
class KotlinScriptTemplateTests {
private WebApplicationContext webAppContext = mock();
private ServletContext servletContext = new MockServletContext();
@BeforeEach
void setup() {
this.servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.webAppContext);
}
@Test
void renderTemplateWithFrenchLocale() throws Exception {
Map<String, Object> model = new HashMap<>();
model.put("foo", "Foo");
String url = "org/springframework/web/servlet/view/script/kotlin/template.kts";
MockHttpServletResponse response = render(url, model, Locale.FRENCH, ScriptTemplatingConfiguration.class);
assertThat(response.getContentAsString()).isEqualTo("<html><body>\n<p>Bonjour Foo</p>\n</body></html>");
}
@Test
void renderTemplateWithEnglishLocale() throws Exception {
Map<String, Object> model = new HashMap<>();
model.put("foo", "Foo");
String url = "org/springframework/web/servlet/view/script/kotlin/template.kts";
MockHttpServletResponse response = render(url, model, Locale.ENGLISH, ScriptTemplatingConfiguration.class);
assertThat(response.getContentAsString()).isEqualTo("<html><body>\n<p>Hello Foo</p>\n</body></html>");
}
@Test
void renderTemplateWithoutRenderFunction() throws Exception {
Map<String, Object> model = new HashMap<>();
model.put("header", "<html><body>");
model.put("hello", "Hello");
model.put("foo", "Foo");
model.put("footer", "</body></html>");
MockHttpServletResponse response = render("org/springframework/web/servlet/view/script/kotlin/eval.kts",
model, Locale.ENGLISH, ScriptTemplatingConfigurationWithoutRenderFunction.class);
assertThat(response.getContentAsString()).isEqualTo("<html><body>\n<p>Hello Foo</p>\n</body></html>");
}
private static MockHttpServletResponse render(String viewUrl, Map<String, Object> model,
Locale locale, Class<?> configuration) throws Exception {
ScriptTemplateView view = createViewWithUrl(viewUrl, configuration);
MockHttpServletResponse response = new MockHttpServletResponse();
MockHttpServletRequest request = new MockHttpServletRequest();
request.addPreferredLocale(locale);
view.renderMergedOutputModel(model, request, response);
return response;
}
private static ScriptTemplateView createViewWithUrl(String viewUrl, Class<?> configuration) throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(configuration);
ScriptTemplateView view = new ScriptTemplateView();
view.setApplicationContext(ctx);
view.setUrl(viewUrl);
view.afterPropertiesSet();
return view;
}
@Configuration
static class ScriptTemplatingConfiguration {
@Bean
ScriptTemplateConfigurer kotlinScriptConfigurer() {
ScriptTemplateConfigurer configurer = new ScriptTemplateConfigurer();
configurer.setEngineName("kotlin");
configurer.setScripts("org/springframework/web/servlet/view/script/kotlin/render.kts");
configurer.setRenderFunction("render");
return configurer;
}
@Bean
ResourceBundleMessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("org/springframework/web/servlet/view/script/messages");
return messageSource;
}
}
@Configuration
static class ScriptTemplatingConfigurationWithoutRenderFunction {
@Bean
ScriptTemplateConfigurer kotlinScriptConfigurer() {
return new ScriptTemplateConfigurer("kotlin");
}
}
}

View File

@ -1,16 +0,0 @@
@file:Suppress("UNCHECKED_CAST")
package org.springframework.web.servlet.view.script
import kotlin.script.templates.standard.ScriptTemplateWithBindings
fun ScriptTemplateWithBindings.include(path: String) =
(bindings["include"] as (String) -> String).invoke(path)
fun ScriptTemplateWithBindings.i18n(code: String) =
(bindings["i18n"] as (String) -> String).invoke(code)
var ScriptTemplateWithBindings.foo: String
get() = bindings["foo"] as String
set(@Suppress("UNUSED_PARAMETER") value) { throw UnsupportedOperationException()}

View File

@ -1,4 +0,0 @@
// TODO Improve syntax when KT-15125 will be fixed
"""${bindings["header"]}
<p>${bindings["hello"]} ${bindings["foo"]}</p>
${bindings["footer"]}"""

View File

@ -1,6 +0,0 @@
import org.springframework.web.servlet.view.script.*
"""
|<p>
| ${i18n("hello")} $foo
|</p>""".trimMargin()

View File

@ -1,6 +0,0 @@
import org.springframework.web.servlet.view.script.*
"""
|<p>
| ${i18n("hello")} $bar
|</p>""".trimMargin()

View File

@ -1,15 +0,0 @@
import javax.script.*
import org.springframework.web.servlet.view.script.RenderingContext
import org.springframework.context.support.ResourceBundleMessageSource
import org.springframework.beans.factory.getBean
fun render(template: String, model: Map<String, Any>, renderingContext: RenderingContext): String {
val engine = ScriptEngineManager().getEngineByName("kotlin")
val bindings = SimpleBindings()
bindings.putAll(model)
var messageSource = renderingContext.applicationContext.getBean<ResourceBundleMessageSource>()
bindings.put("i18n", { code: String -> messageSource.getMessage(code, null, renderingContext.locale) })
bindings.put("include", { path: String -> renderingContext.templateLoader.apply("org/springframework/web/servlet/view/script/kotlin/$path.html") })
return engine.eval(template, bindings) as String
}

View File

@ -1,5 +0,0 @@
import org.springframework.web.servlet.view.script.*
"""${include("header") }
<p>${i18n("hello")} $foo</p>
${include("footer")}"""