001/* 002 * SPDX-License-Identifier: Apache-2.0 003 * 004 * Copyright 2023-2026 The Enola <https://enola.dev> Authors 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); 007 * you may not use this file except in compliance with the License. 008 * You may obtain a copy of the License at 009 * 010 * https://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package dev.enola.web.testlib; 019 020import static com.google.common.truth.Truth.assertThat; 021import static com.google.common.util.concurrent.Futures.immediateFailedFuture; 022import static com.google.common.util.concurrent.Futures.immediateFuture; 023 024import static dev.enola.common.context.testlib.SingletonRule.$; 025 026import static org.junit.Assert.assertThrows; 027 028import com.google.common.net.MediaType; 029 030import dev.enola.common.context.Context; 031import dev.enola.common.context.TLC; 032import dev.enola.common.context.testlib.SingletonRule; 033import dev.enola.common.io.mediatype.MediaTypeProviders; 034import dev.enola.common.io.resource.ResourceProviders; 035import dev.enola.common.io.resource.StringResource; 036import dev.enola.web.StaticWebHandler; 037import dev.enola.web.WebHandlers; 038import dev.enola.web.WebServer; 039 040import org.junit.Rule; 041import org.junit.Test; 042 043import java.io.IOException; 044import java.net.URI; 045 046public abstract class WebServerTestAbstract { 047 048 public @Rule SingletonRule r = $(MediaTypeProviders.set(new MediaTypeProviders())); 049 050 protected abstract WebServer create(WebHandlers handlers) throws IOException; 051 052 private final WebHandlers handlers() { 053 var handlers = new WebHandlers(); 054 055 var hello = StringResource.of("hello, world", MediaType.PLAIN_TEXT_UTF_8); 056 handlers.register("/hello", uri -> immediateFuture(hello)); 057 058 handlers.register("/abc/xyz/", new StaticWebHandler("/abc/xyz/", "static")); 059 060 handlers.register( 061 "/error1", uri -> immediateFailedFuture(new IllegalArgumentException("oink"))); 062 handlers.register( 063 "/error2", 064 uri -> { 065 throw new IllegalArgumentException("oink"); 066 }); 067 068 handlers.register( 069 "/context", 070 uri -> immediateFuture(StringResource.of(TLC.get(TestCtxKey.MAGIC).toString()))); 071 072 return handlers; 073 } 074 075 @Test 076 public void testServer() throws IOException, InterruptedException { 077 try (var ctx = TLC.open()) { 078 ctx.push(TestCtxKey.MAGIC, 123); 079 try (var server = create(handlers())) { 080 server.start(); 081 082 var prefix = "http://localhost:" + server.getInetAddress().getPort(); 083 var rp = new ResourceProviders(); 084 085 // IPv6 NOK :( var uri = URI.create("http://" + server.getInetAddress() + "/hello"); 086 var uri1 = URI.create(prefix + "/hello"); 087 var response1 = rp.getResource(uri1); 088 assertThat(response1.mediaType()).isEqualTo(MediaType.PLAIN_TEXT_UTF_8); 089 assertThat(response1.charSource().read()).isEqualTo("hello, world"); 090 091 var contextURI = URI.create(prefix + "/context"); 092 var responseFromTLC = rp.getResource(contextURI); 093 assertThat(responseFromTLC.charSource().read()).isEqualTo("123"); 094 095 var uri2 = URI.create(prefix + "/abc/xyz/hello.txt"); 096 var response2 = rp.getResource(uri2); 097 assertThat(response2.mediaType()).isEqualTo(MediaType.PLAIN_TEXT_UTF_8); 098 assertThat(response2.charSource().read()).isEqualTo("hi, you\n"); 099 100 var error1 = URI.create(prefix + "/error1"); 101 assertThrows(IOException.class, () -> rp.getNonNull(error1).byteSource().read()); 102 // var errorResponse1 = rp.getResource(error1); 103 // Assert.assertThrows(IOException.class, () -> errorResponse1.charSource().read()); 104 105 var error2 = URI.create(prefix + "/error2"); 106 assertThrows(IOException.class, () -> rp.getNonNull(error2).byteSource().read()); 107 // var errorResponse2 = rp.getResource(error2); 108 // Assert.assertThrows(IOException.class, () -> errorResponse2.charSource().read()); 109 110 // TODO expect HTTP Error 500 111 } 112 } 113 } 114 115 private enum TestCtxKey implements Context.Key<Integer> { 116 MAGIC 117 } 118}