From 41860602e8e0494a749b63590efd9952dff7cd16 Mon Sep 17 00:00:00 2001 From: Daniel Bell Date: Fri, 4 Aug 2023 09:12:46 +0200 Subject: [PATCH] Remove dependency on rdf from storage (#4131) * Remove dependency on rdf from storage * don't compile with java 1.8 * no, it's the other ones which shouldn't use 1.8 * don't trigger storage build if rdf/kernel change * reduce storage scoverage threshold --- .github/workflows/ci-storage.yml | 2 - build.sbt | 10 ++-- .../epfl/bluebrain/nexus/storage/File.scala | 6 +-- .../nexus/storage/JsonLdCirceSupport.scala | 8 ++-- .../bluebrain/nexus/storage/MediaTypes.scala | 9 ++++ .../bluebrain/nexus/storage/Storages.scala | 26 ++++++++--- .../bluebrain/nexus/storage/UriUtils.scala | 25 ++++++++++ .../nexus/storage/config/Contexts.scala | 7 ++- .../storage/config/DeltaClientConfig.scala | 13 +++--- .../nexus/storage/config/Settings.scala | 13 ++---- .../nexus/storage/jsonld/JsonLdContext.scala | 40 ++++++++++++++++ .../nexus/storage/routes/instances.scala | 2 +- .../storage/routes/StorageRoutesSpec.scala | 46 ++++++++++--------- 13 files changed, 146 insertions(+), 61 deletions(-) create mode 100644 storage/src/main/scala/ch/epfl/bluebrain/nexus/storage/MediaTypes.scala create mode 100644 storage/src/main/scala/ch/epfl/bluebrain/nexus/storage/UriUtils.scala create mode 100644 storage/src/main/scala/ch/epfl/bluebrain/nexus/storage/jsonld/JsonLdContext.scala diff --git a/.github/workflows/ci-storage.yml b/.github/workflows/ci-storage.yml index 4ddceeb5e1..3149158617 100644 --- a/.github/workflows/ci-storage.yml +++ b/.github/workflows/ci-storage.yml @@ -2,8 +2,6 @@ name: Storage Integration Service on: pull_request: paths: - - 'delta/kernel/**' - - 'delta/rdf/**' - 'storage/**' - 'build.sbt' - 'project/**' diff --git a/build.sbt b/build.sbt index 9ef9c1639c..81a8d46115 100755 --- a/build.sbt +++ b/build.sbt @@ -21,6 +21,7 @@ val akkaCorsVersion = "1.2.0" val akkaVersion = "2.6.21" val alpakkaVersion = "3.0.4" val apacheCompressVersion = "1.23.0" +val apacheIoVersion = "1.3.2" val awsSdkVersion = "2.17.184" val byteBuddyAgentVersion = "1.10.17" val betterMonadicForVersion = "0.3.1" @@ -76,6 +77,7 @@ lazy val alpakkaFile = "com.lightbend.akka" %% "akka-stream-alp lazy val alpakkaSse = "com.lightbend.akka" %% "akka-stream-alpakka-sse" % alpakkaVersion lazy val alpakkaS3 = "com.lightbend.akka" %% "akka-stream-alpakka-s3" % alpakkaVersion lazy val apacheCompress = "org.apache.commons" % "commons-compress" % apacheCompressVersion +lazy val apacheIo = "org.apache.commons" % "commons-io" % apacheIoVersion lazy val awsSdk = "software.amazon.awssdk" % "s3" % awsSdkVersion lazy val betterMonadicFor = "com.olegpy" %% "better-monadic-for" % betterMonadicForVersion lazy val byteBuddyAgent = "net.bytebuddy" % "byte-buddy-agent" % byteBuddyAgentVersion @@ -203,7 +205,6 @@ lazy val kernel = project .settings(name := "delta-kernel", moduleName := "delta-kernel") .settings(shared, compilation, coverage, release, assertJavaVersion) .settings( - javaSpecificationVersion := "1.8", libraryDependencies ++= Seq( caffeine, catsRetry, @@ -227,7 +228,6 @@ lazy val testkit = project .settings(name := "delta-testkit", moduleName := "delta-testkit") .settings(shared, compilation, coverage, release, assertJavaVersion) .settings( - javaSpecificationVersion := "1.8", coverageMinimumStmtTotal := 0, libraryDependencies ++= Seq( akkaActorTyped, // Needed to create Uri @@ -282,7 +282,6 @@ lazy val rdf = project moduleName := "delta-rdf" ) .settings( - javaSpecificationVersion := "1.8", libraryDependencies ++= Seq( akkaActorTyped, // Needed to create Uri akkaHttpCore, @@ -723,8 +722,7 @@ lazy val cargo = taskKey[(File, String)]("Run Cargo to build 'nexus-fixer'") lazy val storage = project .in(file("storage")) .enablePlugins(UniversalPlugin, JavaAppPackaging, JavaAgent, DockerPlugin, BuildInfoPlugin) - .settings(shared, compilation, assertJavaVersion, kamonSettings, storageAssemblySettings, coverage, release, servicePackaging) - .dependsOn(rdf) + .settings(shared, compilation, assertJavaVersion, kamonSettings, storageAssemblySettings, coverage, release, servicePackaging, coverageMinimumStmtTotal := 75) .settings(cargo := { import scala.sys.process._ @@ -747,6 +745,7 @@ lazy val storage = project javaSpecificationVersion := "1.8", libraryDependencies ++= Seq( apacheCompress, + apacheIo, akkaHttp, akkaHttpCirce, akkaStream, @@ -758,6 +757,7 @@ lazy val storage = project circeGenericExtras, logback, monixEval, + pureconfig, scalaLogging, akkaHttpTestKit % Test, akkaTestKit % Test, diff --git a/storage/src/main/scala/ch/epfl/bluebrain/nexus/storage/File.scala b/storage/src/main/scala/ch/epfl/bluebrain/nexus/storage/File.scala index 0140c5499d..46a55c0917 100644 --- a/storage/src/main/scala/ch/epfl/bluebrain/nexus/storage/File.scala +++ b/storage/src/main/scala/ch/epfl/bluebrain/nexus/storage/File.scala @@ -1,13 +1,13 @@ package ch.epfl.bluebrain.nexus.storage import akka.http.scaladsl.model.{ContentType, Uri} -import ch.epfl.bluebrain.nexus.delta.rdf.implicits._ import ch.epfl.bluebrain.nexus.storage.config.Contexts.resourceCtxIri -import scala.annotation.nowarn +import ch.epfl.bluebrain.nexus.storage.jsonld.JsonLdContext.addContext import io.circe.generic.extras.Configuration import io.circe.generic.extras.semiauto._ import io.circe.{Decoder, Encoder} +import scala.annotation.nowarn import scala.util.Try // $COVERAGE-OFF$ @@ -61,7 +61,7 @@ object File { Decoder.decodeString.emap(ContentType.parse(_).left.map(_.mkString("\n"))) implicit val fileAttrEncoder: Encoder[FileAttributes] = - deriveConfiguredEncoder[FileAttributes].mapJson(_.addContext(resourceCtxIri)) + deriveConfiguredEncoder[FileAttributes].mapJson(addContext(_, resourceCtxIri)) implicit val fileAttrDecoder: Decoder[FileAttributes] = deriveConfiguredDecoder[FileAttributes] } diff --git a/storage/src/main/scala/ch/epfl/bluebrain/nexus/storage/JsonLdCirceSupport.scala b/storage/src/main/scala/ch/epfl/bluebrain/nexus/storage/JsonLdCirceSupport.scala index b9ce5e839c..e8e2c23223 100644 --- a/storage/src/main/scala/ch/epfl/bluebrain/nexus/storage/JsonLdCirceSupport.scala +++ b/storage/src/main/scala/ch/epfl/bluebrain/nexus/storage/JsonLdCirceSupport.scala @@ -3,8 +3,8 @@ package ch.epfl.bluebrain.nexus.storage import akka.http.scaladsl.marshalling.{Marshaller, ToEntityMarshaller} import akka.http.scaladsl.model.MediaTypes.`application/json` import akka.http.scaladsl.model.{ContentTypeRange, HttpEntity} -import ch.epfl.bluebrain.nexus.delta.rdf.RdfMediaTypes import ch.epfl.bluebrain.nexus.storage.JsonLdCirceSupport.{sortKeys, OrderedKeys} +import ch.epfl.bluebrain.nexus.storage.MediaTypes.`application/ld+json` import de.heikoseeberger.akkahttpcirce.FailFastCirceSupport import io.circe.syntax._ import io.circe.{Encoder, Json, JsonObject, Printer} @@ -19,7 +19,7 @@ import scala.collection.immutable.Seq trait JsonLdCirceSupport extends FailFastCirceSupport { override def unmarshallerContentTypes: Seq[ContentTypeRange] = - List(`application/json`, RdfMediaTypes.`application/ld+json`) + List(`application/json`, `application/ld+json`) /** * `A` => HTTP entity @@ -46,8 +46,8 @@ trait JsonLdCirceSupport extends FailFastCirceSupport { printer: Printer = Printer.noSpaces.copy(dropNullValues = true), keys: OrderedKeys = OrderedKeys() ): ToEntityMarshaller[Json] = - Marshaller.withFixedContentType(RdfMediaTypes.`application/ld+json`) { json => - HttpEntity(RdfMediaTypes.`application/ld+json`, printer.print(sortKeys(json))) + Marshaller.withFixedContentType(`application/ld+json`) { json => + HttpEntity(`application/ld+json`, printer.print(sortKeys(json))) } } diff --git a/storage/src/main/scala/ch/epfl/bluebrain/nexus/storage/MediaTypes.scala b/storage/src/main/scala/ch/epfl/bluebrain/nexus/storage/MediaTypes.scala new file mode 100644 index 0000000000..90886fda16 --- /dev/null +++ b/storage/src/main/scala/ch/epfl/bluebrain/nexus/storage/MediaTypes.scala @@ -0,0 +1,9 @@ +package ch.epfl.bluebrain.nexus.storage + +import akka.http.scaladsl.model.MediaType +import akka.http.scaladsl.model.HttpCharsets.`UTF-8` + +object MediaTypes { + final val `application/ld+json`: MediaType.WithFixedCharset = + MediaType.applicationWithFixedCharset("ld+json", `UTF-8`, "jsonld") +} diff --git a/storage/src/main/scala/ch/epfl/bluebrain/nexus/storage/Storages.scala b/storage/src/main/scala/ch/epfl/bluebrain/nexus/storage/Storages.scala index 8500aee68f..83827b5803 100644 --- a/storage/src/main/scala/ch/epfl/bluebrain/nexus/storage/Storages.scala +++ b/storage/src/main/scala/ch/epfl/bluebrain/nexus/storage/Storages.scala @@ -4,14 +4,12 @@ import java.net.URLDecoder import java.nio.file.StandardCopyOption._ import java.nio.file.{Files, Path, Paths} import java.security.MessageDigest - import akka.http.scaladsl.model.Uri import akka.stream.Materializer import akka.stream.alpakka.file.scaladsl.Directory import akka.stream.scaladsl.{FileIO, Keep, Sink} import cats.effect.Effect import cats.implicits._ -import ch.epfl.bluebrain.nexus.delta.rdf.syntax._ import ch.epfl.bluebrain.nexus.storage.File._ import ch.epfl.bluebrain.nexus.storage.Rejection.{PathAlreadyExists, PathContainsLinks, PathNotFound} import ch.epfl.bluebrain.nexus.storage.StorageError.{InternalError, PathInvalid, PermissionsFixingFailed} @@ -22,6 +20,7 @@ import ch.epfl.bluebrain.nexus.storage.attributes.AttributesCache import ch.epfl.bluebrain.nexus.storage.attributes.AttributesComputation._ import ch.epfl.bluebrain.nexus.storage.config.AppConfig.{DigestConfig, StorageConfig} +import scala.annotation.tailrec import scala.concurrent.{ExecutionContext, Future} import scala.sys.process._ import scala.util.{Success, Try} @@ -116,6 +115,21 @@ trait Storages[F[_], Source] { object Storages { + /** + * Checks if the ''target'' path is a descendant of the ''parent'' path. E.g.: path = /some/my/path ; parent = /some + * will return true E.g.: path = /some/my/path ; parent = /other will return false + */ + private def descendantOf(target: Path, parent: Path): Boolean = + inner(parent, target.getParent) + + @tailrec + @SuppressWarnings(Array("NullParameter")) + private def inner(parent: Path, child: Path): Boolean = { + if (child == null) false + else if (parent == child) true + else inner(parent, child.getParent) + } + sealed trait BucketExistence sealed trait PathExistence @@ -162,7 +176,7 @@ object Storages { def pathExists(name: String, relativeFilePath: Uri.Path): PathExistence = { val path = filePath(name, relativeFilePath) - if (Files.exists(path) && Files.isReadable(path) && path.descendantOf(basePath(name))) PathExists + if (Files.exists(path) && Files.isReadable(path) && descendantOf(path, basePath(name))) PathExists else PathDoesNotExist } @@ -172,7 +186,7 @@ object Storages { source: AkkaSource )(implicit bucketEv: BucketExists, pathEv: PathDoesNotExist): F[FileAttributes] = { val absFilePath = filePath(name, relativeFilePath) - if (absFilePath.descendantOf(basePath(name))) + if (descendantOf(absFilePath, basePath(name))) F.fromTry(Try(Files.createDirectories(absFilePath.getParent))) >> F.fromTry(Try(MessageDigest.getInstance(digestConfig.algorithm))).flatMap { msgDigest => source @@ -243,9 +257,9 @@ object Storages { fixPermissions(absSourcePath).flatMap { fixPermsResult => if (!Files.exists(absSourcePath)) F.pure(Left(PathNotFound(name, sourceRelativePath))) - else if (!absSourcePath.descendantOf(bucketPath) || absSourcePath.descendantOf(bucketProtectedPath)) + else if (!descendantOf(absSourcePath, bucketPath) || descendantOf(absSourcePath, bucketProtectedPath)) F.pure(Left(PathNotFound(name, sourceRelativePath))) - else if (!absDestPath.descendantOf(bucketProtectedPath)) + else if (!descendantOf(absDestPath, bucketProtectedPath)) F.raiseError(PathInvalid(name, destRelativePath)) else if (Files.exists(absDestPath)) F.pure(Left(PathAlreadyExists(name, destRelativePath))) diff --git a/storage/src/main/scala/ch/epfl/bluebrain/nexus/storage/UriUtils.scala b/storage/src/main/scala/ch/epfl/bluebrain/nexus/storage/UriUtils.scala new file mode 100644 index 0000000000..068c7064de --- /dev/null +++ b/storage/src/main/scala/ch/epfl/bluebrain/nexus/storage/UriUtils.scala @@ -0,0 +1,25 @@ +package ch.epfl.bluebrain.nexus.storage + +import akka.http.scaladsl.model.Uri + +object UriUtils { + + /** + * Adds a segment to the end of the Uri + */ + def addPath(uri: Uri, segment: String): Uri = { + if (segment.trim.isEmpty) uri + else { + val segmentStartsWithSlash = segment.startsWith("/") + val uriEndsWithSlash = uri.path.endsWithSlash + if (uriEndsWithSlash && segmentStartsWithSlash) + uri.copy(path = uri.path + segment.drop(1)) + else if (uriEndsWithSlash) + uri.copy(path = uri.path + segment) + else if (segmentStartsWithSlash) + uri.copy(path = uri.path / segment.drop(1)) + else + uri.copy(path = uri.path / segment) + } + } +} diff --git a/storage/src/main/scala/ch/epfl/bluebrain/nexus/storage/config/Contexts.scala b/storage/src/main/scala/ch/epfl/bluebrain/nexus/storage/config/Contexts.scala index 47c3b298df..1f6f1ce6dc 100644 --- a/storage/src/main/scala/ch/epfl/bluebrain/nexus/storage/config/Contexts.scala +++ b/storage/src/main/scala/ch/epfl/bluebrain/nexus/storage/config/Contexts.scala @@ -1,13 +1,12 @@ package ch.epfl.bluebrain.nexus.storage.config -import ch.epfl.bluebrain.nexus.delta.rdf.IriOrBNode.Iri -import ch.epfl.bluebrain.nexus.delta.rdf.implicits._ +import akka.http.scaladsl.model.Uri object Contexts { private val base = "https://bluebrain.github.io/nexus/contexts/" - val errorCtxIri: Iri = iri"${base}error.json" - val resourceCtxIri: Iri = iri"${base}resource.json" + val errorCtxIri: Uri = s"${base}error.json" + val resourceCtxIri: Uri = s"${base}resource.json" } diff --git a/storage/src/main/scala/ch/epfl/bluebrain/nexus/storage/config/DeltaClientConfig.scala b/storage/src/main/scala/ch/epfl/bluebrain/nexus/storage/config/DeltaClientConfig.scala index 3fa49e58e4..ea98fe5d61 100644 --- a/storage/src/main/scala/ch/epfl/bluebrain/nexus/storage/config/DeltaClientConfig.scala +++ b/storage/src/main/scala/ch/epfl/bluebrain/nexus/storage/config/DeltaClientConfig.scala @@ -1,6 +1,7 @@ package ch.epfl.bluebrain.nexus.storage.config -import ch.epfl.bluebrain.nexus.delta.rdf.IriOrBNode.Iri +import akka.http.scaladsl.model.Uri +import ch.epfl.bluebrain.nexus.storage.UriUtils.addPath /** * Configuration for DeltaClient identities endpoint. @@ -13,11 +14,11 @@ import ch.epfl.bluebrain.nexus.delta.rdf.IriOrBNode.Iri * the prefix */ final case class DeltaClientConfig( - publicIri: Iri, - internalIri: Iri, + publicIri: Uri, + internalIri: Uri, prefix: String ) { - lazy val baseInternalIri: Iri = internalIri / prefix - lazy val basePublicIri: Iri = publicIri / prefix - lazy val identitiesIri: Iri = baseInternalIri / "identities" + lazy val baseInternalIri: Uri = addPath(internalIri, prefix) + lazy val basePublicIri: Uri = addPath(publicIri, prefix) + lazy val identitiesIri: Uri = addPath(baseInternalIri, "identities") } diff --git a/storage/src/main/scala/ch/epfl/bluebrain/nexus/storage/config/Settings.scala b/storage/src/main/scala/ch/epfl/bluebrain/nexus/storage/config/Settings.scala index b606f4d492..5bf49ba40d 100644 --- a/storage/src/main/scala/ch/epfl/bluebrain/nexus/storage/config/Settings.scala +++ b/storage/src/main/scala/ch/epfl/bluebrain/nexus/storage/config/Settings.scala @@ -1,17 +1,14 @@ package ch.epfl.bluebrain.nexus.storage.config -import java.nio.file.{Path, Paths} - import akka.actor.{ExtendedActorSystem, Extension, ExtensionId, ExtensionIdProvider} import akka.http.scaladsl.model.Uri -import ch.epfl.bluebrain.nexus.delta.rdf.IriOrBNode.Iri - -import scala.annotation.nowarn -import ch.epfl.bluebrain.nexus.delta.rdf.implicits._ import com.typesafe.config.Config -import pureconfig.generic.auto._ import pureconfig.ConvertHelpers._ import pureconfig._ +import pureconfig.generic.auto._ + +import java.nio.file.{Path, Paths} +import scala.annotation.nowarn /** * Akka settings extension to expose application configuration. It typically uses the configuration instance of the @@ -27,8 +24,6 @@ class Settings(config: Config) extends Extension { val appConfig: AppConfig = { implicit val uriConverter: ConfigConvert[Uri] = ConfigConvert.viaString[Uri](catchReadError(s => Uri(s)), _.toString) - implicit val iriConverter: ConfigConvert[Iri] = - ConfigConvert.viaString[Iri](catchReadError(s => iri"$s"), _.toString) implicit val pathConverter: ConfigConvert[Path] = ConfigConvert.viaString[Path](catchReadError(s => Paths.get(s)), _.toString) ConfigSource.fromConfig(config).at("app").loadOrThrow[AppConfig] diff --git a/storage/src/main/scala/ch/epfl/bluebrain/nexus/storage/jsonld/JsonLdContext.scala b/storage/src/main/scala/ch/epfl/bluebrain/nexus/storage/jsonld/JsonLdContext.scala new file mode 100644 index 0000000000..3bf02090ec --- /dev/null +++ b/storage/src/main/scala/ch/epfl/bluebrain/nexus/storage/jsonld/JsonLdContext.scala @@ -0,0 +1,40 @@ +package ch.epfl.bluebrain.nexus.storage.jsonld + +import akka.http.scaladsl.model.Uri +import io.circe.Json + +object JsonLdContext { + + object keywords { + val context = "@context" + } + + /** + * Adds a context Iri to an existing @context, or creates an @context with the Iri as a value. + */ + def addContext(json: Json, contextIri: Uri): Json = { + val jUriString = Json.fromString(contextIri.toString) + + json.asObject match { + case Some(obj) => + val updated = obj(keywords.context) match { + case None => obj.add(keywords.context, jUriString) + case Some(ctxValue) => + (ctxValue.asObject, ctxValue.asArray, ctxValue.asString) match { + case (Some(co), _, _) if co.isEmpty => obj.add(keywords.context, jUriString) + case (_, Some(ca), _) if ca.isEmpty => obj.add(keywords.context, jUriString) + case (_, _, Some(cs)) if cs.isEmpty => obj.add(keywords.context, jUriString) + case (Some(co), _, _) if !co.values.exists(_ == jUriString) => + obj.add(keywords.context, Json.arr(ctxValue, jUriString)) + case (_, Some(ca), _) if !ca.contains(jUriString) => + obj.add(keywords.context, Json.fromValues(ca :+ jUriString)) + case (_, _, Some(cs)) if cs != contextIri.toString => + obj.add(keywords.context, Json.arr(ctxValue, jUriString)) + case _ => obj + } + } + Json.fromJsonObject(updated) + case None => json + } + } +} diff --git a/storage/src/main/scala/ch/epfl/bluebrain/nexus/storage/routes/instances.scala b/storage/src/main/scala/ch/epfl/bluebrain/nexus/storage/routes/instances.scala index edf6ae208e..d8a34f2966 100644 --- a/storage/src/main/scala/ch/epfl/bluebrain/nexus/storage/routes/instances.scala +++ b/storage/src/main/scala/ch/epfl/bluebrain/nexus/storage/routes/instances.scala @@ -4,7 +4,6 @@ import akka.http.scaladsl.marshalling.GenericMarshallers.eitherMarshaller import akka.http.scaladsl.marshalling._ import akka.http.scaladsl.model.MediaTypes._ import akka.http.scaladsl.model._ -import ch.epfl.bluebrain.nexus.delta.rdf.RdfMediaTypes._ import ch.epfl.bluebrain.nexus.storage.JsonLdCirceSupport.sortKeys import ch.epfl.bluebrain.nexus.storage.JsonLdCirceSupport.OrderedKeys import ch.epfl.bluebrain.nexus.storage.Rejection @@ -14,6 +13,7 @@ import io.circe._ import io.circe.syntax._ import monix.eval.Task import monix.execution.Scheduler +import ch.epfl.bluebrain.nexus.storage.MediaTypes.`application/ld+json` import scala.collection.immutable.Seq import scala.concurrent.Future diff --git a/storage/src/test/scala/ch/epfl/bluebrain/nexus/storage/routes/StorageRoutesSpec.scala b/storage/src/test/scala/ch/epfl/bluebrain/nexus/storage/routes/StorageRoutesSpec.scala index a60f4c37a6..e543e21d59 100644 --- a/storage/src/test/scala/ch/epfl/bluebrain/nexus/storage/routes/StorageRoutesSpec.scala +++ b/storage/src/test/scala/ch/epfl/bluebrain/nexus/storage/routes/StorageRoutesSpec.scala @@ -1,7 +1,5 @@ package ch.epfl.bluebrain.nexus.storage.routes -import java.nio.file.Paths -import java.util.regex.Pattern.quote import akka.http.scaladsl.model.ContentTypes._ import akka.http.scaladsl.model.MediaRanges._ import akka.http.scaladsl.model.MediaTypes.{`application/octet-stream`, `image/jpeg`} @@ -14,15 +12,15 @@ import akka.http.scaladsl.server.Route import akka.http.scaladsl.testkit.ScalatestRouteTest import akka.stream.scaladsl.Source import akka.util.ByteString -import ch.epfl.bluebrain.nexus.delta.rdf.implicits._ -import ch.epfl.bluebrain.nexus.storage.File.{Digest, FileAttributes} import ch.epfl.bluebrain.nexus.storage.DeltaIdentitiesClient.Caller import ch.epfl.bluebrain.nexus.storage.DeltaIdentitiesClient.Identity.Anonymous +import ch.epfl.bluebrain.nexus.storage.File.{Digest, FileAttributes} import ch.epfl.bluebrain.nexus.storage.Rejection.PathNotFound import ch.epfl.bluebrain.nexus.storage.StorageError.InternalError import ch.epfl.bluebrain.nexus.storage.Storages.BucketExistence.{BucketDoesNotExist, BucketExists} import ch.epfl.bluebrain.nexus.storage.Storages.PathExistence.{PathDoesNotExist, PathExists} import ch.epfl.bluebrain.nexus.storage.config.{AppConfig, Settings} +import ch.epfl.bluebrain.nexus.storage.jsonld.JsonLdContext.addContext import ch.epfl.bluebrain.nexus.storage.routes.instances._ import ch.epfl.bluebrain.nexus.storage.utils.{Randomness, Resources} import ch.epfl.bluebrain.nexus.storage.{AkkaSource, DeltaIdentitiesClient, Storages} @@ -34,6 +32,8 @@ import org.scalatest.concurrent.ScalaFutures import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpecLike +import java.nio.file.Paths +import java.util.regex.Pattern.quote import scala.concurrent.duration._ class StorageRoutesSpec @@ -58,7 +58,7 @@ class StorageRoutesSpec trait Ctx { val name = genString() - val resourceCtx = iri"https://bluebrain.github.io/nexus/contexts/resource.json" + val resourceCtx = "https://bluebrain.github.io/nexus/contexts/resource.json" } trait RandomFile extends Ctx { @@ -402,14 +402,16 @@ class StorageRoutesSpec "_algorithm" -> Json.fromString(attributes.digest.algorithm), "_value" -> Json.fromString(attributes.digest.value) ) - responseAs[Json] shouldEqual Json - .obj( - "_bytes" -> Json.fromLong(attributes.bytes), - "_digest" -> digestJson, - "_location" -> Json.fromString(attributes.location.toString()), - "_mediaType" -> Json.fromString(attributes.mediaType.toString) - ) - .addContext(resourceCtx) + responseAs[Json] shouldEqual addContext( + Json + .obj( + "_bytes" -> Json.fromLong(attributes.bytes), + "_digest" -> digestJson, + "_location" -> Json.fromString(attributes.location.toString()), + "_mediaType" -> Json.fromString(attributes.mediaType.toString) + ), + resourceCtx + ) storages.getAttributes(name, filePathUri) wasCalled once } } @@ -425,14 +427,16 @@ class StorageRoutesSpec Get(s"/v1/buckets/$name/attributes/$filename") ~> Accept(`*/*`) ~> route ~> check { status shouldEqual Accepted val digestJson = Json.obj("_algorithm" -> Json.fromString(""), "_value" -> Json.fromString("")) - responseAs[Json] shouldEqual Json - .obj( - "_bytes" -> Json.fromLong(0L), - "_digest" -> digestJson, - "_location" -> Json.fromString(s"file://${filePathUri.toString().toLowerCase}"), - "_mediaType" -> Json.fromString(`application/octet-stream`.toString()) - ) - .addContext(resourceCtx) + responseAs[Json] shouldEqual addContext( + Json + .obj( + "_bytes" -> Json.fromLong(0L), + "_digest" -> digestJson, + "_location" -> Json.fromString(s"file://${filePathUri.toString().toLowerCase}"), + "_mediaType" -> Json.fromString(`application/octet-stream`.toString()) + ), + resourceCtx + ) storages.getAttributes(name, filePathUri) wasCalled once } }