<commit_before>/*
 * Copyright 2014 http4s.org
 *
 * 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
 *
 *     http://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.http4s
package tomcat
package server

import cats.effect.{ContextShift, IO, Timer}
import cats.syntax.all._
import java.io.IOException
import java.net.{HttpURLConnection, URL}
import java.nio.charset.StandardCharsets
import org.apache.catalina.webresources.TomcatURLStreamHandlerFactory
import org.http4s.dsl.io._
import org.http4s.server.Server
import scala.concurrent.duration._
import scala.io.Source
import java.util.logging.LogManager

class TomcatServerSuite extends Http4sSuite {
  implicit val contextShift: ContextShift[IO] = Http4sSuite.TestContextShift

  override def beforeEach(context: BeforeEach): Unit = {
    // Prevents us from loading jar and war URLs, but lets us
    // run Tomcat twice in the same JVM.  This makes me grumpy.
    //
    TomcatURLStreamHandlerFactory.disable()
    LogManager.getLogManager().reset()
  }

  val builder = TomcatBuilder[IO]

  val serverR: cats.effect.Resource[IO, Server] =
    builder
      .bindAny()
      .withAsyncTimeout(3.seconds)
      .mountService(
        HttpRoutes.of {
          case GET -> Root / "thread" / "routing" =>
            val thread = Thread.currentThread.getName
            Ok(thread)

          case GET -> Root / "thread" / "effect" =>
            IO(Thread.currentThread.getName).flatMap(Ok(_))

          case req @ POST -> Root / "echo" =>
            Ok(req.body)

          case GET -> Root / "never" =>
            IO.never

          case GET -> Root / "slow" =>
            implicitly[Timer[IO]].sleep(50.millis) *> Ok("slow")
        },
        "/"
      )
      .resource

  val tomcatServer = ResourceFixture[Server](serverR)

  def get(server: Server, path: String): IO[String] =
    testBlocker.blockOn(
      IO(
        Source
          .fromURL(new URL(s"http://127.0.0.1:${server.address.getPort}$path"))
          .getLines()
          .mkString))

  def post(server: Server, path: String, body: String): IO[String] =
    testBlocker.blockOn(IO {
      val url = new URL(s"http://127.0.0.1:${server.address.getPort}$path")
      val conn = url.openConnection().asInstanceOf[HttpURLConnection]
      val bytes = body.getBytes(StandardCharsets.UTF_8)
      conn.setRequestMethod("POST")
      conn.setRequestProperty("Content-Length", bytes.size.toString)
      conn.setDoOutput(true)
      conn.getOutputStream.write(bytes)
      Source
        .fromInputStream(conn.getInputStream, StandardCharsets.UTF_8.name)
        .getLines()
        .mkString
    })

  tomcatServer.test("server should route requests on the service executor") { server =>
    get(server, "/thread/routing")
      .map(_.startsWith("http4s-suite-"))
      .assert
  }

  tomcatServer.test("server should execute the service task on the service executor") { server =>
    get(server, "/thread/effect").map(_.startsWith("http4s-suite-")).assert
  }

  tomcatServer.test("server should be able to echo its input") { server =>
    val input = """{ "Hello": "world" }"""
    post(server, "/echo", input).map(_.startsWith(input)).assert
  }

  tomcatServer.test("Timeout should not fire prematurely") { server =>
    get(server, "/slow").assertEquals("slow")
  }<commit_msg>Use `assertEquals` Rather Than `assert`<commit_after>/*
 * Copyright 2014 http4s.org
 *
 * 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
 *
 *     http://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.http4s
package tomcat
package server

import cats.effect.{ContextShift, IO, Timer}
import cats.syntax.all._
import java.io.IOException
import java.net.{HttpURLConnection, URL}
import java.nio.charset.StandardCharsets
import org.apache.catalina.webresources.TomcatURLStreamHandlerFactory
import org.http4s.dsl.io._
import org.http4s.server.Server
import scala.concurrent.duration._
import scala.io.Source
import java.util.logging.LogManager

class TomcatServerSuite extends Http4sSuite {
  implicit val contextShift: ContextShift[IO] = Http4sSuite.TestContextShift

  override def beforeEach(context: BeforeEach): Unit = {
    // Prevents us from loading jar and war URLs, but lets us
    // run Tomcat twice in the same JVM.  This makes me grumpy.
    //
    TomcatURLStreamHandlerFactory.disable()
    LogManager.getLogManager().reset()
  }

  val builder = TomcatBuilder[IO]

  val serverR: cats.effect.Resource[IO, Server] =
    builder
      .bindAny()
      .withAsyncTimeout(3.seconds)
      .mountService(
        HttpRoutes.of {
          case GET -> Root / "thread" / "routing" =>
            val thread = Thread.currentThread.getName
            Ok(thread)

          case GET -> Root / "thread" / "effect" =>
            IO(Thread.currentThread.getName).flatMap(Ok(_))

          case req @ POST -> Root / "echo" =>
            Ok(req.body)

          case GET -> Root / "never" =>
            IO.never

          case GET -> Root / "slow" =>
            implicitly[Timer[IO]].sleep(50.millis) *> Ok("slow")
        },
        "/"
      )
      .resource

  val tomcatServer = ResourceFixture[Server](serverR)

  def get(server: Server, path: String): IO[String] =
    testBlocker.blockOn(
      IO(
        Source
          .fromURL(new URL(s"http://127.0.0.1:${server.address.getPort}$path"))
          .getLines()
          .mkString))

  def post(server: Server, path: String, body: String): IO[String] =
    testBlocker.blockOn(IO {
      val url = new URL(s"http://127.0.0.1:${server.address.getPort}$path")
      val conn = url.openConnection().asInstanceOf[HttpURLConnection]
      val bytes = body.getBytes(StandardCharsets.UTF_8)
      conn.setRequestMethod("POST")
      conn.setRequestProperty("Content-Length", bytes.size.toString)
      conn.setDoOutput(true)
      conn.getOutputStream.write(bytes)
      Source
        .fromInputStream(conn.getInputStream, StandardCharsets.UTF_8.name)
        .getLines()
        .mkString
    })

  tomcatServer.test("server should route requests on the service executor") { server =>
    val prefix: String = "http4s-suite-"
    get(server, "/thread/routing")
      .map(_.take(prefix))
      .assertEquals(prefix)
  }

  tomcatServer.test("server should execute the service task on the service executor") { server =>
    val prefix: String = "http4s-suite-"
    get(server, "/thread/effect").map(_.take(prefix.size)).assertEquals(prefix)
  }

  tomcatServer.test("server should be able to echo its input") { server =>
    val input = """{ "Hello": "world" }"""
    post(server, "/echo", input).map(_.take(input.size)).assertEquals(input)
  }

  tomcatServer.test("Timeout should not fire prematurely") { server =>
    get(server, "/slow").assertEquals("slow")
  }
{'fraction_non_alphanumeric': 0.11946150829956868, 'fraction_numerical': 0.008626323356423996, 'mean_word_length': 3.0210194429847608, 'pattern_counts': {'":': 2, '<': 3, '<?xml version=': 0, '>': 33, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 4, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6990277', 'n_tokens_mistral': 2293, 'n_tokens_neox': 2225, 'n_words': 594}