Skip to content

Commit

Permalink
Merge branch 'release/1.18.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
nwtgck committed Sep 5, 2018
2 parents ba5cd70 + e60ed89 commit 2a80937
Show file tree
Hide file tree
Showing 9 changed files with 408 additions and 185 deletions.
11 changes: 10 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,23 @@ language: scala
script:
# sbt test
- sbt clean coverage test
# working-test of `sbt assembly`
# Generate a fat jar file
- sbt assembly
# working-test of `sbt dist`
- sbt dist

after_success:
- sbt coverageReport coveralls

# (from: https://docs.travis-ci.com/user/deployment/releases/)
deploy:
provider: releases
api_key: $GITHUB_TOKEN
file: $TRAVIS_BUILD_DIR/target/scala-2.11/trans-server-akka.jar
skip_cleanup: true
on:
tags: true

# (from: http://www.scala-sbt.org/1.0/docs/Travis-CI-with-sbt.html)
before_cache:
# Cleanup the cached directories to avoid unnecessary cache updates
Expand Down
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)

## [Unreleased]

## [1.18.0] - 2018-09-05
### Added
- Allow users to specify File ID when sending

## [1.17.0] - 2018-07-31
### Added
- Add `--db-url` to specify database URL like 'jdbc:h2:tcp://localhost/~/h2db/trans'
Expand Down Expand Up @@ -140,7 +144,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
- Adapt [`sbt-native-packager`](https://github.com/sbt/sbt-native-packager) for [Heroku](https://heroku.com/)


[Unreleased]: https://github.com/nwtgck/trans-server-akka/compare/v1.17.0...HEAD
[Unreleased]: https://github.com/nwtgck/trans-server-akka/compare/v1.18.0...HEAD
[1.18.0]: https://github.com/nwtgck/trans-server-akka/compare/v1.17.0...v1.18.0
[1.17.0]: https://github.com/nwtgck/trans-server-akka/compare/v1.16.2...v1.17.0
[1.16.2]: https://github.com/nwtgck/trans-server-akka/compare/v1.16.1...v1.16.2
[1.16.0]: https://github.com/nwtgck/trans-server-akka/compare/v1.15.1...v1.16.0
Expand Down
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import sbtassembly.AssemblyPlugin.autoImport.assemblyJarName

name := "trans-server-akka"

version := "1.17.0"
version := "1.18.0"

scalaVersion := "2.11.12"

Expand Down
406 changes: 238 additions & 168 deletions src/main/scala/io/github/nwtgck/trans_server/Core.scala

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package io.github.nwtgck.trans_server

class InvalidUseException (msg: String) extends Exception(msg)
15 changes: 4 additions & 11 deletions src/main/scala/io/github/nwtgck/trans_server/Main.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package io.github.nwtgck.trans_server

import java.io.{File, PrintWriter, StringWriter}
import java.io.File

import akka.actor.ActorSystem
import akka.event.Logging
Expand All @@ -10,7 +10,7 @@ import scopt.OptionParser
import slick.driver.H2Driver.api._

import scala.concurrent.Future
import scala.util.{Failure, Success, Try}
import scala.util.{Failure, Success}

/**
* Created by Ryo on 2017/04/23.
Expand Down Expand Up @@ -117,22 +117,15 @@ object Main {
Http().bindAndHandle(core.route, HOST, httpsPort, connectionContext = httpsConnectionContext).map(_ =>
logger.info(s"Listening HTTPS on ${httpsPort}...")
)
case None =>
case _ =>
Future.successful()
}
}
} yield ()).onComplete{
case Success(_) =>
logger.info(s"Running server!")
case Failure(e) =>
// (from: https://alvinalexander.com/scala/how-convert-stack-trace-exception-string-print-logger-logging-log4j-slf4j)
val stackTracesStr: String = {
val sw = new StringWriter()
e.printStackTrace(new PrintWriter(sw))
sw.toString
}

logger.error(s"Error in running server\n${stackTracesStr}", e)
logger.error(s"Error in running server\n${Util.getStackTraceString(e)}", e)
}


Expand Down
3 changes: 3 additions & 0 deletions src/main/scala/io/github/nwtgck/trans_server/Setting.scala
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ object Setting {
val DefaultIdLength : Int = 3
val MinIdLength : Int = 3
val MaxIdLength : Int = 128
val minSpecifiedFileIdLength : Int = 5
val KeySalt : String = "ymiKicjOq5M3yIMmVBEPFcLnkNxJ4n2iY9ms3fYRsBDS3wZvS1lev9ToLnZhlj3O"
val FileEncryptionKey : String = "vKOhINCMuO47xxel" // NOTE: Its length should be 16
val FileIdGenTryLimit : Int = 500 // NOTE: Simple study shows 500 is enough (https://github.com/nwtgck/random-str-collision-graph-scala)
Expand All @@ -28,6 +29,8 @@ object Setting {
val Md5HttpHeaderName : String = "X-FILE-MD5"
val Sha1HttpHeaderName : String = "X-FILE-SHA1"
val Sha256HttpHeaderName : String = "X-FILE-SHA256"
// Path name to specify File ID
val fileIdFixationPathName : String = "fix"

// Reserved route name of GET request
object GetRouteName{
Expand Down
30 changes: 29 additions & 1 deletion src/main/scala/io/github/nwtgck/trans_server/Util.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package io.github.nwtgck.trans_server

import java.io.{FileInputStream, InputStream}
import java.io.{FileInputStream, InputStream, PrintWriter, StringWriter}
import java.security.{KeyStore, SecureRandom}
import java.util.Base64

Expand All @@ -10,6 +10,8 @@ import akka.http.scaladsl.server.{Directive, Directive1, Route}
import akka.http.scaladsl.{ConnectionContext, HttpsConnectionContext}
import javax.net.ssl.{KeyManagerFactory, SSLContext, TrustManagerFactory}

import scala.concurrent.Future

object Util {
// Generate hashed key
// (from: http://www.casleyconsulting.co.jp/blog-engineer/java/%E3%80%90java-se-8%E9%99%90%E5%AE%9A%E3%80%91%E5%AE%89%E5%85%A8%E3%81%AA%E3%83%91%E3%82%B9%E3%83%AF%E3%83%BC%E3%83%89%E3%82%92%E7%94%9F%E6%88%90%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/)
Expand Down Expand Up @@ -122,4 +124,30 @@ object Util {
}
}
}

/**
* If not satisfying cond, Future is failed
* @param cond
* @param exception
* @return
*/
def requireFuture(cond: Boolean, exception: => Exception): Future[Unit] = {
if(cond){
Future.successful(())
} else {
Future.failed(exception)
}
}

/**
* Generate stack trace string
* (from: https://alvinalexander.com/scala/how-convert-stack-trace-exception-string-print-logger-logging-log4j-slf4j)
* @param e
* @return
*/
def getStackTraceString(e: Throwable): String = {
val sw = new StringWriter()
e.printStackTrace(new PrintWriter(sw))
sw.toString
}
}
116 changes: 114 additions & 2 deletions src/test/scala/io/github/nwtgck/trans_server/CoreTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@ class CoreTest extends FunSuite with ScalatestRouteTest with Matchers with Befor
implicit def defaultTimeout(implicit system: ActorSystem): RouteTestTimeout = RouteTestTimeout(5.second)

before {
// Create a memory-base db
db = Database.forConfig("h2mem-trans")
// Temp directory for file DB
val tmpDbPath: String = Files.createTempDirectory("db_").toString
// Create a file-base db
db = Database.forURL(s"jdbc:h2:${tmpDbPath}", driver="org.h2.Driver")
// Create a tables
Await.ready(Tables.createTablesIfNotExist(db), Duration.Inf)
// Temp directory for file DB
Expand Down Expand Up @@ -154,6 +156,78 @@ class CoreTest extends FunSuite with ScalatestRouteTest with Matchers with Befor
}
}

test("[positive] send/get by specifying File ID") {

val fileId: String = "myfileid123"

val originalContent: String = "this is a file content.\nthis doesn't seem to be a file content, but it is.\n"

Post(s"/fix/${fileId}").withEntity(originalContent) ~> core.route ~> check {
// Get file ID
val resFileId = responseAs[String].trim
// Response of File ID should be the specified File ID
resFileId shouldBe fileId
}

Get(s"/${fileId}") ~> core.route ~> check {
val resContent: String = responseAs[String]
// response should be original
resContent shouldBe originalContent
}
}

test("[negative] send/get by specifying too SHORT File ID") {
val fileId: String = "abc"
require(fileId.length < Setting.minSpecifiedFileIdLength)

val originalContent: String = "this is a file content.\nthis doesn't seem to be a file content, but it is.\n"

Post(s"/fix/${fileId}").withEntity(originalContent) ~> core.route ~> check {
status shouldBe StatusCodes.BadRequest
}
}

test("[negative] send/get by specifying too LONG File ID") {
val fileId: String = "a" * 500
require(fileId.length > Setting.MaxIdLength)

val originalContent: String = "this is a file content.\nthis doesn't seem to be a file content, but it is.\n"

Post(s"/fix/${fileId}").withEntity(originalContent) ~> core.route ~> check {
status shouldBe StatusCodes.BadRequest
}
}

test("[negative] send/get by specifying INVALID File ID") {
// NOTE: File ID contains invalid character
val fileId: String = "myfileid~123"

val originalContent: String = "this is a file content.\nthis doesn't seem to be a file content, but it is.\n"

Post(s"/fix/${fileId}").withEntity(originalContent) ~> core.route ~> check {
status shouldBe StatusCodes.BadRequest
}
}

test("[negative] send/get by specifying DUPLICATE File ID") {
val fileId: String = "myfileid123"

val originalContent: String = "this is a file content.\nthis doesn't seem to be a file content, but it is.\n"

Post(s"/fix/${fileId}").withEntity(originalContent) ~> core.route ~> check {
// Get file ID
val resFileId = responseAs[String].trim
// Response of File ID should be the specified File ID
resFileId shouldBe fileId
}

// NOTE: Send twice by the same File ID
Post(s"/fix/${fileId}").withEntity(originalContent) ~> core.route ~> check {
status shouldBe StatusCodes.BadRequest
}
}


test("[positive] send/get by multipart") {
val originalContent: String = "this is a file content.\nthis doesn't seem to be a file content, but it is.\n"

Expand Down Expand Up @@ -296,6 +370,26 @@ class CoreTest extends FunSuite with ScalatestRouteTest with Matchers with Befor
}
}

test("[positive] send/get by PUT specifying File ID") {

val fileId: String = "myfileid123"

val originalContent: String = "this is a file content.\nthis doesn't seem to be a file content, but it is.\n"

Put(s"/fix/${fileId}").withEntity(originalContent) ~> core.route ~> check {
// Get file ID
val resFileId = responseAs[String].trim
// Response of File ID should be the specified File ID
resFileId shouldBe fileId
}

Get(s"/${fileId}") ~> core.route ~> check {
val resContent: String = responseAs[String]
// response should be original
resContent shouldBe originalContent
}
}

test("[positive] send/get by GET method") {
val fileId1: String =
Get("/send?data=hello%2C%20world") ~> core.route ~> check {
Expand Down Expand Up @@ -350,6 +444,24 @@ class CoreTest extends FunSuite with ScalatestRouteTest with Matchers with Befor
}
}

test("[positive] send/get by GET method specifying File ID") {

val fileId: String = "myfileid123"

Get(s"/send/fix/${fileId}?data=hello%2C%20world") ~> core.route ~> check {
// Get file ID
val resFileId = responseAs[String].trim
// Response of File ID should be the specified File ID
resFileId shouldBe fileId
}

Get(s"/${fileId}") ~> core.route ~> check {
val resContent: String = responseAs[String]
// response should be original
resContent shouldBe "hello, world"
}
}


test("[positive] send/get big data") {

Expand Down

0 comments on commit 2a80937

Please sign in to comment.