aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvlad <vlad@drivergrp.com>2016-09-09 14:37:33 -0700
committervlad <vlad@drivergrp.com>2016-09-09 14:37:33 -0700
commit968a702c359cd1de3359109edda6af5dd26fc74a (patch)
tree0f336555fe3caad3c77855c4ae9a81cd37c29aaf
parenta39ab2cb0e19f84176513d7b1e145351c3ceef8b (diff)
downloaddriver-core-968a702c359cd1de3359109edda6af5dd26fc74a.tar.gz
driver-core-968a702c359cd1de3359109edda6af5dd26fc74a.tar.bz2
driver-core-968a702c359cd1de3359109edda6af5dd26fc74a.zip
14 new test + Couple of bug fixes
-rw-r--r--src/main/scala/com/drivergrp/core/core.scala4
-rw-r--r--src/main/scala/com/drivergrp/core/file.scala5
-rw-r--r--src/test/scala/com/drivergrp/core/AuthTest.scala52
-rw-r--r--src/test/scala/com/drivergrp/core/CoreTest.scala32
-rw-r--r--src/test/scala/com/drivergrp/core/FileTest.scala126
-rw-r--r--src/test/scala/com/drivergrp/core/GeneratorsTest.scala28
-rw-r--r--src/test/scala/com/drivergrp/core/JsonTest.scala61
7 files changed, 303 insertions, 5 deletions
diff --git a/src/main/scala/com/drivergrp/core/core.scala b/src/main/scala/com/drivergrp/core/core.scala
index f5f79df..158447f 100644
--- a/src/main/scala/com/drivergrp/core/core.scala
+++ b/src/main/scala/com/drivergrp/core/core.scala
@@ -28,7 +28,7 @@ package object core {
def apply[Tag](value: Long) = value.asInstanceOf[Id[Tag]]
}
implicit def idEqual[T]: Equal[Id[T]] = Equal.equal[Id[T]](_ == _)
- implicit def idOrdering[T]: Ordering[Id[T]] = Ordering.by(identity)
+ implicit def idOrdering[T]: Ordering[Id[T]] = Ordering.by(i => i: Long)
type Name[+Tag] = String @@ Tag
object Name {
@@ -36,7 +36,7 @@ package object core {
}
implicit def nameEqual[T]: Equal[Name[T]] = Equal.equal[Name[T]](_ == _)
- implicit def nameOrdering[T]: Ordering[Name[T]] = Ordering.by(identity)
+ implicit def nameOrdering[T]: Ordering[Name[T]] = Ordering.by(n => n: String)
object revision {
final case class Revision[T](id: String)
diff --git a/src/main/scala/com/drivergrp/core/file.scala b/src/main/scala/com/drivergrp/core/file.scala
index 2c6a990..20bd36e 100644
--- a/src/main/scala/com/drivergrp/core/file.scala
+++ b/src/main/scala/com/drivergrp/core/file.scala
@@ -94,9 +94,8 @@ object file {
result.isTruncated
} flatMap { result =>
result.getObjectSummaries.asScala.toList.map { summary =>
- val file = new File(summary.getKey)
- FileLink(Name[File](file.getName),
- Paths.get(file.getPath),
+ FileLink(Name[File](summary.getKey),
+ Paths.get(path.toString + "/" + summary.getKey),
Revision[File](summary.getETag),
Time(summary.getLastModified.getTime))
} filterNot isInSubFolder(path)
diff --git a/src/test/scala/com/drivergrp/core/AuthTest.scala b/src/test/scala/com/drivergrp/core/AuthTest.scala
new file mode 100644
index 0000000..7725a45
--- /dev/null
+++ b/src/test/scala/com/drivergrp/core/AuthTest.scala
@@ -0,0 +1,52 @@
+package com.drivergrp.core
+
+import com.drivergrp.core.auth._
+import akka.http.scaladsl.testkit.ScalatestRouteTest
+import akka.http.scaladsl.server._
+import Directives._
+import akka.http.scaladsl.model.headers.RawHeader
+import org.scalatest.mock.MockitoSugar
+import org.scalatest.{FlatSpec, Matchers}
+
+class AuthTest extends FlatSpec with Matchers with MockitoSugar with ScalatestRouteTest {
+
+ "'authorize' directive" should "throw error is auth token is not in the request" in {
+
+ Get("/naive/attempt") ~>
+ auth.directives.authorize(CanSignOutReport) { authToken => complete("Never going to be here") } ~>
+ check {
+ handled shouldBe false
+ rejections should contain (MissingHeaderRejection("WWW-Authenticate"))
+ }
+ }
+
+ it should "throw error is authorized user is not having the requested permission" in {
+
+ val referenceAuthToken = AuthToken(Base64("I am a pathologist's token"))
+
+ Post("/administration/attempt").addHeader(
+ RawHeader(auth.directives.AuthenticationTokenHeader, s"Macaroon ${referenceAuthToken.value.value}")
+ ) ~>
+ auth.directives.authorize(CanAssignRoles) { authToken => complete("Never going to get here") } ~>
+ check {
+ handled shouldBe false
+ rejections should contain (ValidationRejection("User does not have the required permission CanAssignRoles", None))
+ }
+ }
+
+ it should "pass and retrieve the token to client code, if token is in request and user has permission" in {
+
+ val referenceAuthToken = AuthToken(Base64("I am token"))
+
+ Get("/valid/attempt/?a=2&b=5").addHeader(
+ RawHeader(auth.directives.AuthenticationTokenHeader, s"Macaroon ${referenceAuthToken.value.value}")
+ ) ~>
+ auth.directives.authorize(CanSignOutReport) { authToken =>
+ complete("Alright, \"" + authToken.value.value + "\" is handled")
+ } ~>
+ check {
+ handled shouldBe true
+ responseAs[String] shouldBe "Alright, \"Macaroon I am token\" is handled"
+ }
+ }
+}
diff --git a/src/test/scala/com/drivergrp/core/CoreTest.scala b/src/test/scala/com/drivergrp/core/CoreTest.scala
index 005cda5..b944ebb 100644
--- a/src/test/scala/com/drivergrp/core/CoreTest.scala
+++ b/src/test/scala/com/drivergrp/core/CoreTest.scala
@@ -2,6 +2,7 @@ package com.drivergrp.core
import java.io.ByteArrayOutputStream
+import com.drivergrp.core.revision.Revision
import org.scalatest.mock.MockitoSugar
import org.scalatest.{FlatSpec, Matchers}
import org.mockito.Mockito._
@@ -27,4 +28,35 @@ class CoreTest extends FlatSpec with Matchers with MockitoSugar {
verify(baos).close()
}
+
+ "Id" should "have equality and ordering working correctly" in {
+
+ (Id[String](1234213L) === Id[String](1234213L)) should be (true)
+ (Id[String](1234213L) === Id[String](213414L)) should be (false)
+ (Id[String](213414L) === Id[String](1234213L)) should be (false)
+
+
+ Seq(Id[String](4L), Id[String](3L), Id[String](2L), Id[String](1L)).sorted should contain
+ theSameElementsInOrderAs (Seq(Id[String](1L), Id[String](2L), Id[String](3L), Id[String](4L)))
+ }
+
+ "Name" should "have equality and ordering working correctly" in {
+
+ (Name[String]("foo") === Name[String]("foo")) should be (true)
+ (Name[String]("foo") === Name[String]("bar")) should be (false)
+ (Name[String]("bar") === Name[String]("foo")) should be (false)
+
+ Seq(Name[String]("d"), Name[String]("cc"), Name[String]("a"), Name[String]("bbb")).sorted should contain
+ theSameElementsInOrderAs (Seq(Name[String]("a"), Name[String]("bbb"), Name[String]("cc"), Name[String]("d")))
+ }
+
+ "Revision" should "have equality working correctly" in {
+
+ val bla = Revision[String]("85569dab-a3dc-401b-9f95-d6fb4162674b")
+ val foo = Revision[String]("f54b3558-bdcd-4646-a14b-8beb11f6b7c4")
+
+ (bla === bla) should be (true)
+ (bla === foo) should be (false)
+ (foo === bla) should be (false)
+ }
}
diff --git a/src/test/scala/com/drivergrp/core/FileTest.scala b/src/test/scala/com/drivergrp/core/FileTest.scala
new file mode 100644
index 0000000..adf38e2
--- /dev/null
+++ b/src/test/scala/com/drivergrp/core/FileTest.scala
@@ -0,0 +1,126 @@
+package com.drivergrp.core
+
+import java.io.File
+import java.nio.file.Paths
+
+import com.amazonaws.services.s3.AmazonS3
+import com.amazonaws.services.s3.model._
+import com.drivergrp.core.file.{FileSystemStorage, S3Storage}
+import org.scalatest.mock.MockitoSugar
+import org.scalatest.{FlatSpec, Matchers}
+import org.mockito.Mockito._
+import org.mockito.Matchers._
+
+import scala.concurrent.Await
+import scala.concurrent.duration._
+
+class FileTest extends FlatSpec with Matchers with MockitoSugar {
+
+ "S3 Storage" should "create and download local files and do other operations" in {
+ import scala.collection.JavaConverters._
+
+ val tempDir = System.getProperty("java.io.tmpdir")
+ val sourceTestFile = generateTestLocalFile(tempDir)
+ val testFileName = "uploadTestFile"
+
+ val randomFolderName = java.util.UUID.randomUUID().toString
+ val testDirPath = Paths.get(randomFolderName)
+ val testFilePath = Paths.get(randomFolderName, testFileName)
+
+ val testBucket = Name[Bucket]("IamBucket")
+
+ val s3PutMock = mock[PutObjectResult]
+ when(s3PutMock.getETag).thenReturn("IAmEtag")
+
+ val s3ObjectSummaryMock = mock[S3ObjectSummary]
+ when(s3ObjectSummaryMock.getKey).thenReturn(testFileName)
+ when(s3ObjectSummaryMock.getETag).thenReturn("IAmEtag")
+ when(s3ObjectSummaryMock.getLastModified).thenReturn(new java.util.Date())
+
+ val s3ResultsMock = mock[ListObjectsV2Result]
+ when(s3ResultsMock.getNextContinuationToken).thenReturn("continuationToken")
+ when(s3ResultsMock.isTruncated).thenReturn(
+ false, // before file created it is empty (zero pages)
+ true, false, // after file is uploaded it contains this one file (one page)
+ false) // after file is deleted it is empty (zero pages) again
+ when(s3ResultsMock.getObjectSummaries).thenReturn(
+ // before file created it is empty, `getObjectSummaries` is never called
+ List[S3ObjectSummary](s3ObjectSummaryMock).asJava, // after file is uploaded it contains this one file
+ List.empty[S3ObjectSummary].asJava) // after file is deleted it is empty again
+
+ val s3ObjectMetadataMock = mock[ObjectMetadata]
+ val amazonS3Mock = mock[AmazonS3]
+ when(amazonS3Mock.listObjectsV2(any[ListObjectsV2Request]())).thenReturn(s3ResultsMock)
+ when(amazonS3Mock.putObject(testBucket, testFilePath.toString, sourceTestFile)).thenReturn(s3PutMock)
+ when(amazonS3Mock.getObject(any[GetObjectRequest](), any[File]())).thenReturn(s3ObjectMetadataMock)
+
+ val s3Storage = new S3Storage(amazonS3Mock, testBucket, scala.concurrent.ExecutionContext.global)
+
+ val filesBefore = Await.result(s3Storage.list(testDirPath).run, 10 seconds)
+ filesBefore shouldBe empty
+
+ Await.result(s3Storage.upload(sourceTestFile, testFilePath), 10 seconds)
+
+ val filesAfterUpload = Await.result(s3Storage.list(testDirPath).run, 10 seconds)
+ filesAfterUpload.size should be (1)
+ val uploadedFileLine = filesAfterUpload.head
+ uploadedFileLine.name should be (Name[File](testFileName))
+ uploadedFileLine.location should be (testFilePath)
+ uploadedFileLine.revision.id.length should be > 0
+ uploadedFileLine.lastModificationDate.millis should be > 0L
+
+ val downloadedFile = Await.result(s3Storage.download(testFilePath).run, 10 seconds)
+ downloadedFile shouldBe defined
+ downloadedFile.foreach {
+ _.getAbsolutePath.endsWith(testFilePath.toString) should be (true)
+ }
+
+ Await.result(s3Storage.delete(testFilePath), 10 seconds)
+
+ val filesAfterRemoval = Await.result(s3Storage.list(testDirPath).run, 10 seconds)
+ filesAfterRemoval shouldBe empty
+ }
+
+ "Filesystem files storage" should "create and download local files and do other operations" in {
+
+ val tempDir = System.getProperty("java.io.tmpdir")
+ val sourceTestFile = generateTestLocalFile(tempDir)
+
+ val randomFolderName = java.util.UUID.randomUUID().toString
+ val testDirPath = Paths.get(tempDir, randomFolderName)
+ val testFilePath = Paths.get(tempDir, randomFolderName, "uploadTestFile")
+
+ val fileStorage = new FileSystemStorage(scala.concurrent.ExecutionContext.global)
+
+ val filesBefore = Await.result(fileStorage.list(testDirPath).run, 10 seconds)
+ filesBefore shouldBe empty
+
+ Await.result(fileStorage.upload(sourceTestFile, testFilePath), 10 seconds)
+
+ val filesAfterUpload = Await.result(fileStorage.list(testDirPath).run, 10 seconds)
+ filesAfterUpload.size should be (1)
+ val uploadedFileLine = filesAfterUpload.head
+ uploadedFileLine.name should be (Name[File]("uploadTestFile"))
+ uploadedFileLine.location should be (testFilePath)
+ uploadedFileLine.revision.id.length should be > 0
+ uploadedFileLine.lastModificationDate.millis should be > 0L
+
+ val downloadedFile = Await.result(fileStorage.download(testFilePath).run, 10 seconds)
+ downloadedFile shouldBe defined
+ downloadedFile.map(_.getAbsolutePath) should be (Some(testFilePath.toString))
+
+ Await.result(fileStorage.delete(testFilePath), 10 seconds)
+
+ val filesAfterRemoval = Await.result(fileStorage.list(testDirPath).run, 10 seconds)
+ filesAfterRemoval shouldBe empty
+ }
+
+ private def generateTestLocalFile(path: String): File = {
+ val randomSourceFolderName = java.util.UUID.randomUUID().toString
+ val sourceTestFile = new File(Paths.get(path, randomSourceFolderName, "uploadTestFile").toString)
+ sourceTestFile.getParentFile.mkdirs() should be (true)
+ sourceTestFile.createNewFile() should be (true)
+ using(new java.io.PrintWriter(sourceTestFile)) { _.append("Test File Contents") }
+ sourceTestFile
+ }
+}
diff --git a/src/test/scala/com/drivergrp/core/GeneratorsTest.scala b/src/test/scala/com/drivergrp/core/GeneratorsTest.scala
index 9332e7f..84a8635 100644
--- a/src/test/scala/com/drivergrp/core/GeneratorsTest.scala
+++ b/src/test/scala/com/drivergrp/core/GeneratorsTest.scala
@@ -18,6 +18,22 @@ class GeneratorsTest extends FlatSpec with Matchers with Assertions {
generatedId2 should !==(generatedId3)
}
+ it should "be able to generate com.drivergrp.core.Id identifiers with max value" in {
+
+ val generatedLimitedId1 = nextId[String](10000)
+ val generatedLimitedId2 = nextId[String](1000)
+ val generatedLimitedId3 = nextId[Long](2000)
+
+ generatedLimitedId1 should be >= 0L
+ generatedLimitedId1 should be < 10000L
+ generatedLimitedId2 should be >= 0L
+ generatedLimitedId2 should be < 1000L
+ generatedLimitedId3 should be >= 0L
+ generatedLimitedId3 should be < 2000L
+ generatedLimitedId1 should not be generatedLimitedId2
+ generatedLimitedId2 should !==(generatedLimitedId3)
+ }
+
it should "be able to generate com.drivergrp.core.Name names" in {
nextName[String]() should not be nextName[String]()
@@ -28,6 +44,18 @@ class GeneratorsTest extends FlatSpec with Matchers with Assertions {
assert(!fixedLengthName.exists(_.isControl))
}
+ it should "be able to generate proper UUIDs" in {
+
+ nextUuid() should not be nextUuid()
+ nextUuid().toString.length should be (36)
+ }
+
+ it should "be able to generate new Revisions" in {
+
+ nextRevision[String]() should not be nextRevision[String]()
+ nextRevision[String]().id.length should be > 0
+ }
+
it should "be able to generate strings" in {
nextString() should not be nextString()
diff --git a/src/test/scala/com/drivergrp/core/JsonTest.scala b/src/test/scala/com/drivergrp/core/JsonTest.scala
index a167762..125e97c 100644
--- a/src/test/scala/com/drivergrp/core/JsonTest.scala
+++ b/src/test/scala/com/drivergrp/core/JsonTest.scala
@@ -1,5 +1,7 @@
package com.drivergrp.core
+import com.drivergrp.core.json.{EnumJsonFormat, ValueClassFormat}
+import com.drivergrp.core.revision.Revision
import com.drivergrp.core.time.provider.SystemTimeProvider
import org.scalatest.{FlatSpec, Matchers}
@@ -37,4 +39,63 @@ class JsonTest extends FlatSpec with Matchers {
val parsedTime = com.drivergrp.core.json.timeFormat.read(writtenJson)
parsedTime should be(referenceTime)
}
+
+ "Json format for Revision" should "read and write correct JSON" in {
+
+ val referenceRevision = Revision[String]("037e2ec0-8901-44ac-8e53-6d39f6479db4")
+
+ val writtenJson = com.drivergrp.core.json.revisionFormat.write(referenceRevision)
+ writtenJson.prettyPrint should be("\"" + referenceRevision.id + "\"")
+
+ val parsedRevision = com.drivergrp.core.json.revisionFormat.read(writtenJson)
+ parsedRevision should be(referenceRevision)
+ }
+
+ "Json format for Enums" should "read and write correct JSON" in {
+
+ sealed trait EnumVal
+ case object Val1 extends EnumVal
+ case object Val2 extends EnumVal
+ case object Val3 extends EnumVal
+
+ val format = new EnumJsonFormat[EnumVal]("a" -> Val1, "b" -> Val2, "c" -> Val3)
+
+ val referenceEnumValue1 = Val2
+ val referenceEnumValue2 = Val3
+
+ val writtenJson1 = format.write(referenceEnumValue1)
+ writtenJson1.prettyPrint should be("\"b\"")
+
+ val writtenJson2 = format.write(referenceEnumValue2)
+ writtenJson2.prettyPrint should be("\"c\"")
+
+ val parsedEnumValue1 = format.read(writtenJson1)
+ val parsedEnumValue2 = format.read(writtenJson2)
+
+ parsedEnumValue1 should be(referenceEnumValue1)
+ parsedEnumValue2 should be(referenceEnumValue2)
+ }
+
+ // Should be defined outside of case to have a TypeTag
+ case class CustomWrapperClass(value: Int)
+
+ "Json format for Value classes" should "read and write correct JSON" in {
+
+ val format = new ValueClassFormat[CustomWrapperClass](v => BigDecimal(v.value), d => CustomWrapperClass(d.toInt))
+
+ val referenceValue1 = CustomWrapperClass(-2)
+ val referenceValue2 = CustomWrapperClass(10)
+
+ val writtenJson1 = format.write(referenceValue1)
+ writtenJson1.prettyPrint should be("-2")
+
+ val writtenJson2 = format.write(referenceValue2)
+ writtenJson2.prettyPrint should be("10")
+
+ val parsedValue1 = format.read(writtenJson1)
+ val parsedValue2 = format.read(writtenJson2)
+
+ parsedValue1 should be(referenceValue1)
+ parsedValue2 should be(referenceValue2)
+ }
}