Repository: http4s/http4s
Pull request #4007 (2020-12-11 16:28:06)

port tests module to cats-effect 3
https://github.com/http4s/http4s/issues/3835


Patch:
diff --git a/build.sbt b/build.sbt
index f1f89e018a..09580b020a 100644
--- a/build.sbt
+++ b/build.sbt
@@ -16,7 +16,7 @@ lazy val modules: List[ProjectReference] = List(
   core,
   laws,
   testing,
-  // tests,
+  tests,
   // server,
   // prometheusMetrics,
   // client,
diff --git a/core/src/main/scala/org/http4s/StaticFile.scala b/core/src/main/scala/org/http4s/StaticFile.scala
index 647139f383..0622464c48 100644
--- a/core/src/main/scala/org/http4s/StaticFile.scala
+++ b/core/src/main/scala/org/http4s/StaticFile.scala
@@ -154,8 +154,8 @@ object StaticFile {
       etagCalc <- etagCalculator(f).map(et => ETag(et))
       res <- Files[F].isFile(f.toPath()).flatMap[Option[Response[F]]] { isFile =>
         if (isFile) {
-
-          if (start >= 0 && end >= start && buffsize > 0) {
+          val requireCondition = start >= 0 && end >= start && buffsize > 0
+          if (!requireCondition) {
             F.raiseError[Option[Response[F]]](new IllegalArgumentException(
               s"requirement failed: start: $start, end: $end, buffsize: $buffsize"))
           } else {


Test patch:
diff --git a/testing/src/test/scala/org/http4s/testing/EqF.scala b/testing/src/test/scala/org/http4s/testing/EqF.scala
new file mode 100644
index 0000000000..a52c772fe4
--- /dev/null
+++ b/testing/src/test/scala/org/http4s/testing/EqF.scala
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2016 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.testing
+
+import cats.Eq
+import cats.effect.std.Dispatcher
+
+trait EqF {
+  implicit def eqF[A, F[_]](implicit eqA: Eq[A], dispatcher: Dispatcher[F]): Eq[F[A]] =
+    Eq.by[F[A], A](f => dispatcher.unsafeRunSync(f))
+}
diff --git a/tests/src/test/scala/io/chrisdavenport/vault/KeyTests.scala b/tests/src/test/scala/io/chrisdavenport/vault/KeyTests.scala
index 0a55ff9516..edcd2a60c3 100644
--- a/tests/src/test/scala/io/chrisdavenport/vault/KeyTests.scala
+++ b/tests/src/test/scala/io/chrisdavenport/vault/KeyTests.scala
@@ -1,3 +1,19 @@
+/*
+ * Copyright 2013 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 io.chrisdavenport.vault
 
 import org.scalacheck._
diff --git a/tests/src/test/scala/io/chrisdavenport/vault/VaultSpec.scala b/tests/src/test/scala/io/chrisdavenport/vault/VaultSpec.scala
index 0c8b3857aa..1b7a13e7a9 100644
--- a/tests/src/test/scala/io/chrisdavenport/vault/VaultSpec.scala
+++ b/tests/src/test/scala/io/chrisdavenport/vault/VaultSpec.scala
@@ -1,3 +1,19 @@
+/*
+ * Copyright 2013 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 io.chrisdavenport.vault
 
 import cats.effect._
diff --git a/tests/src/test/scala/org/http4s/EntityCodecSpec.scala b/tests/src/test/scala/org/http4s/EntityCodecSpec.scala
index 423a2576bb..e62c9595fa 100644
--- a/tests/src/test/scala/org/http4s/EntityCodecSpec.scala
+++ b/tests/src/test/scala/org/http4s/EntityCodecSpec.scala
@@ -18,26 +18,27 @@ package org.http4s
 
 import cats.Eq
 import cats.effect.IO
-import cats.effect.laws.util.TestContext
-import cats.effect.laws.util.TestInstances._
+import cats.effect.std.Dispatcher
+import cats.implicits._
 import fs2.Chunk
 import org.http4s.laws.discipline.EntityCodecTests
+import org.http4s.testing.EqF
 import org.http4s.testing.fs2Arbitraries._
 
-class EntityCodecSpec extends Http4sSpec {
-  implicit val testContext: TestContext = TestContext()
-
+class EntityCodecSpec extends Http4sSpec with EqF {
   implicit def eqArray[A](implicit ev: Eq[Vector[A]]): Eq[Array[A]] =
     Eq.by(_.toVector)
 
   implicit def eqChunk[A](implicit ev: Eq[Vector[A]]): Eq[Chunk[A]] =
     Eq.by(_.toVector)
 
-  checkAll("EntityCodec[IO, String]", EntityCodecTests[IO, String].entityCodec)
-  checkAll("EntityCodec[IO, Array[Char]]", EntityCodecTests[IO, Array[Char]].entityCodec)
+  withResource(Dispatcher[IO]) { implicit dispatcher =>
+    checkAll("EntityCodec[IO, String]", EntityCodecTests[IO, String].entityCodec)
+    checkAll("EntityCodec[IO, Array[Char]]", EntityCodecTests[IO, Array[Char]].entityCodec)
 
-  checkAll("EntityCodec[IO, Chunk[Byte]]", EntityCodecTests[IO, Chunk[Byte]].entityCodec)
-  checkAll("EntityCodec[IO, Array[Byte]]", EntityCodecTests[IO, Array[Byte]].entityCodec)
+    checkAll("EntityCodec[IO, Chunk[Byte]]", EntityCodecTests[IO, Chunk[Byte]].entityCodec)
+    checkAll("EntityCodec[IO, Array[Byte]]", EntityCodecTests[IO, Array[Byte]].entityCodec)
 
-  checkAll("EntityCodec[IO, Unit]", EntityCodecTests[IO, Unit].entityCodec)
+    checkAll("EntityCodec[IO, Unit]", EntityCodecTests[IO, Unit].entityCodec)
+  }
 }
diff --git a/tests/src/test/scala/org/http4s/EntityDecoderSpec.scala b/tests/src/test/scala/org/http4s/EntityDecoderSpec.scala
index 7d44626bbc..dc4cc9e78b 100644
--- a/tests/src/test/scala/org/http4s/EntityDecoderSpec.scala
+++ b/tests/src/test/scala/org/http4s/EntityDecoderSpec.scala
@@ -17,7 +17,6 @@
 package org.http4s
 
 import cats.effect._
-import cats.effect.laws.util.TestContext
 import cats.syntax.all._
 import fs2._
 import fs2.Stream._
@@ -33,7 +32,6 @@ import scala.concurrent.ExecutionContext
 
 class EntityDecoderSpec extends Http4sSpec with Http4sLegacyMatchersIO with PendingUntilFixed {
   implicit val executionContext: ExecutionContext = Trampoline
-  implicit val testContext: TestContext = TestContext()
 
   val `application/excel`: MediaType =
     new MediaType("application", "excel", true, false, List("xls"))
@@ -312,7 +310,7 @@ class EntityDecoderSpec extends Http4sSpec with Http4sLegacyMatchersIO with Pend
     "invoke the function with  the right on a success" in {
       val happyDecoder: EntityDecoder[IO, String] =
         EntityDecoder.decodeBy(MediaRange.`*/*`)(_ => DecodeResult.success(IO.pure("hooray")))
-      IO.async[String] { cb =>
+      IO.async_[String] { cb =>
         request
           .decodeWith(happyDecoder, strict = false) { s =>
             cb(Right(s))
@@ -390,7 +388,7 @@ class EntityDecoderSpec extends Http4sSpec with Http4sLegacyMatchersIO with Pend
       val tmpFile = File.createTempFile("foo", "bar")
       try {
         val response = mockServe(Request()) { req =>
-          req.decodeWith(EntityDecoder.textFile(tmpFile, testBlocker), strict = false) { _ =>
+          req.decodeWith(EntityDecoder.textFile(tmpFile), strict = false) { _ =>
             Response[IO](Ok).withEntity("Hello").pure[IO]
           }
         }.unsafeRunSync()
@@ -408,7 +406,7 @@ class EntityDecoderSpec extends Http4sSpec with Http4sLegacyMatchersIO with Pend
       val tmpFile = File.createTempFile("foo", "bar")
       try {
         val response = mockServe(Request()) { case req =>
-          req.decodeWith(EntityDecoder.binFile(tmpFile, testBlocker), strict = false) { _ =>
+          req.decodeWith(EntityDecoder.binFile(tmpFile), strict = false) { _ =>
             Response[IO](Ok).withEntity("Hello").pure[IO]
           }
         }.unsafeRunSync()
diff --git a/tests/src/test/scala/org/http4s/EntityDecoderSuite.scala b/tests/src/test/scala/org/http4s/EntityDecoderSuite.scala
index 6eb912e791..061fbd43eb 100644
--- a/tests/src/test/scala/org/http4s/EntityDecoderSuite.scala
+++ b/tests/src/test/scala/org/http4s/EntityDecoderSuite.scala
@@ -333,7 +333,7 @@ class EntityDecoderSuite extends Http4sSuite {
   test("apply should invoke the function with  the right on a success") {
     val happyDecoder: EntityDecoder[IO, String] =
       EntityDecoder.decodeBy(MediaRange.`*/*`)(_ => DecodeResult.success(IO.pure("hooray")))
-    IO.async[String] { cb =>
+    IO.async_[String] { cb =>
       request
         .decodeWith(happyDecoder, strict = false) { s =>
           cb(Right(s))
@@ -413,7 +413,7 @@ class EntityDecoderSuite extends Http4sSuite {
       .make(IO(File.createTempFile("foo", "bar")))(f => IO(f.delete()).void)
       .use { tmpFile =>
         val response = mockServe(Request()) { req =>
-          req.decodeWith(EntityDecoder.textFile(tmpFile, testBlocker), strict = false) { _ =>
+          req.decodeWith(EntityDecoder.textFile(tmpFile), strict = false) { _ =>
             Response[IO](Ok).withEntity("Hello").pure[IO]
           }
         }
@@ -430,7 +430,7 @@ class EntityDecoderSuite extends Http4sSuite {
       .make(IO(File.createTempFile("foo", "bar")))(f => IO(f.delete()).void)
       .use { tmpFile =>
         val response = mockServe(Request()) { case req =>
-          req.decodeWith(EntityDecoder.binFile(tmpFile, testBlocker), strict = false) { _ =>
+          req.decodeWith(EntityDecoder.binFile(tmpFile), strict = false) { _ =>
             Response[IO](Ok).withEntity("Hello").pure[IO]
           }
         }
diff --git a/tests/src/test/scala/org/http4s/EntityEncoderSpec.scala b/tests/src/test/scala/org/http4s/EntityEncoderSpec.scala
index c089578939..dd7cd3bf8a 100644
--- a/tests/src/test/scala/org/http4s/EntityEncoderSpec.scala
+++ b/tests/src/test/scala/org/http4s/EntityEncoderSpec.scala
@@ -73,7 +73,7 @@ class EntityEncoderSpec extends Http4sSpec {
         val w = new FileWriter(tmpFile)
         try w.write("render files test")
         finally w.close()
-        writeToString(tmpFile)(EntityEncoder.fileEncoder(testBlocker)) must_== "render files test"
+        writeToString(tmpFile)(EntityEncoder.fileEncoder) must_== "render files test"
       } finally {
         tmpFile.delete()
         ()
@@ -82,13 +82,12 @@ class EntityEncoderSpec extends Http4sSpec {
 
     "render input streams" in {
       val inputStream = new ByteArrayInputStream("input stream".getBytes(StandardCharsets.UTF_8))
-      writeToString(IO(inputStream))(
-        EntityEncoder.inputStreamEncoder(testBlocker)) must_== "input stream"
+      writeToString(IO(inputStream))(EntityEncoder.inputStreamEncoder) must_== "input stream"
     }
 
     "render readers" in {
       val reader = new StringReader("string reader")
-      writeToString(IO(reader))(EntityEncoder.readerEncoder(testBlocker)) must_== "string reader"
+      writeToString(IO(reader))(EntityEncoder.readerEncoder) must_== "string reader"
     }
 
     "render very long readers" in {
@@ -97,15 +96,13 @@ class EntityEncoderSpec extends Http4sSpec {
       // This is reproducible on input streams
       val longString = "string reader" * 5000
       val reader = new StringReader(longString)
-      writeToString[IO[Reader]](IO(reader))(
-        EntityEncoder.readerEncoder(testBlocker)) must_== longString
+      writeToString[IO[Reader]](IO(reader))(EntityEncoder.readerEncoder) must_== longString
     }
 
     "render readers with UTF chars" in {
       val utfString = "A" + "\u08ea" + "\u00f1" + "\u72fc" + "C"
       val reader = new StringReader(utfString)
-      writeToString[IO[Reader]](IO(reader))(
-        EntityEncoder.readerEncoder(testBlocker)) must_== utfString
+      writeToString[IO[Reader]](IO(reader))(EntityEncoder.readerEncoder) must_== utfString
     }
 
     "give the content type" in {
diff --git a/tests/src/test/scala/org/http4s/StaticFileSuite.scala b/tests/src/test/scala/org/http4s/StaticFileSuite.scala
index 6c9a6b1827..095b37a6be 100644
--- a/tests/src/test/scala/org/http4s/StaticFileSuite.scala
+++ b/tests/src/test/scala/org/http4s/StaticFileSuite.scala
@@ -31,7 +31,7 @@ import java.net.UnknownHostException
 class StaticFileSuite extends Http4sSuite {
   test("Determine the media-type based on the files extension") {
     def check(f: File, tpe: Option[MediaType]): IO[Boolean] =
-      StaticFile.fromFile[IO](f, testBlocker).value.map { r =>
+      StaticFile.fromFile[IO](f).value.map { r =>
         r.isDefined &&
         r.flatMap(_.headers.get(`Content-Type`)) == tpe.map(t => `Content-Type`(t)) &&
         // Other headers must be present
@@ -50,7 +50,7 @@ class StaticFileSuite extends Http4sSuite {
   test("load from resource") {
     def check(resource: String, status: Status): IO[Unit] = {
       val res1 = StaticFile
-        .fromResource[IO](resource, testBlocker)
+        .fromResource[IO](resource)
         .value
 
       Nested(res1)
@@ -83,7 +83,7 @@ class StaticFileSuite extends Http4sSuite {
 
     def check(resource: String, status: Status): IO[Unit] = {
       val res1 = StaticFile
-        .fromResource[IO](resource, testBlocker, classloader = Some(loader))
+        .fromResource[IO](resource, classloader = Some(loader))
         .value
 
       Nested(res1).map(_.status).value.map(_.getOrElse(NotFound)).assertEquals(status)
@@ -106,7 +106,7 @@ class StaticFileSuite extends Http4sSuite {
   test("handle an empty file") {
     val emptyFile = File.createTempFile("empty", ".tmp")
 
-    StaticFile.fromFile[IO](emptyFile, testBlocker).value.map(_.isDefined).assertEquals(true)
+    StaticFile.fromFile[IO](emptyFile).value.map(_.isDefined).assertEquals(true)
   }
 
   test("Don't send unmodified files") {
@@ -115,7 +115,7 @@ class StaticFileSuite extends Http4sSuite {
     val request =
       Request[IO]().putHeaders(`If-Modified-Since`(HttpDate.MaxValue))
     val response = StaticFile
-      .fromFile[IO](emptyFile, testBlocker, Some(request))
+      .fromFile[IO](emptyFile, Some(request))
       .value
     Nested(response).map(_.status).value.assertEquals(Some(NotModified))
   }
@@ -128,7 +128,7 @@ class StaticFileSuite extends Http4sSuite {
         `If-None-Match`(
           EntityTag(s"${emptyFile.lastModified().toHexString}-${emptyFile.length().toHexString}")))
     val response = StaticFile
-      .fromFile[IO](emptyFile, testBlocker, Some(request))
+      .fromFile[IO](emptyFile, Some(request))
       .value
     Nested(response).map(_.status).value.assertEquals(Some(NotModified))
   }
@@ -143,7 +143,7 @@ class StaticFileSuite extends Http4sSuite {
           EntityTag(s"${emptyFile.lastModified().toHexString}-${emptyFile.length().toHexString}")))
 
     val response = StaticFile
-      .fromFile[IO](emptyFile, testBlocker, Some(request))
+      .fromFile[IO](emptyFile, Some(request))
       .value
     Nested(response).map(_.status).value.assertEquals(Some(NotModified))
   }
@@ -156,7 +156,7 @@ class StaticFileSuite extends Http4sSuite {
         .putHeaders(`If-Modified-Since`(HttpDate.MaxValue), `If-None-Match`(EntityTag(s"12345")))
 
     val response = StaticFile
-      .fromFile[IO](emptyFile, testBlocker, Some(request))
+      .fromFile[IO](emptyFile, Some(request))
       .value
     Nested(response).map(_.status).value.assertEquals(Some(Ok))
   }
@@ -173,7 +173,7 @@ class StaticFileSuite extends Http4sSuite {
               s"${emptyFile.lastModified().toHexString}-${emptyFile.length().toHexString}")))
 
     val response = StaticFile
-      .fromFile[IO](emptyFile, testBlocker, Some(request))
+      .fromFile[IO](emptyFile, Some(request))
       .value
     Nested(response).map(_.status).value.assertEquals(Some(Ok))
   }
@@ -182,14 +182,7 @@ class StaticFileSuite extends Http4sSuite {
     def check(path: String): IO[Unit] =
       IO(new File(path)).flatMap { f =>
         StaticFile
-          .fromFile[IO](
-            f,
-            0,
-            1,
-            StaticFile.DefaultBufferSize,
-            testBlocker,
-            None,
-            StaticFile.calcETag[IO])
+          .fromFile[IO](f, 0, 1, StaticFile.DefaultBufferSize, None, StaticFile.calcETag[IO])
           .value
           .flatMap { r =>
             // Length is only 1 byte
@@ -222,10 +215,9 @@ class StaticFileSuite extends Http4sSuite {
       StaticFile
         .fromFile[IO](
           file,
-          0,
-          fileSize.toLong - 1,
-          StaticFile.DefaultBufferSize,
-          testBlocker,
+          start = 0,
+          end = fileSize.toLong - 1,
+          buffsize = StaticFile.DefaultBufferSize,
           None,
           StaticFile.calcETag[IO])
         .value
@@ -257,7 +249,7 @@ class StaticFileSuite extends Http4sSuite {
     val url = getClass.getResource("/lorem-ipsum.txt")
     val expected = scala.io.Source.fromURL(url, "utf-8").mkString
     val s = StaticFile
-      .fromURL[IO](getClass.getResource("/lorem-ipsum.txt"), testBlocker)
+      .fromURL[IO](getClass.getResource("/lorem-ipsum.txt"))
       .value
       .map(_.fold[EntityBody[IO]](sys.error("Couldn't find resource"))(_.body))
     // Expose problem with readInputStream recycling buffer.  chunks.compile.toVector
@@ -271,7 +263,7 @@ class StaticFileSuite extends Http4sSuite {
     val url = getClass.getResource("/lorem-ipsum.txt")
     val len =
       StaticFile
-        .fromURL[IO](url, testBlocker)
+        .fromURL[IO](url)
         .value
         .map(_.flatMap(_.contentLength))
     len.assertEquals(Some(24005L))
@@ -280,21 +272,21 @@ class StaticFileSuite extends Http4sSuite {
   test("return none from a URL that is a directory") {
     // val url = getClass.getResource("/foo")
     StaticFile
-      .fromURL[IO](getClass.getResource("/foo"), testBlocker)
+      .fromURL[IO](getClass.getResource("/foo"))
       .value
       .assertEquals(None)
   }
 
   test("return none from a URL that points to a resource that does not exist") {
     StaticFile
-      .fromURL[IO](new URL("https://github.com/http4s/http4s/fooz"), testBlocker)
+      .fromURL[IO](new URL("https://github.com/http4s/http4s/fooz"))
       .value
       .assertEquals(None)
   }
 
   test("raise exception when url does not exist") {
     StaticFile
-      .fromURL[IO](new URL("https://quuzgithubfoo.com/http4s/http4s/fooz"), testBlocker)
+      .fromURL[IO](new URL("https://quuzgithubfoo.com/http4s/http4s/fooz"))
       .value
       .intercept[UnknownHostException]
   }
diff --git a/tests/src/test/scala/org/http4s/multipart/MultipartParserSpec.scala b/tests/src/test/scala/org/http4s/multipart/MultipartParserSpec.scala
index 8092dbca62..bb463a2cb5 100644
--- a/tests/src/test/scala/org/http4s/multipart/MultipartParserSpec.scala
+++ b/tests/src/test/scala/org/http4s/multipart/MultipartParserSpec.scala
@@ -18,9 +18,8 @@ package org.http4s
 package multipart
 
 import java.nio.charset.StandardCharsets
-
 import cats.effect._
-import cats.effect.concurrent.Ref
+import cats.effect.unsafe.IORuntime
 import cats.instances.string._
 import fs2._
 import org.http4s.headers._
@@ -29,7 +28,7 @@ import org.specs2.mutable._
 import org.specs2.specification.core.{Fragment, Fragments}
 
 object MultipartParserSpec extends Specification {
-  implicit val contextShift: ContextShift[IO] = IO.contextShift(Http4sSpec.TestExecutionContext)
+  private implicit val ioRuntime: IORuntime = Http4sSpec.TestIORuntime
 
   val boundary = Boundary("_5PHqf8_Pl1FCzBuT5o_mVZg36k67UYI")
 
@@ -565,7 +564,7 @@ object MultipartParserSpec extends Specification {
           val checkReachedTheEnd: IO[Boolean] = for {
             // This should be false until we drain the whole input.
             ref <- Ref[IO].of(false)
-            trackedInput = unspool(input, chunkSize) ++ Stream.eval_(ref.set(true))
+            trackedInput = unspool(input, chunkSize) ++ Stream.eval(ref.set(true)).drain
 
             _ <- trackedInput.through(multipartPipe(boundary)).compile.drain
 
@@ -604,9 +603,9 @@ object MultipartParserSpec extends Specification {
 
   multipartParserTests(
     "mixed file parser",
-    MultipartParser.parseStreamedFile[IO](_, Http4sSpec.TestBlocker),
-    MultipartParser.parseStreamedFile[IO](_, Http4sSpec.TestBlocker, _),
-    MultipartParser.parseToPartsStreamedFile[IO](_, Http4sSpec.TestBlocker)
+    MultipartParser.parseStreamedFile[IO](_),
+    MultipartParser.parseStreamedFile[IO](_, _),
+    MultipartParser.parseToPartsStreamedFile[IO](_)
   )
 
   "Multipart mixed file parser" should {
@@ -628,8 +627,7 @@ object MultipartParserSpec extends Specification {
 
       val boundaryTest = Boundary("RU(_9F(PcJK5+JMOPCAF6Aj4iSXvpJkWy):6s)YU0")
       val results =
-        unspool(input).through(
-          MultipartParser.parseStreamedFile[IO](boundaryTest, Http4sSpec.TestBlocker, maxParts = 1))
+        unspool(input).through(MultipartParser.parseStreamedFile[IO](boundaryTest, maxParts = 1))
 
       val multipartMaterialized = results.compile.last.map(_.get).unsafeRunSync()
       val headers =
@@ -660,11 +658,7 @@ object MultipartParserSpec extends Specification {
 
       val boundaryTest = Boundary("RU(_9F(PcJK5+JMOPCAF6Aj4iSXvpJkWy):6s)YU0")
       val results = unspool(input).through(
-        MultipartParser.parseStreamedFile[IO](
-          boundaryTest,
-          Http4sSpec.TestBlocker,
-          maxParts = 1,
-          failOnLimit = true))
+        MultipartParser.parseStreamedFile[IO](boundaryTest, maxParts = 1, failOnLimit = true))
 
       results.compile.last.map(_.get).unsafeRunSync() must throwA[MalformedMessageBodyFailure]
     }
diff --git a/tests/src/test/scala/org/http4s/multipart/MultipartSpec.scala b/tests/src/test/scala/org/http4s/multipart/MultipartSpec.scala
index 5554a4bf2f..57b8eab117 100644
--- a/tests/src/test/scala/org/http4s/multipart/MultipartSpec.scala
+++ b/tests/src/test/scala/org/http4s/multipart/MultipartSpec.scala
@@ -19,8 +19,10 @@ package multipart
 
 import cats._
 import cats.effect._
+import cats.effect.unsafe.IORuntime
 import cats.syntax.all._
 import fs2._
+
 import java.io.File
 import org.http4s.headers._
 import org.http4s.syntax.literals._
@@ -28,7 +30,7 @@ import org.http4s.EntityEncoder._
 import org.specs2.mutable.Specification
 
 class MultipartSpec extends Specification {
-  implicit val contextShift: ContextShift[IO] = IO.contextShift(Http4sSpec.TestExecutionContext)
+  private implicit val ioRuntime: IORuntime = Http4sSpec.TestIORuntime
 
   val url = uri"https://example.com/path/to/some/where"
 
@@ -90,7 +92,7 @@ class MultipartSpec extends Specification {
 
         val field1 = Part.formData[IO]("field1", "Text_Field_1")
         val field2 = Part
-          .fileData[IO]("image", file, Http4sSpec.TestBlocker, `Content-Type`(MediaType.image.png))
+          .fileData[IO]("image", file, `Content-Type`(MediaType.image.png))
 
         val multipart = Multipart[IO](Vector(field1, field2))
 
@@ -193,7 +195,7 @@ I am a big moose
   }
 
   multipartSpec("with default decoder")(implicitly)
-  multipartSpec("with mixed decoder")(MultipartDecoder.mixedMultipart[IO](Http4sSpec.TestBlocker))
+  multipartSpec("with mixed decoder")(MultipartDecoder.mixedMultipart[IO]())
 
   "Part" >> {
     def testPart[F[_]] = Part[F](Headers.empty, EmptyBody)