http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/f2311f25/s2rest_play/conf/logger.xml ---------------------------------------------------------------------- diff --git a/s2rest_play/conf/logger.xml b/s2rest_play/conf/logger.xml new file mode 100644 index 0000000..2d767c2 --- /dev/null +++ b/s2rest_play/conf/logger.xml @@ -0,0 +1,83 @@ +<configuration> + + <conversionRule conversionWord="coloredLevel" converterClass="play.api.Logger$ColoredLevel"/> + + <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>logs/application.log</file> + + <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy"> + <fileNamePattern>logs/application.%i.log</fileNamePattern> + <minIndex>1</minIndex> + <maxIndex>9</maxIndex> + </rollingPolicy> + + <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> + <maxFileSize>500MB</maxFileSize> + </triggeringPolicy> + <encoder> + <pattern>%date [%level] [%logger] [%thread] - %message %xException%n</pattern> + </encoder> + </appender> + + + <appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>logs/error.log</file> + <append>true</append> + <encoder> + <pattern>%date [%level] [%logger] [%thread] - %message %xException%n</pattern> + </encoder> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <fileNamePattern>logs/error.log.%d.%i</fileNamePattern> + <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> + <maxFileSize>500MB</maxFileSize> + </timeBasedFileNamingAndTriggeringPolicy> + <maxHistory>3</maxHistory> + </rollingPolicy> + </appender> + + <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> + <encoder> + <pattern>%coloredLevel %logger{15} - %message%n%xException%n</pattern> + </encoder> + </appender> + + <appender name="ACTOR" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>logs/actor.log</file> + <append>true</append> + <encoder> + <pattern>%date [%level] [%logger] [%thread] - %message %xException%n</pattern> + </encoder> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <fileNamePattern>logs/actor.log.%d.%i</fileNamePattern> + <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> + <maxFileSize>200MB</maxFileSize> + </timeBasedFileNamingAndTriggeringPolicy> + <maxHistory>7</maxHistory> + </rollingPolicy> + </appender> + + <logger name="play" level="INFO"> + <appender-ref ref="STDOUT"/> + <appender-ref ref="FILE"/> + </logger> + + <logger name="application" level="INFO"> + <appender-ref ref="STDOUT"/> + <appender-ref ref="FILE"/> + </logger> + + <logger name="error" level="INFO"> + <appender-ref ref="STDOUT"/> + <appender-ref ref="ERROR"/> + </logger> + + <logger name="actor" level="INFO"> + <appender-ref ref="ACTOR"/> + </logger> + + <logger name="akka" level="INFO"> + <appender-ref ref="STDOUT"/> + <appender-ref ref="FILE"/> + </logger> + +</configuration>
http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/f2311f25/s2rest_play/conf/reference.conf ---------------------------------------------------------------------- diff --git a/s2rest_play/conf/reference.conf b/s2rest_play/conf/reference.conf new file mode 100644 index 0000000..a992e5d --- /dev/null +++ b/s2rest_play/conf/reference.conf @@ -0,0 +1,131 @@ +# This is the main configuration file for the application. +# ~~~~~ + +# Secret key +# ~~~~~ +# The secret key is used to secure cryptographics functions. +# +# This must be changed for production, but we recommend not changing it in this file. +# +# See http://www.playframework.com/documentation/latest/ApplicationSecret for more details. +application.secret="/`==g^yr2DNnZGK_L^rguLZeR`60uLOVgY@OhyTv:maatl:Tl>9or/d1xME3b/Pi" + +# The application languages +# ~~~~~ +application.langs="en" + +# Global object class +# ~~~~~ +# Define the Global object class for this application. +# Default to Global in the root package. +# application.global=Global + +# Router +# ~~~~~ +# Define the Router object to use for this application. +# This router will be looked up first when the application is starting up, +# so make sure this is the entry point. +# Furthermore, it's assumed your route file is named properly. +# So for an application router like `my.application.Router`, +# you may need to define a router file `conf/my.application.routes`. +# Default to Routes in the root package (and conf/routes) +# application.router=my.application.Routes + +# Database configuration +# ~~~~~ +# You can declare as many datasources as you want. +# By convention, the default datasource is named `default` +# +# db.default.driver=org.h2.Driver +# db.default.url="jdbc:h2:mem:play" +# db.default.user=sa +# db.default.password="" + +# Evolutions +# ~~~~~ +# You can disable evolutions if needed +# evolutionplugin=disabled + +# Logger +# ~~~~~ +# You can also configure logback (http://logback.qos.ch/), +# by providing an application-logger.xml file in the conf directory. + +# Root logger: +logger.root=ERROR + +# Logger used by the framework: +logger.play=INFO + +# Logger provided to your application: +logger.application=DEBUG + +# APP PHASE +phase=dev +host=localhost + +# DB +s2graph.models.table.name="models-dev" +hbase.zookeeper.quorum=${host} +db.default.url="jdbc:mysql://"${host}":3306/graph_dev" +# Query server +is.query.server=true +is.write.server=true +query.hard.limit=100000 + +# Local Cache +cache.ttl.seconds=60 +cache.max.size=100000 + +# HBASE +#hbase.client.operation.timeout=1000 +#async.hbase.client.flush.interval=100 +hbase.table.compression.algorithm="gz" + +# Asynchbase +hbase.client.retries.number=100 +hbase.rpcs.buffered_flush_interval=100 +hbase.rpc.timeout=0 +#hbase.nsre.high_watermark=1000000 +#hbase.timer.tick=5 +#hbase.timer.ticks_per_wheel=5 + +# Kafka +kafka.metadata.broker.list=${host} +kafka.producer.pool.size=0 + +# HTTP +parsers.text.maxLength=512K +parsers.json.maxLength=512K +trustxforwarded=false + +# Local Queue Actor +local.queue.actor.max.queue.size=100000 +local.queue.actor.rate.limit=1000000 + +# local retry number +max.retry.number=100 +max.back.off=50 +delete.all.fetch.size=10000 +hbase.fail.prob=-1.0 + +# max allowd edges for deleteAll is multiply of above two configuration. + +# set global obejct package, TODO: remove global +application.global=com.kakao.s2graph.rest.Global + +akka { + loggers = ["akka.event.slf4j.Slf4jLogger"] + loglevel = "DEBUG" +} + + +# Future cache. +future.cache.max.size=100000 +future.cache.expire.after.write=10000 +future.cache.expire.after.access=5000 + + +# Counter +redis.instances = [${host}] + http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/f2311f25/s2rest_play/conf/routes ---------------------------------------------------------------------- diff --git a/s2rest_play/conf/routes b/s2rest_play/conf/routes new file mode 100644 index 0000000..df4a1ee --- /dev/null +++ b/s2rest_play/conf/routes @@ -0,0 +1,124 @@ +# Routes +# This file defines all application routes (Higher priority routes first) +# ~~~~ + + +# publish +#POST /publish/:topic controllers.PublishController.publish(topic) +POST /publish/:topic controllers.PublishController.mutateBulk(topic) +POST /publishOnly/:topic controllers.PublishController.publishOnly(topic) + +#### Health Check +#GET /health_check.html controllers.Assets.at(path="/public", file="health_check.html") +GET /health_check.html controllers.ApplicationController.healthCheck() +PUT /health_check/:isHealthy controllers.ApplicationController.updateHealthCheck(isHealthy: Boolean) + +## Edge +POST /graphs/edges/insert controllers.EdgeController.inserts() +POST /graphs/edges/insertWithWait controllers.EdgeController.insertsWithWait() +POST /graphs/edges/insertBulk controllers.EdgeController.insertsBulk() +POST /graphs/edges/delete controllers.EdgeController.deletes() +POST /graphs/edges/deleteWithWait controllers.EdgeController.deletesWithWait() +POST /graphs/edges/deleteAll controllers.EdgeController.deleteAll() +POST /graphs/edges/update controllers.EdgeController.updates() +POST /graphs/edges/updateWithWait controllers.EdgeController.updatesWithWait() +POST /graphs/edges/increment controllers.EdgeController.increments() +POST /graphs/edges/incrementCount controllers.EdgeController.incrementCounts() +POST /graphs/edges/bulk controllers.EdgeController.mutateBulk() + +## Vertex +POST /graphs/vertices/insert controllers.VertexController.inserts() +POST /graphs/vertices/insertWithWait controllers.VertexController.insertsWithWait() +POST /graphs/vertices/insert/:serviceName/:columnName controllers.VertexController.insertsSimple(serviceName, columnName) +POST /graphs/vertices/delete controllers.VertexController.deletes() +POST /graphs/vertices/deleteWithWait controllers.VertexController.deletesWithWait() +POST /graphs/vertices/delete/:serviceName/:columnName controllers.VertexController.deletesSimple(serviceName, columnName) +POST /graphs/vertices/deleteAll controllers.VertexController.deletesAll() +POST /graphs/vertices/deleteAll/:serviceName/:columnName controllers.VertexController.deletesAllSimple(serviceName, columnName) + + +### SELECT Edges +POST /graphs/getEdges controllers.QueryController.getEdges() +POST /graphs/getEdges/grouped controllers.QueryController.getEdgesWithGrouping() +POST /graphs/getEdgesExcluded controllers.QueryController.getEdgesExcluded() +POST /graphs/getEdgesExcluded/grouped controllers.QueryController.getEdgesExcludedWithGrouping() +POST /graphs/checkEdges controllers.QueryController.checkEdges() + +### this will be deprecated +POST /graphs/getEdgesGrouped controllers.QueryController.getEdgesGrouped() +POST /graphs/getEdgesGroupedExcluded controllers.QueryController.getEdgesGroupedExcluded() +POST /graphs/getEdgesGroupedExcludedFormatted controllers.QueryController.getEdgesGroupedExcludedFormatted() +GET /graphs/getEdge/:srcId/:tgtId/:labelName/:direction controllers.QueryController.getEdge(srcId, tgtId, labelName, direction) + + +### SELECT Vertices +#POST /graphs/getVertex controllers.QueryController.getVertex() +POST /graphs/getVertices controllers.QueryController.getVertices() + + +#### ADMIN +POST /graphs/createService controllers.AdminController.createService() +GET /graphs/getService/:serviceName controllers.AdminController.getService(serviceName) +GET /graphs/getLabels/:serviceName controllers.AdminController.getLabels(serviceName) +POST /graphs/createLabel controllers.AdminController.createLabel() +POST /graphs/addIndex controllers.AdminController.addIndex() +GET /graphs/getLabel/:labelName controllers.AdminController.getLabel(labelName) +PUT /graphs/deleteLabel/:labelName controllers.AdminController.deleteLabel(labelName) + +POST /graphs/addProp/:labelName controllers.AdminController.addProp(labelName) +POST /graphs/createServiceColumn controllers.AdminController.createServiceColumn() +PUT /graphs/deleteServiceColumn/:serviceName/:columnName controllers.AdminController.deleteServiceColumn(serviceName, columnName) +POST /graphs/addServiceColumnProp/:serviceName/:columnName controllers.AdminController.addServiceColumnProp(serviceName, columnName) +POST /graphs/addServiceColumnProps/:serviceName/:columnName controllers.AdminController.addServiceColumnProps(serviceName, columnName) +GET /graphs/getServiceColumn/:serviceName/:columnName controllers.AdminController.getServiceColumn(serviceName, columnName) +POST /graphs/createHTable controllers.AdminController.createHTable() + + + + +#### TEST +#GET /graphs/testGetEdges/:label/:limit/:friendCntStep controllers.QueryController.testGetEdges(label, limit: Int, friendCntStep: Int) +#GET /graphs/testGetEdges2/:label1/:limit1/:label2/:limit2 controllers.QueryController.testGetEdges2(label1, limit1: Int, label2, limit2: Int) +#GET /graphs/testGetEdges3/:label1/:limit1/:label2/:limit2/:label3/:limit3 controllers.QueryController.testGetEdges3(label1, limit1: Int, label2, limit2: Int, label3, limit3: Int) +POST /ping controllers.TestController.ping() +POST /pingAsync controllers.TestController.pingAsync() +GET /graphs/testId controllers.TestController.getRandomId() + +# Map static resources from the /public folder to the /assets URL path +GET /images/*file controllers.Assets.at(path="/public/images", file) +GET /javascripts/*file controllers.Assets.at(path="/public/javascripts", file) +GET /stylesheets/*file controllers.Assets.at(path="/public/stylesheets", file) +GET /font-awesome-4.1.0/*file controllers.Assets.at(path="/public/font-awesome-4.1.0", file) +GET /swagger/*file controllers.Assets.at(path="/public/swagger-ui", file) + + +# AdminController API +#GET /admin/services controllers.AdminController.allServices +GET /admin/labels/:serviceName controllers.AdminController.getLabels(serviceName) +#POST /admin/labels/delete/:zkAddr/:tableName/:labelIds/:minTs/:maxTs controllers.AdminController.deleteEdges(zkAddr, tableName, labelIds, minTs: Long, maxTs: Long) +#POST /admin/labels/deleteAll/:zkAddr/:tableName/:minTs/:maxTs controllers.AdminController.deleteAllEdges(zkAddr, tableName, minTs: Long, maxTs: Long) +#POST /admin/swapLabel/:oldLabelName/:newLabelName controllers.AdminController.swapLabel(oldLabelName, newLabelName) +#GET /admin/reloadLabel/:labelName controllers.AdminController.reloadLabel(labelName) +#POST /admin/getEdges controllers.AdminController.getEdges() +POST /graphs/copyLabel/:oldLabelName/:newLabelName controllers.AdminController.copyLabel(oldLabelName, newLabelName) +POST /graphs/renameLabel/:oldLabelName/:newLabelName controllers.AdminController.renameLabel(oldLabelName, newLabelName) +POST /graphs/updateHTable/:labelName/:newHTableName controllers.AdminController.updateHTable(labelName, newHTableName) +PUT /graphs/loadCache controllers.AdminController.loadCache() + + +# Counter Admin API +POST /counter/v1/:service/:action controllers.CounterController.createAction(service, action) +GET /counter/v1/:service/:action controllers.CounterController.getAction(service, action) +PUT /counter/v1/:service/:action controllers.CounterController.updateAction(service, action) +PUT /counter/v1/:service/:action/prepare controllers.CounterController.prepareAction(service, action) +DELETE /counter/v1/:service/:action controllers.CounterController.deleteAction(service, action) + +# Counter API +GET /counter/v1/:service/:action/ranking controllers.CounterController.getRankingCountAsync(service, action) +DELETE /counter/v1/:service/:action/ranking controllers.CounterController.deleteRankingCount(service, action) +GET /counter/v1/:service/:action/:item controllers.CounterController.getExactCountAsync(service, action, item) +PUT /counter/v1/:service/:action/:item controllers.CounterController.incrementCount(service, action, item) +POST /counter/v1/mget controllers.CounterController.getExactCountAsyncMulti() + +# Experiment API +POST /graphs/experiment/:accessToken/:experimentName/:uuid controllers.ExperimentController.experiment(accessToken, experimentName, uuid) http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/f2311f25/s2rest_play/conf/test.conf ---------------------------------------------------------------------- diff --git a/s2rest_play/conf/test.conf b/s2rest_play/conf/test.conf new file mode 100644 index 0000000..c51baef --- /dev/null +++ b/s2rest_play/conf/test.conf @@ -0,0 +1,2 @@ +max.retry.number=10000 +hbase.fail.prob=0.1 http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/f2311f25/s2rest_play/test/benchmark/BenchmarkCommon.scala ---------------------------------------------------------------------- diff --git a/s2rest_play/test/benchmark/BenchmarkCommon.scala b/s2rest_play/test/benchmark/BenchmarkCommon.scala new file mode 100644 index 0000000..9dd69ec --- /dev/null +++ b/s2rest_play/test/benchmark/BenchmarkCommon.scala @@ -0,0 +1,15 @@ +package benchmark + +import org.specs2.mutable.Specification + +trait BenchmarkCommon extends Specification { + val wrapStr = s"\n==================================================" + + def duration[T](prefix: String = "")(block: => T) = { + val startTs = System.currentTimeMillis() + val ret = block + val endTs = System.currentTimeMillis() + println(s"$wrapStr\n$prefix: took ${endTs - startTs} ms$wrapStr") + ret + } +} http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/f2311f25/s2rest_play/test/benchmark/GraphUtilSpec.scala ---------------------------------------------------------------------- diff --git a/s2rest_play/test/benchmark/GraphUtilSpec.scala b/s2rest_play/test/benchmark/GraphUtilSpec.scala new file mode 100644 index 0000000..b5ce93a --- /dev/null +++ b/s2rest_play/test/benchmark/GraphUtilSpec.scala @@ -0,0 +1,125 @@ +package benchmark + +import com.kakao.s2graph.core.{Management, GraphUtil} +import com.kakao.s2graph.core.types.{SourceVertexId, HBaseType, InnerVal, VertexId} +import org.apache.hadoop.hbase.util.Bytes +import play.api.test.{FakeApplication, PlaySpecification} + +import scala.collection.mutable +import scala.collection.mutable.ListBuffer +import scala.util.Random + +class GraphUtilSpec extends BenchmarkCommon with PlaySpecification { + + def between(bytes: Array[Byte], startKey: Array[Byte], endKey: Array[Byte]): Boolean = + Bytes.compareTo(startKey, bytes) <= 0 && Bytes.compareTo(endKey, bytes) >= 0 + + def betweenShort(value: Short, start: Short, end: Short): Boolean = + start <= value && value <= end + + + "GraphUtil" should { + "test murmur3 hash function distribution" in { + val testNum = 1000000 + val bucketSize = Short.MaxValue / 40 + val countsNew = new mutable.HashMap[Int, Int]() + val counts = new mutable.HashMap[Int, Int]() + for { + i <- (0 until testNum) + } { + val h = GraphUtil.murmur3(i.toString) / bucketSize + val hNew = GraphUtil.murmur3Int(i.toString) / bucketSize + counts += (h -> (counts.getOrElse(h, 0) + 1)) + countsNew += (hNew -> (countsNew.getOrElse(hNew, 0) + 1)) + } + val all = counts.toList.sortBy { case (bucket, count) => count }.reverse + val allNew = countsNew.toList.sortBy { case (bucket, count) => count }.reverse + val top = all.take(10) + val bottom = all.takeRight(10) + val topNew = allNew.take(10) + val bottomNew = allNew.takeRight(10) + println(s"Top: $top") + println(s"Bottom: $bottom") + println("-" * 50) + println(s"TopNew: $topNew") + println(s"Bottom: $bottomNew") + true + } + + "test murmur hash skew2" in { + running(FakeApplication()) { + import HBaseType._ + val testNum = 1000000L + val regionCount = 40 + val window = Int.MaxValue / regionCount + val rangeBytes = new ListBuffer[(List[Byte], List[Byte])]() + for { + i <- (0 until regionCount) + } yield { + val startKey = Bytes.toBytes(i * window) + val endKey = Bytes.toBytes((i + 1) * window) + rangeBytes += (startKey.toList -> endKey.toList) + } + + + + val stats = new collection.mutable.HashMap[Int, ((List[Byte], List[Byte]), Long)]() + val counts = new collection.mutable.HashMap[Short, Long]() + stats += (0 -> (rangeBytes.head -> 0L)) + + for (i <- (0L until testNum)) { + val vertexId = SourceVertexId(DEFAULT_COL_ID, InnerVal.withLong(i, HBaseType.DEFAULT_VERSION)) + val bytes = vertexId.bytes + val shortKey = GraphUtil.murmur3(vertexId.innerId.toIdString()) + val shortVal = counts.getOrElse(shortKey, 0L) + 1L + counts += (shortKey -> shortVal) + var j = 0 + var found = false + while (j < rangeBytes.size && !found) { + val (start, end) = rangeBytes(j) + if (between(bytes, start.toArray, end.toArray)) { + found = true + } + j += 1 + } + val head = rangeBytes(j - 1) + val key = j - 1 + val value = stats.get(key) match { + case None => 0L + case Some(v) => v._2 + 1 + } + stats += (key -> (head, value)) + } + val sorted = stats.toList.sortBy(kv => kv._2._2).reverse + println(s"Index: StartBytes ~ EndBytes\tStartShortBytes ~ EndShortBytes\tStartShort ~ EndShort\tCount\tShortCount") + sorted.foreach { case (idx, ((start, end), cnt)) => + val startShort = Bytes.toShort(start.take(2).toArray) + val endShort = Bytes.toShort(end.take(2).toArray) + val count = counts.count(t => startShort <= t._1 && t._1 < endShort) + println(s"$idx: $start ~ $end\t${start.take(2)} ~ ${end.take(2)}\t$startShort ~ $endShort\t$cnt\t$count") + + } + println("\n" * 10) + println(s"Index: StartBytes ~ EndBytes\tStartShortBytes ~ EndShortBytes\tStartShort ~ EndShort\tCount\tShortCount") + stats.toList.sortBy(kv => kv._1).reverse.foreach { case (idx, ((start, end), cnt)) => + val startShort = Bytes.toShort(start.take(2).toArray) + val endShort = Bytes.toShort(end.take(2).toArray) + val count = counts.count(t => startShort <= t._1 && t._1 < endShort) + println(s"$idx: $start ~ $end\t${start.take(2)} ~ ${end.take(2)}\t$startShort ~ $endShort\t$cnt\t$count") + + } + } + true + } + + "Bytes compareTo" in { + val x = Array[Byte](11, -12, -26, -14, -23) + val startKey = Array[Byte](0, 0, 0, 0) + val endKey = Array[Byte](12, -52, -52, -52) + println(Bytes.compareTo(startKey, x)) + println(Bytes.compareTo(endKey, x)) + true + } + } + +} http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/f2311f25/s2rest_play/test/benchmark/JsonBenchmarkSpec.scala ---------------------------------------------------------------------- diff --git a/s2rest_play/test/benchmark/JsonBenchmarkSpec.scala b/s2rest_play/test/benchmark/JsonBenchmarkSpec.scala new file mode 100644 index 0000000..bf24ed7 --- /dev/null +++ b/s2rest_play/test/benchmark/JsonBenchmarkSpec.scala @@ -0,0 +1,46 @@ +package benchmark + +import play.api.libs.json.JsNumber +import play.api.test.{FakeApplication, PlaySpecification, WithApplication} +import play.libs.Json + +class JsonBenchmarkSpec extends BenchmarkCommon with PlaySpecification { + "to json" should { + implicit val app = FakeApplication() + + "json benchmark" in new WithApplication(app) { + + duration("map to json") { + (0 to 100) foreach { n => + val numberMaps = (0 to 100).map { n => (n.toString -> JsNumber(n * n)) }.toMap + Json.toJson(numberMaps) + } + } + + duration("directMakeJson") { + (0 to 100) foreach { n => + var jsObj = play.api.libs.json.Json.obj() + (0 to 100).foreach { n => + jsObj += (n.toString -> JsNumber(n * n)) + } + } + } + + duration("map to json 2") { + (0 to 500) foreach { n => + val numberMaps = (0 to 100).map { n => (n.toString -> JsNumber(n * n)) }.toMap + Json.toJson(numberMaps) + } + } + + duration("directMakeJson 2") { + (0 to 500) foreach { n => + var jsObj = play.api.libs.json.Json.obj() + (0 to 100).foreach { n => + jsObj += (n.toString -> JsNumber(n * n)) + } + } + } + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/f2311f25/s2rest_play/test/benchmark/OrderingUtilBenchmarkSpec.scala ---------------------------------------------------------------------- diff --git a/s2rest_play/test/benchmark/OrderingUtilBenchmarkSpec.scala b/s2rest_play/test/benchmark/OrderingUtilBenchmarkSpec.scala new file mode 100644 index 0000000..d38ff5e --- /dev/null +++ b/s2rest_play/test/benchmark/OrderingUtilBenchmarkSpec.scala @@ -0,0 +1,103 @@ +package benchmark + +import com.kakao.s2graph.core.OrderingUtil._ +import com.kakao.s2graph.core.SeqMultiOrdering +import play.api.libs.json.{JsNumber, JsValue} +import play.api.test.PlaySpecification +import play.api.{Application => PlayApplication} + +import scala.util.Random + +/** + * Created by hsleep([email protected]) on 2015. 11. 9.. + */ +class OrderingUtilBenchmarkSpec extends BenchmarkCommon with PlaySpecification { + "OrderingUtilBenchmarkSpec" should { + + "performance MultiOrdering any" >> { + val tupLs = (0 until 10) map { i => + Random.nextDouble() -> Random.nextLong() + } + + val seqLs = tupLs.map { tup => + Seq(tup._1, tup._2) + } + + val sorted1 = duration("TupleOrdering double,long") { + (0 until 10000) foreach { _ => + tupLs.sortBy { case (x, y) => + -x -> -y + } + } + tupLs.sortBy { case (x, y) => + -x -> -y + } + }.map { x => x._1 } + + val sorted2 = duration("MultiOrdering double,long") { + (0 until 10000) foreach { _ => + seqLs.sorted(new SeqMultiOrdering[Any](Seq(false, false))) + } + seqLs.sorted(new SeqMultiOrdering[Any](Seq(false, false))) + }.map { x => x.head } + + sorted1.toString() must_== sorted2.toString() + } + + "performance MultiOrdering double" >> { + val tupLs = (0 until 500) map { i => + Random.nextDouble() -> Random.nextDouble() + } + + val seqLs = tupLs.map { tup => + Seq(tup._1, tup._2) + } + + duration("MultiOrdering double") { + (0 until 10000) foreach { _ => + seqLs.sorted(new SeqMultiOrdering[Double](Seq(false, false))) + } + } + + duration("TupleOrdering double") { + (0 until 10000) foreach { _ => + tupLs.sortBy { case (x, y) => + -x -> -y + } + } + } + + 1 must_== 1 + } + + "performance MultiOrdering jsvalue" >> { + val tupLs = (0 until 500) map { i => + Random.nextDouble() -> Random.nextLong() + } + + val seqLs = tupLs.map { tup => + Seq(JsNumber(tup._1), JsNumber(tup._2)) + } + + val sorted1 = duration("TupleOrdering double,long") { + (0 until 10000) foreach { _ => + tupLs.sortBy { case (x, y) => + -x -> -y + } + } + tupLs.sortBy { case (x, y) => + -x -> -y + } + } + + val sorted2 = duration("MultiOrdering jsvalue") { + (0 until 10000) foreach { _ => + seqLs.sorted(new SeqMultiOrdering[JsValue](Seq(false, false))) + } + seqLs.sorted(new SeqMultiOrdering[JsValue](Seq(false, false))) + } + + 1 must_== 1 + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/f2311f25/s2rest_play/test/benchmark/SamplingBenchmarkSpec.scala ---------------------------------------------------------------------- diff --git a/s2rest_play/test/benchmark/SamplingBenchmarkSpec.scala b/s2rest_play/test/benchmark/SamplingBenchmarkSpec.scala new file mode 100644 index 0000000..0c27a2a --- /dev/null +++ b/s2rest_play/test/benchmark/SamplingBenchmarkSpec.scala @@ -0,0 +1,85 @@ +package benchmark +import play.api.test.{FakeApplication, PlaySpecification, WithApplication} +import scala.annotation.tailrec +import scala.util.Random + +class SamplingBenchmarkSpec extends BenchmarkCommon with PlaySpecification { + "sample" should { + implicit val app = FakeApplication() + + "sample benchmark" in new WithApplication(app) { + @tailrec + def randomInt(n: Int, range: Int, set: Set[Int] = Set.empty[Int]): Set[Int] = { + if (set.size == n) set + else randomInt(n, range, set + Random.nextInt(range)) + } + + // sample using random array + def randomArraySample[T](num: Int, ls: List[T]): List[T] = { + val randomNum = randomInt(num, ls.size) + var sample = List.empty[T] + var idx = 0 + ls.foreach { e => + if (randomNum.contains(idx)) sample = e :: sample + idx += 1 + } + sample + } + + // sample using shuffle + def shuffleSample[T](num: Int, ls: List[T]): List[T] = { + Random.shuffle(ls).take(num) + } + + // sample using random number generation + def rngSample[T](num: Int, ls: List[T]): List[T] = { + var sampled = List.empty[T] + val N = ls.size // population + var t = 0 // total input records dealt with + var m = 0 // number of items selected so far + + while (m < num) { + val u = Random.nextDouble() + if ( (N - t)*u < num - m) { + sampled = ls(t) :: sampled + m += 1 + } + t += 1 + } + sampled + } + + // test data + val testLimit = 500000 + val testNum = 10 + val testData = (0 to 1000).toList + + // dummy for warm-up + (0 to testLimit) foreach { n => + randomArraySample(testNum, testData) + shuffleSample(testNum, testData) + rngSample(testNum, testData) + } + + duration("Random Array Sampling") { + (0 to testLimit) foreach { _ => + val sampled = randomArraySample(testNum, testData) + } + } + + duration("Shuffle Sampling") { + (0 to testLimit) foreach { _ => + val sampled = shuffleSample(testNum, testData) + } + } + + duration("RNG Sampling") { + (0 to testLimit) foreach { _ => + val sampled = rngSample(testNum, testData) + } + } + } + + + } +} http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/f2311f25/s2rest_play/test/controllers/PostProcessSpec.scala ---------------------------------------------------------------------- diff --git a/s2rest_play/test/controllers/PostProcessSpec.scala b/s2rest_play/test/controllers/PostProcessSpec.scala new file mode 100644 index 0000000..cea132a --- /dev/null +++ b/s2rest_play/test/controllers/PostProcessSpec.scala @@ -0,0 +1,112 @@ +package controllers + +import com.kakao.s2graph.core.{OrderingUtil, SeqMultiOrdering} +import play.api.libs.json.{JsNumber, JsString, JsValue} +import play.api.test.PlaySpecification + +class PostProcessSpec extends PlaySpecification { + import OrderingUtil._ + + "test order by json" >> { + val jsLs: Seq[Seq[JsValue]] = Seq( + Seq(JsNumber(0), JsString("a")), + Seq(JsNumber(0), JsString("b")), + Seq(JsNumber(1), JsString("a")), + Seq(JsNumber(1), JsString("b")), + Seq(JsNumber(2), JsString("c")) + ) + + // number descending, string ascending + val sortedJsLs: Seq[Seq[JsValue]] = Seq( + Seq(JsNumber(2), JsString("c")), + Seq(JsNumber(1), JsString("a")), + Seq(JsNumber(1), JsString("b")), + Seq(JsNumber(0), JsString("a")), + Seq(JsNumber(0), JsString("b")) + ) + + val orderParam: Seq[Boolean] = Seq(false, true) + val resultJsLs = jsLs.sorted(new Ordering[Seq[JsValue]] { + override def compare(x: Seq[JsValue], y: Seq[JsValue]): Int = { + val xe = x.iterator + val ye = y.iterator + val oe = orderParam.iterator + + while (xe.hasNext && ye.hasNext && oe.hasNext) { + val (xev, yev) = oe.next() match { + case true => xe.next() -> ye.next() + case false => ye.next() -> xe.next() + } + val res = (xev, yev) match { + case (JsNumber(xv), JsNumber(yv)) => + Ordering[BigDecimal].compare(xv, yv) + case (JsString(xv), JsString(yv)) => + Ordering[String].compare(xv, yv) + case _ => throw new Exception("type mismatch") + } + if (res != 0) return res + } + + Ordering.Boolean.compare(xe.hasNext, ye.hasNext) + } + }) + + resultJsLs.toString() must_== sortedJsLs.toString + } + + "test order by primitive type" >> { + val jsLs: Seq[Seq[Any]] = Seq( + Seq(0, "a"), + Seq(0, "b"), + Seq(1, "a"), + Seq(1, "b"), + Seq(2, "c") + ) + + // number descending, string ascending + val sortedJsLs: Seq[Seq[Any]] = Seq( + Seq(2, "c"), + Seq(1, "a"), + Seq(1, "b"), + Seq(0, "a"), + Seq(0, "b") + ) + + val ascendingLs: Seq[Boolean] = Seq(false, true) + val resultJsLs = jsLs.sorted(new SeqMultiOrdering[Any](ascendingLs)) + + resultJsLs.toString() must_== sortedJsLs.toString + } + + "test order by primitive type with short ascending list" >> { + val jsLs: Seq[Seq[Any]] = Seq( + Seq(0, "a"), + Seq(1, "b"), + Seq(0, "b"), + Seq(1, "a"), + Seq(2, "c"), + Seq(1, "c"), + Seq(1, "d"), + Seq(1, "f"), + Seq(1, "e") + ) + + // number descending, string ascending(default) + val sortedJsLs: Seq[Seq[Any]] = Seq( + Seq(2, "c"), + Seq(1, "a"), + Seq(1, "b"), + Seq(1, "c"), + Seq(1, "d"), + Seq(1, "e"), + Seq(1, "f"), + Seq(0, "a"), + Seq(0, "b") + ) + + val ascendingLs: Seq[Boolean] = Seq(false) + val resultJsLs = jsLs.sorted(new SeqMultiOrdering[Any](ascendingLs)) + + resultJsLs.toString() must_== sortedJsLs.toString + } +} http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/f2311f25/test/benchmark/BenchmarkCommon.scala ---------------------------------------------------------------------- diff --git a/test/benchmark/BenchmarkCommon.scala b/test/benchmark/BenchmarkCommon.scala deleted file mode 100644 index cd465e8..0000000 --- a/test/benchmark/BenchmarkCommon.scala +++ /dev/null @@ -1,18 +0,0 @@ -package benchmark - -import org.specs2.mutable.Specification - -/** - * Created by hsleep([email protected]) on 2015. 11. 6.. - */ -trait BenchmarkCommon extends Specification { - val wrapStr = s"\n==================================================" - - def duration[T](prefix: String = "")(block: => T) = { - val startTs = System.currentTimeMillis() - val ret = block - val endTs = System.currentTimeMillis() - println(s"$wrapStr\n$prefix: took ${endTs - startTs} ms$wrapStr") - ret - } -} http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/f2311f25/test/benchmark/GraphUtilSpec.scala ---------------------------------------------------------------------- diff --git a/test/benchmark/GraphUtilSpec.scala b/test/benchmark/GraphUtilSpec.scala deleted file mode 100644 index b5ce93a..0000000 --- a/test/benchmark/GraphUtilSpec.scala +++ /dev/null @@ -1,125 +0,0 @@ -package benchmark - -import com.kakao.s2graph.core.{Management, GraphUtil} -import com.kakao.s2graph.core.types.{SourceVertexId, HBaseType, InnerVal, VertexId} -import org.apache.hadoop.hbase.util.Bytes -import play.api.test.{FakeApplication, PlaySpecification} - -import scala.collection.mutable -import scala.collection.mutable.ListBuffer -import scala.util.Random - -class GraphUtilSpec extends BenchmarkCommon with PlaySpecification { - - def between(bytes: Array[Byte], startKey: Array[Byte], endKey: Array[Byte]): Boolean = - Bytes.compareTo(startKey, bytes) <= 0 && Bytes.compareTo(endKey, bytes) >= 0 - - def betweenShort(value: Short, start: Short, end: Short): Boolean = - start <= value && value <= end - - - "GraphUtil" should { - "test murmur3 hash function distribution" in { - val testNum = 1000000 - val bucketSize = Short.MaxValue / 40 - val countsNew = new mutable.HashMap[Int, Int]() - val counts = new mutable.HashMap[Int, Int]() - for { - i <- (0 until testNum) - } { - val h = GraphUtil.murmur3(i.toString) / bucketSize - val hNew = GraphUtil.murmur3Int(i.toString) / bucketSize - counts += (h -> (counts.getOrElse(h, 0) + 1)) - countsNew += (hNew -> (countsNew.getOrElse(hNew, 0) + 1)) - } - val all = counts.toList.sortBy { case (bucket, count) => count }.reverse - val allNew = countsNew.toList.sortBy { case (bucket, count) => count }.reverse - val top = all.take(10) - val bottom = all.takeRight(10) - val topNew = allNew.take(10) - val bottomNew = allNew.takeRight(10) - println(s"Top: $top") - println(s"Bottom: $bottom") - println("-" * 50) - println(s"TopNew: $topNew") - println(s"Bottom: $bottomNew") - true - } - - "test murmur hash skew2" in { - running(FakeApplication()) { - import HBaseType._ - val testNum = 1000000L - val regionCount = 40 - val window = Int.MaxValue / regionCount - val rangeBytes = new ListBuffer[(List[Byte], List[Byte])]() - for { - i <- (0 until regionCount) - } yield { - val startKey = Bytes.toBytes(i * window) - val endKey = Bytes.toBytes((i + 1) * window) - rangeBytes += (startKey.toList -> endKey.toList) - } - - - - val stats = new collection.mutable.HashMap[Int, ((List[Byte], List[Byte]), Long)]() - val counts = new collection.mutable.HashMap[Short, Long]() - stats += (0 -> (rangeBytes.head -> 0L)) - - for (i <- (0L until testNum)) { - val vertexId = SourceVertexId(DEFAULT_COL_ID, InnerVal.withLong(i, HBaseType.DEFAULT_VERSION)) - val bytes = vertexId.bytes - val shortKey = GraphUtil.murmur3(vertexId.innerId.toIdString()) - val shortVal = counts.getOrElse(shortKey, 0L) + 1L - counts += (shortKey -> shortVal) - var j = 0 - var found = false - while (j < rangeBytes.size && !found) { - val (start, end) = rangeBytes(j) - if (between(bytes, start.toArray, end.toArray)) { - found = true - } - j += 1 - } - val head = rangeBytes(j - 1) - val key = j - 1 - val value = stats.get(key) match { - case None => 0L - case Some(v) => v._2 + 1 - } - stats += (key -> (head, value)) - } - val sorted = stats.toList.sortBy(kv => kv._2._2).reverse - println(s"Index: StartBytes ~ EndBytes\tStartShortBytes ~ EndShortBytes\tStartShort ~ EndShort\tCount\tShortCount") - sorted.foreach { case (idx, ((start, end), cnt)) => - val startShort = Bytes.toShort(start.take(2).toArray) - val endShort = Bytes.toShort(end.take(2).toArray) - val count = counts.count(t => startShort <= t._1 && t._1 < endShort) - println(s"$idx: $start ~ $end\t${start.take(2)} ~ ${end.take(2)}\t$startShort ~ $endShort\t$cnt\t$count") - - } - println("\n" * 10) - println(s"Index: StartBytes ~ EndBytes\tStartShortBytes ~ EndShortBytes\tStartShort ~ EndShort\tCount\tShortCount") - stats.toList.sortBy(kv => kv._1).reverse.foreach { case (idx, ((start, end), cnt)) => - val startShort = Bytes.toShort(start.take(2).toArray) - val endShort = Bytes.toShort(end.take(2).toArray) - val count = counts.count(t => startShort <= t._1 && t._1 < endShort) - println(s"$idx: $start ~ $end\t${start.take(2)} ~ ${end.take(2)}\t$startShort ~ $endShort\t$cnt\t$count") - - } - } - true - } - - "Bytes compareTo" in { - val x = Array[Byte](11, -12, -26, -14, -23) - val startKey = Array[Byte](0, 0, 0, 0) - val endKey = Array[Byte](12, -52, -52, -52) - println(Bytes.compareTo(startKey, x)) - println(Bytes.compareTo(endKey, x)) - true - } - } - -} http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/f2311f25/test/benchmark/JsonBenchmarkSpec.scala ---------------------------------------------------------------------- diff --git a/test/benchmark/JsonBenchmarkSpec.scala b/test/benchmark/JsonBenchmarkSpec.scala deleted file mode 100644 index bf24ed7..0000000 --- a/test/benchmark/JsonBenchmarkSpec.scala +++ /dev/null @@ -1,46 +0,0 @@ -package benchmark - -import play.api.libs.json.JsNumber -import play.api.test.{FakeApplication, PlaySpecification, WithApplication} -import play.libs.Json - -class JsonBenchmarkSpec extends BenchmarkCommon with PlaySpecification { - "to json" should { - implicit val app = FakeApplication() - - "json benchmark" in new WithApplication(app) { - - duration("map to json") { - (0 to 100) foreach { n => - val numberMaps = (0 to 100).map { n => (n.toString -> JsNumber(n * n)) }.toMap - Json.toJson(numberMaps) - } - } - - duration("directMakeJson") { - (0 to 100) foreach { n => - var jsObj = play.api.libs.json.Json.obj() - (0 to 100).foreach { n => - jsObj += (n.toString -> JsNumber(n * n)) - } - } - } - - duration("map to json 2") { - (0 to 500) foreach { n => - val numberMaps = (0 to 100).map { n => (n.toString -> JsNumber(n * n)) }.toMap - Json.toJson(numberMaps) - } - } - - duration("directMakeJson 2") { - (0 to 500) foreach { n => - var jsObj = play.api.libs.json.Json.obj() - (0 to 100).foreach { n => - jsObj += (n.toString -> JsNumber(n * n)) - } - } - } - } - } -} http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/f2311f25/test/benchmark/OrderingUtilBenchmarkSpec.scala ---------------------------------------------------------------------- diff --git a/test/benchmark/OrderingUtilBenchmarkSpec.scala b/test/benchmark/OrderingUtilBenchmarkSpec.scala deleted file mode 100644 index d38ff5e..0000000 --- a/test/benchmark/OrderingUtilBenchmarkSpec.scala +++ /dev/null @@ -1,103 +0,0 @@ -package benchmark - -import com.kakao.s2graph.core.OrderingUtil._ -import com.kakao.s2graph.core.SeqMultiOrdering -import play.api.libs.json.{JsNumber, JsValue} -import play.api.test.PlaySpecification -import play.api.{Application => PlayApplication} - -import scala.util.Random - -/** - * Created by hsleep([email protected]) on 2015. 11. 9.. - */ -class OrderingUtilBenchmarkSpec extends BenchmarkCommon with PlaySpecification { - "OrderingUtilBenchmarkSpec" should { - - "performance MultiOrdering any" >> { - val tupLs = (0 until 10) map { i => - Random.nextDouble() -> Random.nextLong() - } - - val seqLs = tupLs.map { tup => - Seq(tup._1, tup._2) - } - - val sorted1 = duration("TupleOrdering double,long") { - (0 until 10000) foreach { _ => - tupLs.sortBy { case (x, y) => - -x -> -y - } - } - tupLs.sortBy { case (x, y) => - -x -> -y - } - }.map { x => x._1 } - - val sorted2 = duration("MultiOrdering double,long") { - (0 until 10000) foreach { _ => - seqLs.sorted(new SeqMultiOrdering[Any](Seq(false, false))) - } - seqLs.sorted(new SeqMultiOrdering[Any](Seq(false, false))) - }.map { x => x.head } - - sorted1.toString() must_== sorted2.toString() - } - - "performance MultiOrdering double" >> { - val tupLs = (0 until 500) map { i => - Random.nextDouble() -> Random.nextDouble() - } - - val seqLs = tupLs.map { tup => - Seq(tup._1, tup._2) - } - - duration("MultiOrdering double") { - (0 until 10000) foreach { _ => - seqLs.sorted(new SeqMultiOrdering[Double](Seq(false, false))) - } - } - - duration("TupleOrdering double") { - (0 until 10000) foreach { _ => - tupLs.sortBy { case (x, y) => - -x -> -y - } - } - } - - 1 must_== 1 - } - - "performance MultiOrdering jsvalue" >> { - val tupLs = (0 until 500) map { i => - Random.nextDouble() -> Random.nextLong() - } - - val seqLs = tupLs.map { tup => - Seq(JsNumber(tup._1), JsNumber(tup._2)) - } - - val sorted1 = duration("TupleOrdering double,long") { - (0 until 10000) foreach { _ => - tupLs.sortBy { case (x, y) => - -x -> -y - } - } - tupLs.sortBy { case (x, y) => - -x -> -y - } - } - - val sorted2 = duration("MultiOrdering jsvalue") { - (0 until 10000) foreach { _ => - seqLs.sorted(new SeqMultiOrdering[JsValue](Seq(false, false))) - } - seqLs.sorted(new SeqMultiOrdering[JsValue](Seq(false, false))) - } - - 1 must_== 1 - } - } -} http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/f2311f25/test/benchmark/PostProcessBenchmarkSpec.scala ---------------------------------------------------------------------- diff --git a/test/benchmark/PostProcessBenchmarkSpec.scala b/test/benchmark/PostProcessBenchmarkSpec.scala deleted file mode 100644 index 70644d6..0000000 --- a/test/benchmark/PostProcessBenchmarkSpec.scala +++ /dev/null @@ -1,238 +0,0 @@ -package benchmark - -import com.kakao.s2graph.core.mysqls.Label -import com.kakao.s2graph.core.{Graph, Management} -import controllers._ -import play.api.libs.json.{JsValue, Json} -import play.api.test.{FakeApplication, FakeRequest, PlaySpecification} - -import scala.concurrent.Await -import scala.concurrent.duration._ - -/** - * Created by hsleep([email protected]) on 2015. 11. 6.. - */ -class PostProcessBenchmarkSpec extends SpecCommon with BenchmarkCommon with PlaySpecification { - sequential - - import Helper._ - - init() - - override def init() = { - running(FakeApplication()) { - println("[init start]: >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>") - Management.deleteService(testServiceName) - - // 1. createService - val result = AdminController.createServiceInner(Json.parse(createService)) - println(s">> Service created : $createService, $result") - - val labelNames = Map( - testLabelNameWeak -> testLabelNameWeakCreate - ) - - for { - (labelName, create) <- labelNames - } { - Management.deleteLabel(labelName) - Label.findByName(labelName, useCache = false) match { - case None => - AdminController.createLabelInner(Json.parse(create)) - case Some(label) => - println(s">> Label already exist: $create, $label") - } - } - - // create edges - val bulkEdges: String = (0 until 500).map { i => - edge"${System.currentTimeMillis()} insert e 0 $i $testLabelNameWeak"($(weight=i)) - }.mkString("\n") - - val jsResult = contentAsJson(EdgeController.mutateAndPublish(bulkEdges, withWait = true)) - - println("[init end]: >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>") - } - } - - def getEdges(queryJson: JsValue): JsValue = { - val ret = route(FakeRequest(POST, "/graphs/getEdges").withJsonBody(queryJson)).get - contentAsJson(ret) - } - - val s2: Graph = com.kakao.s2graph.rest.Global.s2graph - -// "test performance of getEdges orderBy" >> { -// running(FakeApplication()) { -// val strJs = -// s""" -// |{ -// | "orderBy": [ -// | {"score": "DESC"}, -// | {"timestamp": "DESC"} -// | ], -// | "srcVertices": [ -// | { -// | "serviceName": "$testServiceName", -// | "columnName": "$testColumnName", -// | "ids": [0] -// | } -// | ], -// | "steps": [ -// | { -// | "step": [ -// | { -// | "cacheTTL": 60000, -// | "label": "$testLabelNameWeak", -// | "offset": 0, -// | "limit": -1, -// | "direction": "out", -// | "scoring": [ -// | {"weight": 1} -// | ] -// | } -// | ] -// | } -// | ] -// |} -// """.stripMargin -// -// object Parser extends RequestParser -// -// val js = Json.parse(strJs) -// -// val q = Parser.toQuery(js) -// -// val queryResultLs = Await.result(s2.getEdges(q), 1 seconds) -// -// val resultJs = PostProcess.toSimpleVertexArrJson(queryResultLs) -// -// (resultJs \ "size").as[Int] must_== 500 -// -// (0 to 5) foreach { _ => -// duration("toSimpleVertexArrJson new orderBy") { -// (0 to 1000) foreach { _ => -// PostProcess.toSimpleVertexArrJson(queryResultLs, Nil) -// } -// } -// } -// -// (resultJs \ "size").as[Int] must_== 500 -// } -// } - - "test performance of getEdges" >> { - running(FakeApplication()) { - val strJs = - s""" - |{ - | "srcVertices": [ - | { - | "serviceName": "$testServiceName", - | "columnName": "$testColumnName", - | "ids": [0] - | } - | ], - | "steps": [ - | { - | "step": [ - | { - | "cacheTTL": 60000, - | "label": "$testLabelNameWeak", - | "offset": 0, - | "limit": -1, - | "direction": "out", - | "scoring": [ - | {"weight": 1} - | ] - | } - | ] - | } - | ] - |} - """.stripMargin - - object Parser extends RequestParser - - val js = Json.parse(strJs) - - val q = Parser.toQuery(js) - - val queryResultLs = Await.result(s2.getEdges(q), 1 seconds) - - val resultJs = PostProcess.toSimpleVertexArrJson(queryResultLs, Nil) - - (0 to 5) foreach { _ => - duration("toSimpleVertexArrJson new") { - (0 to 1000) foreach { _ => - PostProcess.toSimpleVertexArrJson(queryResultLs, Nil) - } - } - } - - (resultJs \ "size").as[Int] must_== 500 - } - } - -// "test performance of getEdges withScore=false" >> { -// running(FakeApplication()) { -// val strJs = -// s""" -// |{ -// | "withScore": false, -// | "srcVertices": [ -// | { -// | "serviceName": "$testServiceName", -// | "columnName": "$testColumnName", -// | "ids": [0] -// | } -// | ], -// | "steps": [ -// | { -// | "step": [ -// | { -// | "cacheTTL": 60000, -// | "label": "$testLabelNameWeak", -// | "offset": 0, -// | "limit": -1, -// | "direction": "out", -// | "scoring": [ -// | {"weight": 1} -// | ] -// | } -// | ] -// | } -// | ] -// |} -// """.stripMargin -// -// object Parser extends RequestParser -// -// val js = Json.parse(strJs) -// -// val q = Parser.toQuery(js) -// -// val queryResultLs = Await.result(s2.getEdges(q), 1 seconds) -// -// val resultJs = PostProcess.toSimpleVertexArrJson(queryResultLs) -// -// (resultJs \ "size").as[Int] must_== 500 -// -// (0 to 5) foreach { _ => -// duration("toSimpleVertexArrJson withScore=false org") { -// (0 to 1000) foreach { _ => -// PostProcess.toSimpleVertexArrJsonOrg(queryResultLs, Nil) -// } -// } -// -// duration("toSimpleVertexArrJson withScore=false new") { -// (0 to 1000) foreach { _ => -// PostProcess.toSimpleVertexArrJson(queryResultLs, Nil) -// } -// } -// } -// -// (resultJs \ "size").as[Int] must_== 500 -// } -// } -} http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/f2311f25/test/benchmark/SamplingBenchmarkSpec.scala ---------------------------------------------------------------------- diff --git a/test/benchmark/SamplingBenchmarkSpec.scala b/test/benchmark/SamplingBenchmarkSpec.scala deleted file mode 100644 index 8943a62..0000000 --- a/test/benchmark/SamplingBenchmarkSpec.scala +++ /dev/null @@ -1,90 +0,0 @@ -package benchmark - -/** - * Created by jojo on 12/1/15. - */ - -import play.api.test.{FakeApplication, PlaySpecification, WithApplication} -import scala.annotation.tailrec -import scala.util.Random - -class SamplingBenchmarkSpec extends BenchmarkCommon with PlaySpecification { - "to json" should { - implicit val app = FakeApplication() - - "json benchmark" in new WithApplication(app) { - @tailrec - def randomInt(n: Int, range: Int, set: Set[Int] = Set.empty[Int]): Set[Int] = { - if (set.size == n) set - else randomInt(n, range, set + Random.nextInt(range)) - } - - // sample using random array - def randomArraySample[T](num: Int, ls: List[T]): List[T] = { - val randomNum = randomInt(num, ls.size) - var sample = List.empty[T] - var idx = 0 - ls.foreach { e => - if (randomNum.contains(idx)) sample = e :: sample - idx += 1 - } - sample - } - - // sample using shuffle - def shuffleSample[T](num: Int, ls: List[T]): List[T] = { - Random.shuffle(ls).take(num) - } - - // sample using random number generation - def rngSample[T](num: Int, ls: List[T]): List[T] = { - var sampled = List.empty[T] - val N = ls.size // population - var t = 0 // total input records dealt with - var m = 0 // number of items selected so far - - while (m < num) { - val u = Random.nextDouble() - if ( (N - t)*u < num - m) { - sampled = ls(t) :: sampled - m += 1 - } - t += 1 - } - sampled - } - - // test data - val testLimit = 500000 - val testNum = 10 - val testData = (0 to 1000).toList - - // dummy for warm-up - (0 to testLimit) foreach { n => - randomArraySample(testNum, testData) - shuffleSample(testNum, testData) - rngSample(testNum, testData) - } - - duration("Random Array Sampling") { - (0 to testLimit) foreach { _ => - val sampled = randomArraySample(testNum, testData) - } - } - - duration("Shuffle Sampling") { - (0 to testLimit) foreach { _ => - val sampled = shuffleSample(testNum, testData) - } - } - - duration("RNG Sampling") { - (0 to testLimit) foreach { _ => - val sampled = rngSample(testNum, testData) - } - } - } - - - } -} http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/f2311f25/test/controllers/AdminControllerSpec.scala ---------------------------------------------------------------------- diff --git a/test/controllers/AdminControllerSpec.scala b/test/controllers/AdminControllerSpec.scala deleted file mode 100644 index e41fccb..0000000 --- a/test/controllers/AdminControllerSpec.scala +++ /dev/null @@ -1,27 +0,0 @@ -package controllers - -import com.kakao.s2graph.core.mysqls.Label -import play.api.http.HeaderNames -import play.api.test.Helpers._ -import play.api.test.{FakeApplication, FakeRequest} - -import scala.concurrent.Await - -/** - * Created by mojo22jojo([email protected]) on 15. 10. 13.. - */ -class AdminControllerSpec extends SpecCommon { - init() - "EdgeControllerSpec" should { - "update htable" in { - running(FakeApplication()) { - val insertUrl = s"/graphs/updateHTable/$testLabelName/$newHTableName" - - val req = FakeRequest("POST", insertUrl).withBody("").withHeaders(HeaderNames.CONTENT_TYPE -> "text/plain") - - Await.result(route(req).get, HTTP_REQ_WAITING_TIME) - Label.findByName(testLabelName, useCache = true).get.hTableName mustEqual newHTableName - } - } - } -} http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/f2311f25/test/controllers/BasicCrudSpec.scala ---------------------------------------------------------------------- diff --git a/test/controllers/BasicCrudSpec.scala b/test/controllers/BasicCrudSpec.scala deleted file mode 100644 index f4f11b4..0000000 --- a/test/controllers/BasicCrudSpec.scala +++ /dev/null @@ -1,251 +0,0 @@ -package controllers - -import com.kakao.s2graph.core.Management -import com.kakao.s2graph.core.mysqls._ - -//import com.kakao.s2graph.core.models._ - -import play.api.libs.json._ -import play.api.test.Helpers._ -import play.api.test.{FakeApplication, FakeRequest} - -import scala.concurrent.Await - - -class BasicCrudSpec extends SpecCommon { - sequential - - var seed = 0 - def runTC(tcNum: Int, tcString: String, opWithProps: List[(Long, String, String)], expected: Map[String, String]) = { - for { - labelName <- List(testLabelName, testLabelName2) - i <- 0 until NUM_OF_EACH_TEST - } { - seed += 1 -// val srcId = ((tcNum * 1000) + i).toString -// val tgtId = if (labelName == testLabelName) s"${srcId + 1000 + i}" else s"${srcId + 1000 + i}abc" - val srcId = seed.toString - val tgtId = srcId - - val maxTs = opWithProps.map(t => t._1).max - - /** insert edges */ - println(s"---- TC${tcNum}_init ----") - val bulkEdge = (for ((ts, op, props) <- opWithProps) yield { - List(ts, op, "e", srcId, tgtId, labelName, props).mkString("\t") - }).mkString("\n") - - val req = EdgeController.mutateAndPublish(bulkEdge, withWait = true) - val res = Await.result(req, HTTP_REQ_WAITING_TIME) - - res.header.status must equalTo(200) - - println(s"---- TC${tcNum}_init ----") -// Thread.sleep(100) - - for { - label <- Label.findByName(labelName) - direction <- List("out", "in") - cacheTTL <- List(-1L) - } { - val (serviceName, columnName, id, otherId) = direction match { - case "out" => (label.srcService.serviceName, label.srcColumn.columnName, srcId, tgtId) - case "in" => (label.tgtService.serviceName, label.tgtColumn.columnName, tgtId, srcId) - } - val qId = if (labelName == testLabelName) id else "\"" + id + "\"" - val query = queryJson(serviceName, columnName, labelName, qId, direction, cacheTTL) - val ret = route(FakeRequest(POST, "/graphs/getEdges").withJsonBody(query)).get - val jsResult = commonCheck(ret) - - val results = jsResult \ "results" - val deegrees = (jsResult \ "degrees").as[List[JsObject]] - val propsLs = (results \\ "props").seq - (deegrees.head \ LabelMeta.degree.name).as[Int] must equalTo(1) - - val from = (results \\ "from").seq.last.toString.replaceAll("\"", "") - val to = (results \\ "to").seq.last.toString.replaceAll("\"", "") - - from must equalTo(id.toString) - to must equalTo(otherId.toString) -// (results \\ "_timestamp").seq.last.as[Long] must equalTo(maxTs) - for ((key, expectedVal) <- expected) { - propsLs.last.as[JsObject].keys.contains(key) must equalTo(true) - (propsLs.last \ key).toString must equalTo(expectedVal) - } - Await.result(ret, HTTP_REQ_WAITING_TIME) - } - } - } - - init() - "Basic Crud " should { - "tc1" in { - running(FakeApplication()) { - - var tcNum = 0 - var tcString = "" - var bulkQueries = List.empty[(Long, String, String)] - var expected = Map.empty[String, String] - - tcNum = 7 - tcString = "[t1 -> t2 -> t3 test case] insert(t1) delete(t2) insert(t3) test " - bulkQueries = List( - (t1, "insert", "{\"time\": 10}"), - (t2, "delete", ""), - (t3, "insert", "{\"time\": 10, \"weight\": 20}")) - expected = Map("time" -> "10", "weight" -> "20") - - runTC(tcNum, tcString, bulkQueries, expected) - - tcNum = 8 - tcString = "[t1 -> t2 -> t3 test case] insert(t1) delete(t2) insert(t3) test " - bulkQueries = List( - (t1, "insert", "{\"time\": 10}"), - (t3, "insert", "{\"time\": 10, \"weight\": 20}"), - (t2, "delete", "")) - expected = Map("time" -> "10", "weight" -> "20") - - runTC(tcNum, tcString, bulkQueries, expected) - - tcNum = 9 - tcString = "[t3 -> t2 -> t1 test case] insert(t3) delete(t2) insert(t1) test " - bulkQueries = List( - (t3, "insert", "{\"time\": 10, \"weight\": 20}"), - (t2, "delete", ""), - (t1, "insert", "{\"time\": 10}")) - expected = Map("time" -> "10", "weight" -> "20") - - runTC(tcNum, tcString, bulkQueries, expected) - - tcNum = 10 - tcString = "[t3 -> t1 -> t2 test case] insert(t3) insert(t1) delete(t2) test " - bulkQueries = List( - (t3, "insert", "{\"time\": 10, \"weight\": 20}"), - (t1, "insert", "{\"time\": 10}"), - (t2, "delete", "")) - expected = Map("time" -> "10", "weight" -> "20") - - runTC(tcNum, tcString, bulkQueries, expected) - - tcNum = 11 - tcString = "[t2 -> t1 -> t3 test case] delete(t2) insert(t1) insert(t3) test" - bulkQueries = List( - (t2, "delete", ""), - (t1, "insert", "{\"time\": 10}"), - (t3, "insert", "{\"time\": 10, \"weight\": 20}")) - expected = Map("time" -> "10", "weight" -> "20") - - runTC(tcNum, tcString, bulkQueries, expected) - - tcNum = 12 - tcString = "[t2 -> t3 -> t1 test case] delete(t2) insert(t3) insert(t1) test " - bulkQueries = List( - (t2, "delete", ""), - (t3, "insert", "{\"time\": 10, \"weight\": 20}"), - (t1, "insert", "{\"time\": 10}")) - expected = Map("time" -> "10", "weight" -> "20") - - runTC(tcNum, tcString, bulkQueries, expected) - - tcNum = 13 - tcString = "[t1 -> t2 -> t3 test case] update(t1) delete(t2) update(t3) test " - bulkQueries = List( - (t1, "update", "{\"time\": 10}"), - (t2, "delete", ""), - (t3, "update", "{\"time\": 10, \"weight\": 20}")) - expected = Map("time" -> "10", "weight" -> "20") - - runTC(tcNum, tcString, bulkQueries, expected) - tcNum = 14 - tcString = "[t1 -> t3 -> t2 test case] update(t1) update(t3) delete(t2) test " - bulkQueries = List( - (t1, "update", "{\"time\": 10}"), - (t3, "update", "{\"time\": 10, \"weight\": 20}"), - (t2, "delete", "")) - expected = Map("time" -> "10", "weight" -> "20") - - runTC(tcNum, tcString, bulkQueries, expected) - tcNum = 15 - tcString = "[t2 -> t1 -> t3 test case] delete(t2) update(t1) update(t3) test " - bulkQueries = List( - (t2, "delete", ""), - (t1, "update", "{\"time\": 10}"), - (t3, "update", "{\"time\": 10, \"weight\": 20}")) - expected = Map("time" -> "10", "weight" -> "20") - - runTC(tcNum, tcString, bulkQueries, expected) - tcNum = 16 - tcString = "[t2 -> t3 -> t1 test case] delete(t2) update(t3) update(t1) test" - bulkQueries = List( - (t2, "delete", ""), - (t3, "update", "{\"time\": 10, \"weight\": 20}"), - (t1, "update", "{\"time\": 10}")) - expected = Map("time" -> "10", "weight" -> "20") - - runTC(tcNum, tcString, bulkQueries, expected) - tcNum = 17 - tcString = "[t3 -> t2 -> t1 test case] update(t3) delete(t2) update(t1) test " - bulkQueries = List( - (t3, "update", "{\"time\": 10, \"weight\": 20}"), - (t2, "delete", ""), - (t1, "update", "{\"time\": 10}")) - expected = Map("time" -> "10", "weight" -> "20") - - runTC(tcNum, tcString, bulkQueries, expected) - tcNum = 18 - tcString = "[t3 -> t1 -> t2 test case] update(t3) update(t1) delete(t2) test " - bulkQueries = List( - (t3, "update", "{\"time\": 10, \"weight\": 20}"), - (t1, "update", "{\"time\": 10}"), - (t2, "delete", "")) - expected = Map("time" -> "10", "weight" -> "20") - - runTC(tcNum, tcString, bulkQueries, expected) - - tcNum = 19 - tcString = "[t5 -> t1 -> t3 -> t2 -> t4 test case] update(t5) insert(t1) insert(t3) delete(t2) update(t4) test " - bulkQueries = List( - (t5, "update", "{\"is_blocked\": true}"), - (t1, "insert", "{\"is_hidden\": false}"), - (t3, "insert", "{\"is_hidden\": false, \"weight\": 10}"), - (t2, "delete", ""), - (t4, "update", "{\"time\": 1, \"weight\": -10}")) - expected = Map("time" -> "1", "weight" -> "-10", "is_hidden" -> "false", "is_blocked" -> "true") - - runTC(tcNum, tcString, bulkQueries, expected) - true - } - } - } - - "toLogString" in { - running(FakeApplication()) { - val bulkQueries = List( - ("1445240543366", "update", "{\"is_blocked\":true}"), - ("1445240543362", "insert", "{\"is_hidden\":false}"), - ("1445240543364", "insert", "{\"is_hidden\":false,\"weight\":10}"), - ("1445240543363", "delete", "{}"), - ("1445240543365", "update", "{\"time\":1, \"weight\":-10}")) - - val (srcId, tgtId, labelName) = ("1", "2", testLabelName) - - val bulkEdge = (for ((ts, op, props) <- bulkQueries) yield { - Management.toEdge(ts.toLong, op, srcId, tgtId, labelName, "out", props).toLogString - }).mkString("\n") - - val expected = Seq( - Seq("1445240543366", "update", "e", "1", "2", "s2graph_label_test", "{\"is_blocked\":true}"), - Seq("1445240543362", "insert", "e", "1", "2", "s2graph_label_test", "{\"is_hidden\":false}"), - Seq("1445240543364", "insert", "e", "1", "2", "s2graph_label_test", "{\"is_hidden\":false,\"weight\":10}"), - Seq("1445240543363", "delete", "e", "1", "2", "s2graph_label_test"), - Seq("1445240543365", "update", "e", "1", "2", "s2graph_label_test", "{\"time\":1,\"weight\":-10}") - ).map(_.mkString("\t")).mkString("\n") - - bulkEdge must equalTo(expected) - - true - } - } -} - - http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/f2311f25/test/controllers/EdgeControllerSpec.scala ---------------------------------------------------------------------- diff --git a/test/controllers/EdgeControllerSpec.scala b/test/controllers/EdgeControllerSpec.scala deleted file mode 100644 index e76404a..0000000 --- a/test/controllers/EdgeControllerSpec.scala +++ /dev/null @@ -1,22 +0,0 @@ -package controllers - -import play.api.http.HeaderNames -import play.api.test.{FakeApplication, FakeRequest, PlaySpecification, WithApplication} -import play.api.{Application => PlayApplication} - -/** - * Created by hsleep([email protected]) on 15. 9. 1.. - */ -class EdgeControllerSpec extends PlaySpecification { -// "EdgeControllerSpec" should { -// implicit val app = FakeApplication() -// -// "bad request invalid json" in new WithApplication(app) { -// val insertUrl = "http://localhost:9000/graphs/edges/insert" -// val req = FakeRequest("POST", insertUrl).withBody("").withHeaders(HeaderNames.CONTENT_TYPE -> "application/json") -// val result = EdgeController.inserts().apply(req).run -// -// status(result) must_== BAD_REQUEST -// } -// } -} http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/f2311f25/test/controllers/PostProcessSpec.scala ---------------------------------------------------------------------- diff --git a/test/controllers/PostProcessSpec.scala b/test/controllers/PostProcessSpec.scala deleted file mode 100644 index 9573791..0000000 --- a/test/controllers/PostProcessSpec.scala +++ /dev/null @@ -1,115 +0,0 @@ -package controllers - -import com.kakao.s2graph.core.SeqMultiOrdering -import com.kakao.s2graph.core.OrderingUtil._ -import play.api.libs.json.{JsNumber, JsString, JsValue} -import play.api.test.PlaySpecification - -/** - * Created by hsleep on 2015. 11. 4.. - */ -class PostProcessSpec extends SpecCommon with PlaySpecification { - - "test order by json" >> { - val jsLs: Seq[Seq[JsValue]] = Seq( - Seq(JsNumber(0), JsString("a")), - Seq(JsNumber(0), JsString("b")), - Seq(JsNumber(1), JsString("a")), - Seq(JsNumber(1), JsString("b")), - Seq(JsNumber(2), JsString("c")) - ) - - // number descending, string ascending - val sortedJsLs: Seq[Seq[JsValue]] = Seq( - Seq(JsNumber(2), JsString("c")), - Seq(JsNumber(1), JsString("a")), - Seq(JsNumber(1), JsString("b")), - Seq(JsNumber(0), JsString("a")), - Seq(JsNumber(0), JsString("b")) - ) - - val orderParam: Seq[Boolean] = Seq(false, true) - val resultJsLs = jsLs.sorted(new Ordering[Seq[JsValue]] { - override def compare(x: Seq[JsValue], y: Seq[JsValue]): Int = { - val xe = x.iterator - val ye = y.iterator - val oe = orderParam.iterator - - while (xe.hasNext && ye.hasNext && oe.hasNext) { - val (xev, yev) = oe.next() match { - case true => xe.next() -> ye.next() - case false => ye.next() -> xe.next() - } - val res = (xev, yev) match { - case (JsNumber(xv), JsNumber(yv)) => - Ordering[BigDecimal].compare(xv, yv) - case (JsString(xv), JsString(yv)) => - Ordering[String].compare(xv, yv) - case _ => throw new Exception("type mismatch") - } - if (res != 0) return res - } - - Ordering.Boolean.compare(xe.hasNext, ye.hasNext) - } - }) - - resultJsLs.toString() must_== sortedJsLs.toString - } - - "test order by primitive type" >> { - val jsLs: Seq[Seq[Any]] = Seq( - Seq(0, "a"), - Seq(0, "b"), - Seq(1, "a"), - Seq(1, "b"), - Seq(2, "c") - ) - - // number descending, string ascending - val sortedJsLs: Seq[Seq[Any]] = Seq( - Seq(2, "c"), - Seq(1, "a"), - Seq(1, "b"), - Seq(0, "a"), - Seq(0, "b") - ) - - val ascendingLs: Seq[Boolean] = Seq(false, true) - val resultJsLs = jsLs.sorted(new SeqMultiOrdering[Any](ascendingLs)) - - resultJsLs.toString() must_== sortedJsLs.toString - } - - "test order by primitive type with short ascending list" >> { - val jsLs: Seq[Seq[Any]] = Seq( - Seq(0, "a"), - Seq(1, "b"), - Seq(0, "b"), - Seq(1, "a"), - Seq(2, "c"), - Seq(1, "c"), - Seq(1, "d"), - Seq(1, "f"), - Seq(1, "e") - ) - - // number descending, string ascending(default) - val sortedJsLs: Seq[Seq[Any]] = Seq( - Seq(2, "c"), - Seq(1, "a"), - Seq(1, "b"), - Seq(1, "c"), - Seq(1, "d"), - Seq(1, "e"), - Seq(1, "f"), - Seq(0, "a"), - Seq(0, "b") - ) - - val ascendingLs: Seq[Boolean] = Seq(false) - val resultJsLs = jsLs.sorted(new SeqMultiOrdering[Any](ascendingLs)) - - resultJsLs.toString() must_== sortedJsLs.toString - } -} http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/f2311f25/test/controllers/QueryCacheSpec.scala ---------------------------------------------------------------------- diff --git a/test/controllers/QueryCacheSpec.scala b/test/controllers/QueryCacheSpec.scala deleted file mode 100644 index 7d91aa9..0000000 --- a/test/controllers/QueryCacheSpec.scala +++ /dev/null @@ -1,89 +0,0 @@ -//package test.controllers -// -////import com.kakao.s2graph.core.models._ -// -//import controllers.EdgeController -//import play.api.libs.json._ -//import play.api.test.Helpers._ -//import play.api.test.{FakeApplication, FakeRequest} -// -//class QueryCacheSpec extends SpecCommon { -// init() -// -// "cache test" should { -// def queryWithTTL(id: Int, cacheTTL: Long) = Json.parse( s""" -// { "srcVertices": [ -// { "serviceName": "${testServiceName}", -// "columnName": "${testColumnName}", -// "id": ${id} -// }], -// "steps": [[ { -// "label": "${testLabelName}", -// "direction": "out", -// "offset": 0, -// "limit": 10, -// "cacheTTL": ${cacheTTL}, -// "scoring": {"weight": 1} }]] -// }""") -// -// def getEdges(queryJson: JsValue): JsValue = { -// var ret = route(FakeRequest(POST, "/graphs/getEdges").withJsonBody(queryJson)).get -// contentAsJson(ret) -// } -// -// // init -// running(FakeApplication()) { -// // insert bulk and wait .. -// val bulkEdges: String = Seq( -// Seq("1", "insert", "e", "0", "2", "s2graph_label_test", "{}").mkString("\t"), -// Seq("1", "insert", "e", "1", "2", "s2graph_label_test", "{}").mkString("\t") -// ).mkString("\n") -// -// val jsResult = contentAsJson(EdgeController.mutateAndPublish(bulkEdges, withWait = true)) -// Thread.sleep(asyncFlushInterval) -// } -// -// "tc1: query with {id: 0, ttl: 1000}" in { -// running(FakeApplication()) { -// var jsRslt = getEdges(queryWithTTL(0, 1000)) -// var cacheRemain = (jsRslt \\ "cacheRemain").head -// cacheRemain.as[Int] must greaterThan(500) -// -// // get edges from cache after wait 500ms -// Thread.sleep(500) -// val ret = route(FakeRequest(POST, "/graphs/getEdges").withJsonBody(queryWithTTL(0, 1000))).get -// jsRslt = contentAsJson(ret) -// cacheRemain = (jsRslt \\ "cacheRemain").head -// cacheRemain.as[Int] must lessThan(500) -// } -// } -// -// "tc2: query with {id: 1, ttl: 3000}" in { -// running(FakeApplication()) { -// var jsRslt = getEdges(queryWithTTL(1, 3000)) -// var cacheRemain = (jsRslt \\ "cacheRemain").head -// // before update: is_blocked is false -// (jsRslt \\ "is_blocked").head must equalTo(JsBoolean(false)) -// -// val bulkEdges = Seq( -// Seq("2", "update", "e", "0", "2", "s2graph_label_test", "{\"is_blocked\": true}").mkString("\t"), -// Seq("2", "update", "e", "1", "2", "s2graph_label_test", "{\"is_blocked\": true}").mkString("\t") -// ).mkString("\n") -// -// // update edges with {is_blocked: true} -// jsRslt = contentAsJson(EdgeController.mutateAndPublish(bulkEdges, withWait = true)) -// -// Thread.sleep(asyncFlushInterval) -// -// // prop 'is_blocked' still false, cause queryResult on cache -// jsRslt = getEdges(queryWithTTL(1, 3000)) -// (jsRslt \\ "is_blocked").head must equalTo(JsBoolean(false)) -// -// // after wait 3000ms prop 'is_blocked' is updated to true, cache cleared -// Thread.sleep(3000) -// jsRslt = getEdges(queryWithTTL(1, 3000)) -// (jsRslt \\ "is_blocked").head must equalTo(JsBoolean(true)) -// } -// } -// } -//}
