/*
* Copyright 2014-2021 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/

package io.ktor.tests.server.jetty.http2

import io.ktor.server.application.*
import io.ktor.server.engine.*
import io.ktor.server.jetty.*
import io.ktor.server.response.*
import io.ktor.server.servlet.*
import org.slf4j.*
import java.net.*
import java.util.concurrent.*
import java.util.concurrent.atomic.*
import kotlin.test.*

@Suppress("BlockingMethodInNonBlockingContext")
class MultipleDispatchOnTimeout {

    private fun findFreePort() = ServerSocket(0).use { it.localPort }

    /**
     * We are testing that the servlet container does not trigger an extra error dispatch for calls that timeout from
     * the perspective of the servlet container. The fact that it does so is apparently specified here on this url:
     * https://docs.oracle.com/javaee/6/api/javax/servlet/AsyncContext.html
     *
     * [Report a problem](https://ktor.io/feedback/?fqname=io.ktor.tests.server.jetty.http2.MultipleDispatchOnTimeout.calls with duration longer than default timeout do not trigger a redispatch)
     */
    @Test
    fun `calls with duration longer than default timeout do not trigger a redispatch`() {
        val callCount = AtomicInteger(0)
        val port = findFreePort()
        val environment = applicationEnvironment {
            log = LoggerFactory.getLogger("io.ktor.test")
        }

        val jetty = embeddedServer(
            Jetty,
            serverConfig(environment) {
                module {
                    intercept(ApplicationCallPipeline.Call) {
                        callCount.incrementAndGet()
                        val timeout = (call.request as ServletApplicationRequest)
                            .servletRequest.asyncContext.timeout.coerceAtLeast(0)
                        Thread.sleep(timeout + 1000)
                        call.respondTextWriter {
                            write("A ok!")
                        }
                    }
                }
            }
        ) {
            connector { this.port = port }
        }
        try {
            jetty.start()

            Thread.sleep(1000)

            val result = URL("http://localhost:$port/").openConnection().inputStream.bufferedReader().readLine().let {
                it
            } ?: "<empty>"

            // println("Got result: $result" )

            assertEquals(1, callCount.get())
            assertEquals("A ok!", result)
        } finally {
            jetty.stop(1, 5, TimeUnit.SECONDS)
        }
    }
}
