X-Git-Url: https://juplo.de/gitweb/?a=blobdiff_plain;f=dist%2Fhttp-resources%2F2.0.0%2Fxref-test%2Fde%2Fjuplo%2Fhttpresources%2FThymeleafWithHttpResourceProtocolResolverIT.html;fp=dist%2Fhttp-resources%2F2.0.0%2Fxref-test%2Fde%2Fjuplo%2Fhttpresources%2FThymeleafWithHttpResourceProtocolResolverIT.html;h=909fec7afddb5bf5e7a31f7506a2839bdf5ed593;hb=96ec104e2974d001e9bc82c3af8b21029b2042d4;hp=0000000000000000000000000000000000000000;hpb=de1fa457a1c69c673d4dd5c0a2c9af568f74ea12;p=website diff --git a/dist/http-resources/2.0.0/xref-test/de/juplo/httpresources/ThymeleafWithHttpResourceProtocolResolverIT.html b/dist/http-resources/2.0.0/xref-test/de/juplo/httpresources/ThymeleafWithHttpResourceProtocolResolverIT.html new file mode 100644 index 00000000..909fec7a --- /dev/null +++ b/dist/http-resources/2.0.0/xref-test/de/juplo/httpresources/ThymeleafWithHttpResourceProtocolResolverIT.html @@ -0,0 +1,279 @@ + + + +/home/kai/Dokumente/yourshouter/http-resources/src/test/java/de/juplo/httpresources/ThymeleafWithHttpResourceProtocolResolverIT.java xref + + + +
View Javadoc
+1   package de.juplo.httpresources;
+2   
+3   import org.apache.http.entity.StringEntity;
+4   import org.junit.jupiter.api.BeforeEach;
+5   import org.junit.jupiter.api.Test;
+6   import org.mockserver.integration.ClientAndServer;
+7   import org.slf4j.Logger;
+8   import org.slf4j.LoggerFactory;
+9   import org.springframework.beans.factory.annotation.Autowired;
+10  import org.springframework.boot.autoconfigure.SpringBootApplication;
+11  import org.springframework.boot.autoconfigure.thymeleaf.ThymeleafProperties;
+12  import org.springframework.boot.test.context.SpringBootTest;
+13  import org.springframework.cache.Cache;
+14  import org.springframework.context.ApplicationContext;
+15  import org.springframework.context.annotation.Bean;
+16  import org.springframework.core.io.Resource;
+17  import org.springframework.stereotype.Controller;
+18  import org.springframework.test.web.servlet.MockMvc;
+19  import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+20  import org.springframework.ui.Model;
+21  import org.springframework.web.bind.annotation.RequestMapping;
+22  import org.springframework.web.bind.annotation.RequestParam;
+23  import org.springframework.web.context.WebApplicationContext;
+24  import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
+25  import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+26  import org.springframework.web.util.NestedServletException;
+27  import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver;
+28  
+29  import java.io.IOException;
+30  import java.net.URI;
+31  import java.net.URISyntaxException;
+32  import java.nio.file.Files;
+33  import java.nio.file.Paths;
+34  import java.time.Duration;
+35  import java.util.Scanner;
+36  import java.util.stream.Collectors;
+37  
+38  import static org.junit.jupiter.api.Assertions.assertThrows;
+39  import static org.mockserver.model.HttpRequest.request;
+40  import static org.mockserver.verify.VerificationTimes.exactly;
+41  import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+42  import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
+43  import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
+44  import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+45  
+46  
+47  /**
+48   * This test-case showcases the usage of the {@link HttpResourceProtocolResolver}
+49   * with Thymeleaf.
+50   *
+51   * Since Thymeleaf does not use the Resource-Chain mechanism, that Spring introduced
+52   * for the handling of static resources, the {@code HttpResourceProtocolResolver} has
+53   * to be used and the protocol has to be hardwired into the configuration as
+54   * {@code spring.thymeleaf.prefix}.
+55   * The downside of this approach is, that the templates are only resolved against
+56   * the configured remote-URI and do not take part in the fallback-mechanism, that
+57   * can be configured through {@code spring.resources.static-locations}.
+58   *
+59   * The test-case was addapted accordingly, to show the changed behaviour.
+60   */
+61  @SpringBootTest({
+62      "juplo.http-resources.protocol-resolver.enabled=true",
+63      "spring.thymeleaf.cache=true" })
+64  public class ThymeleafWithHttpResourceProtocolResolverIT extends IntegrationTestBase
+65  {
+66    private static final Logger LOG =
+67        LoggerFactory.getLogger(ThymeleafWithHttpResourceProtocolResolverIT.class);
+68  
+69  
+70    @Autowired
+71    HttpResources resources;
+72    @Autowired
+73    Cache cache;
+74    @Autowired
+75    WebApplicationContext context;
+76  
+77    MockMvc mvc;
+78  
+79  
+80    @BeforeEach
+81    public void setUp()
+82    {
+83      cache.clear();
+84      mvc = MockMvcBuilders
+85          .webAppContextSetup(context)
+86          .alwaysDo(print())
+87          .build();
+88    }
+89  
+90  
+91    @Test
+92    public void testRenderLocalTemplate() throws Exception
+93    {
+94      LOG.info("<-- start of test-case");
+95  
+96      assertThrows(
+97          NestedServletException.class,
+98          () -> mvc.perform(get(URI.create("http://test/controller.html?template=local"))));
+99  
+100     server.verify(FETCH("/local.html"), exactly(2));
+101   }
+102 
+103   @Test
+104   public void testRenderRemoteTemplate() throws Exception
+105   {
+106     LOG.info("<-- start of test-case");
+107 
+108     mvc
+109         .perform(get(URI.create("http://test/controller.html?template=remote")))
+110         .andExpect(status().isOk())
+111         .andExpect(content().string(read("/rendered/remote.html")));
+112 
+113     server.verify(FETCH("/remote.html"), exactly(1));
+114   }
+115 
+116   @Test
+117   public void testRenderCachedRemoteTemplate() throws Exception
+118   {
+119     LOG.info("<-- start of test-case");
+120 
+121     mvc
+122         .perform(get(URI.create("http://test/controller.html?template=remote")))
+123         .andExpect(status().isOk())
+124         .andExpect(content().string(read("/rendered/remote.html")));
+125 
+126     mvc
+127         .perform(get(URI.create("http://test/controller.html?template=remote")))
+128         .andExpect(status().isOk())
+129         .andExpect(content().string(read("/rendered/remote.html")));
+130 
+131     mvc
+132         .perform(get(URI.create("http://test/controller.html?template=remote")))
+133         .andExpect(status().isOk())
+134         .andExpect(content().string(read("/rendered/remote.html")));
+135 
+136     mvc
+137         .perform(get(URI.create("http://test/controller.html?template=remote")))
+138         .andExpect(status().isOk())
+139         .andExpect(content().string(read("/rendered/remote.html")));
+140 
+141     server.verify(FETCH("/remote.html"), exactly(1));
+142   }
+143 
+144   @Test
+145   public void testRenderModifiedRemoteTemplate() throws Exception
+146   {
+147     LOG.info("<-- start of test-case");
+148 
+149     mvc
+150         .perform(get(URI.create("http://test/controller.html?template=remote")))
+151         .andExpect(status().isOk())
+152         .andExpect(content().string(read("/rendered/remote.html")));
+153 
+154     CLOCK.timetravel(Duration.ofSeconds(10));
+155     server.when(FETCH("/remote.html")).forward(NGINX("/modified.html"));
+156 
+157     mvc
+158         .perform(get(URI.create("http://test/controller.html?template=remote")))
+159         .andExpect(status().isOk())
+160         .andExpect(content().string(read("/rendered/modified.html")));
+161 
+162     server.verify(FETCH("/remote.html"), exactly(2));
+163     server.verify(
+164         request()
+165             .withPath("/remote.html")
+166             .withHeader("If-Modified-Since")
+167             .withHeader("If-None-Match"),
+168         exactly(1));
+169   }
+170 
+171 
+172   @Controller
+173   public static class TestController
+174   {
+175 
+176     @RequestMapping("/controller.html")
+177     public String controller(
+178         @RequestParam String template,
+179         Model model
+180         )
+181     {
+182       model.addAttribute("template", template);
+183       return template;
+184     }
+185 
+186   }
+187 
+188 
+189   static StringEntity body(String resource) throws URISyntaxException, IOException
+190   {
+191     return new StringEntity(read(resource));
+192   }
+193 
+194   static String read(String resource) throws URISyntaxException, IOException
+195   {
+196     URI uri = ThymeleafWithHttpResourceProtocolResolverIT.class.getResource(resource).toURI();
+197     return Files.readAllLines(Paths.get(uri)).stream().collect(Collectors.joining("\n"));
+198   }
+199 
+200   static String read(Resource resource) throws URISyntaxException, IOException
+201   {
+202     Scanner s = new Scanner(resource.getInputStream()).useDelimiter("\\A");
+203     return s.hasNext() ? s.next() : "";
+204   }
+205 
+206 
+207   @SpringBootApplication
+208   public static class Application implements WebMvcConfigurer
+209   {
+210     @Autowired
+211     ClientAndServer server;
+212 
+213     /**
+214      * This mimics the autoconfiguration of Thymeleaf in Spring-Boot.
+215      * Reason: Found no other way to inject the property {@code spring.thymeleaf.prefix} dynamically
+216      */
+217     @Bean
+218     public SpringResourceTemplateResolver defaultTemplateResolver(
+219         ThymeleafProperties properties,
+220         ApplicationContext applicationContext,
+221         ClientAndServer server)
+222     {
+223       SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
+224       resolver.setApplicationContext(applicationContext);
+225       resolver.setPrefix("http://localhost:" + server.getLocalPort() + "/"); // << Cannot be passed in via properties
+226       resolver.setSuffix(properties.getSuffix());
+227       resolver.setTemplateMode(properties.getMode());
+228       if (properties.getEncoding() != null)
+229       {
+230         resolver.setCharacterEncoding(properties.getEncoding().name());
+231       }
+232       resolver.setCacheable(false); // << With caching enabled, the caching of HttpResources cannot be tested
+233       Integer order = properties.getTemplateResolverOrder();
+234       if (order != null)
+235       {
+236         resolver.setOrder(order);
+237       }
+238       resolver.setCheckExistence(properties.isCheckTemplate());
+239       return resolver;
+240     }
+241 
+242     @Bean
+243     public TestController testController()
+244     {
+245       return new TestController();
+246     }
+247 
+248     @Override
+249     public void addResourceHandlers(ResourceHandlerRegistry registry)
+250     {
+251       LOG.info(
+252           "{} resource-handler for static location {}",
+253           registry.hasMappingForPattern("/**") ? "Overwriting" : "Setting",
+254           "/**"
+255       );
+256       registry
+257           .addResourceHandler("/**")
+258           .addResourceLocations(
+259               "classpath:/static/",
+260               "classpath:/public/",
+261               "http://localhost:" + server.getLocalPort(),
+262               "classpath:/fallback/")
+263           .resourceChain(false);
+264     }
+265   }
+266 }
+
+
+ + +