<commit_before>package test.controllers

import com.kakao.s2graph.core.Graph
import controllers.EdgeController
import play.api.libs.json._
import play.api.test.Helpers._
import play.api.test.{FakeApplication, FakeRequest}
import test.controllers.SpecCommon

import scala.util.Random

class StrongLabelDeleteSpec extends SpecCommon {
  init()

  def bulkEdges(startTs: Int = 0) = Seq(
    Seq(startTs + 1, "insert", "e", "0", "1", testLabelName2, s"""{"time": 10}""").mkString("\t"),
    Seq(startTs + 2, "insert", "e", "0", "1", testLabelName2, s"""{"time": 11}""").mkString("\t"),
    Seq(startTs + 3, "insert", "e", "0", "1", testLabelName2, s"""{"time": 12}""").mkString("\t"),
    Seq(startTs + 4, "insert", "e", "0", "2", testLabelName2, s"""{"time": 10}""").mkString("\t"),
    Seq(startTs + 5, "insert", "e", "10", "20", testLabelName2, s"""{"time": 10}""").mkString("\t"),
    Seq(startTs + 6, "insert", "e", "10", "21", testLabelName2, s"""{"time": 11}""").mkString("\t"),
    Seq(startTs + 7, "insert", "e", "11", "20", testLabelName2, s"""{"time": 12}""").mkString("\t"),
    Seq(startTs + 8, "insert", "e", "12", "20", testLabelName2, s"""{"time": 13}""").mkString("\t")
  ).mkString("\n")

  def query(id: Long, serviceName: String = testServiceName, columnName: String = testColumnName,
            labelName: String = testLabelName2, direction: String = "out") = Json.parse(
    s"""
        { "srcVertices": [
          { "serviceName": "$serviceName",
            "columnName": "$columnName",
            "id": $id
           }],
          "steps": [
          [ {
              "label": "$labelName",
              "direction": "${direction}",
              "offset": 0,
              "limit": 1000,
              "duplicate": "raw"
            }
          ]]
        }""")

  def getEdges(queryJson: JsValue): JsValue = {
    val ret = route(FakeRequest(POST, "/graphs/getEdges").withJsonBody(queryJson)).get
    contentAsJson(ret)
  }
  def getDegree(jsValue: JsValue): Long = {
    ((jsValue \ "degrees") \\ "_degree").headOption.map(_.as[Long]).getOrElse(0L)
  }


  "strong label delete test" should {
    running(FakeApplication()) {
      // insert bulk and wait ..
      val ret = route(FakeRequest(POST, "/graphs/edges/bulk").withBody(bulkEdges())).get
      val jsRslt = contentAsJson(ret)
      Thread.sleep(asyncFlushInterval)
    }




    "test strong consistency select" in {
      running(FakeApplication()) {
        var result = getEdges(query(0))
        println(result)
        (result \ "results").as[List[JsValue]].size must equalTo(2)
        result = getEdges(query(10))
        println(result)
        (result \ "results").as[List[JsValue]].size must equalTo(2)
        true
      }
    }

    "test strong consistency duration. insert -> delete -> insert" in {
      running(FakeApplication()) {
        val ts0 = 1
        val ts1 = 2
        val ts2 = 3

        val edges = Seq(
          Seq(5, "insert", "edge", "-10", "-20", testLabelName2).mkString("\t"),
          Seq(10, "delete", "edge", "-10", "-20", testLabelName2).mkString("\t"),
          Seq(20, "insert", "edge", "-10", "-20", testLabelName2).mkString("\t")
        ).mkString("\n")

        val ret = route(FakeRequest(POST, "/graphs/edges/bulk").withBody(edges)).get
        val jsRslt = contentAsJson(ret)

        Thread.sleep(asyncFlushInterval)
        var result = getEdges(query(-10))

        println(result)

        true
      }
    }

    "test strong consistency deleteAll" in {
      running(FakeApplication()) {
        val deletedAt = 100
        var result = getEdges(query(20, direction = "in", columnName = testTgtColumnName))
        println(result)
        (result \ "results").as[List[JsValue]].size must equalTo(3)



        val json = Json.arr(Json.obj("label" -> testLabelName2,
          "direction" -> "in", "ids" -> Json.arr("20"), "timestamp" -> deletedAt))
        println(json)
        EdgeController.deleteAllInner(json)
        Thread.sleep(asyncFlushInterval)


        result = getEdges(query(11, direction = "out"))
        println(result)
        (result \ "results").as[List[JsValue]].size must equalTo(0)

        result = getEdges(query(12, direction = "out"))
        println(result)
        (result \ "results").as[List[JsValue]].size must equalTo(0)

        result = getEdges(query(10, direction = "out"))
        println(result)
        // 10 -> out -> 20 should not be in result.
        (result \ "results").as[List[JsValue]].size must equalTo(1)
        (result \\ "to").size must equalTo(1)
        (result \\ "to").head.as[String] must equalTo("21")


        result = getEdges(query(20, direction = "in", columnName = testTgtColumnName))
        println(result)
        (result \ "results").as[List[JsValue]].size must equalTo(0)


        val ret = route(FakeRequest(POST, "/graphs/edges/bulk").withBody(bulkEdges(startTs = deletedAt + 1))).get
        val jsRslt = contentAsJson(ret)
        Thread.sleep(asyncFlushInterval)

        result = getEdges(query(20, direction = "in", columnName = testTgtColumnName))
        println(result)
        (result \ "results").as[List[JsValue]].size must equalTo(3)

        true

      }
    }
  }

  "largeSet of contention" should {
    val labelName = testLabelName2
    val maxTgtId = 5
    val maxRetryNum = 10
    val maxTestNum = 10
    val maxTestIntervalNum = 10
    def testInner(src: Long) = {<commit_msg>resolving #137 + add TC for degree check<commit_after>package test.controllers

import com.kakao.s2graph.core.Graph
import controllers.EdgeController
import play.api.libs.json._
import play.api.test.Helpers._
import play.api.test.{FakeApplication, FakeRequest}
import test.controllers.SpecCommon

import scala.util.Random

class StrongLabelDeleteSpec extends SpecCommon {
  init()

  def bulkEdges(startTs: Int = 0) = Seq(
    Seq(startTs + 1, "insert", "e", "0", "1", testLabelName2, s"""{"time": 10}""").mkString("\t"),
    Seq(startTs + 2, "insert", "e", "0", "1", testLabelName2, s"""{"time": 11}""").mkString("\t"),
    Seq(startTs + 3, "insert", "e", "0", "1", testLabelName2, s"""{"time": 12}""").mkString("\t"),
    Seq(startTs + 4, "insert", "e", "0", "2", testLabelName2, s"""{"time": 10}""").mkString("\t"),
    Seq(startTs + 5, "insert", "e", "10", "20", testLabelName2, s"""{"time": 10}""").mkString("\t"),
    Seq(startTs + 6, "insert", "e", "10", "21", testLabelName2, s"""{"time": 11}""").mkString("\t"),
    Seq(startTs + 7, "insert", "e", "11", "20", testLabelName2, s"""{"time": 12}""").mkString("\t"),
    Seq(startTs + 8, "insert", "e", "12", "20", testLabelName2, s"""{"time": 13}""").mkString("\t")
  ).mkString("\n")

  def query(id: Long, serviceName: String = testServiceName, columnName: String = testColumnName,
            labelName: String = testLabelName2, direction: String = "out") = Json.parse(
    s"""
        { "srcVertices": [
          { "serviceName": "$serviceName",
            "columnName": "$columnName",
            "id": $id
           }],
          "steps": [
          [ {
              "label": "$labelName",
              "direction": "${direction}",
              "offset": 0,
              "limit": 1000,
              "duplicate": "raw"
            }
          ]]
        }""")

  def getEdges(queryJson: JsValue): JsValue = {
    val ret = route(FakeRequest(POST, "/graphs/getEdges").withJsonBody(queryJson)).get
    contentAsJson(ret)
  }
  def getDegree(jsValue: JsValue): Long = {
    ((jsValue \ "degrees") \\ "_degree").headOption.map(_.as[Long]).getOrElse(0L)
  }


  "strong label delete test" should {
    running(FakeApplication()) {
      // insert bulk and wait ..
      val ret = route(FakeRequest(POST, "/graphs/edges/bulk").withBody(bulkEdges())).get
      val jsRslt = contentAsJson(ret)
      Thread.sleep(asyncFlushInterval)
    }




    "test strong consistency select" in {
      running(FakeApplication()) {
        var result = getEdges(query(0))
        println(result)
        (result \ "results").as[List[JsValue]].size must equalTo(2)
        result = getEdges(query(10))
        println(result)
        (result \ "results").as[List[JsValue]].size must equalTo(2)
        true
      }
    }

    "test strong consistency duration. insert -> delete -> insert" in {
      running(FakeApplication()) {
        val ts0 = 1
        val ts1 = 2
        val ts2 = 3

        val edges = Seq(
          Seq(5, "insert", "edge", "-10", "-20", testLabelName2).mkString("\t"),
          Seq(10, "delete", "edge", "-10", "-20", testLabelName2).mkString("\t"),
          Seq(20, "insert", "edge", "-10", "-20", testLabelName2).mkString("\t")
        ).mkString("\n")

        val ret = route(FakeRequest(POST, "/graphs/edges/bulk").withBody(edges)).get
        val jsRslt = contentAsJson(ret)

        Thread.sleep(asyncFlushInterval)
        var result = getEdges(query(-10))

        println(result)

        true
      }
    }

    "test strong consistency deleteAll" in {
      running(FakeApplication()) {
        val deletedAt = 100
        var result = getEdges(query(20, direction = "in", columnName = testTgtColumnName))
        println(result)
        (result \ "results").as[List[JsValue]].size must equalTo(3)



        val json = Json.arr(Json.obj("label" -> testLabelName2,
          "direction" -> "in", "ids" -> Json.arr("20"), "timestamp" -> deletedAt))
        println(json)
        EdgeController.deleteAllInner(json)
        Thread.sleep(asyncFlushInterval)


        result = getEdges(query(11, direction = "out"))
        println(result)
        (result \ "results").as[List[JsValue]].size must equalTo(0)

        result = getEdges(query(12, direction = "out"))
        println(result)
        (result \ "results").as[List[JsValue]].size must equalTo(0)

        result = getEdges(query(10, direction = "out"))
        println(result)
        // 10 -> out -> 20 should not be in result.
        (result \ "results").as[List[JsValue]].size must equalTo(1)
        (result \\ "to").size must equalTo(1)
        (result \\ "to").head.as[String] must equalTo("21")


        result = getEdges(query(20, direction = "in", columnName = testTgtColumnName))
        println(result)
        (result \ "results").as[List[JsValue]].size must equalTo(0)


        val ret = route(FakeRequest(POST, "/graphs/edges/bulk").withBody(bulkEdges(startTs = deletedAt + 1))).get
        val jsRslt = contentAsJson(ret)
        Thread.sleep(asyncFlushInterval)

        result = getEdges(query(20, direction = "in", columnName = testTgtColumnName))
        println(result)
        (result \ "results").as[List[JsValue]].size must equalTo(3)

        true

      }
    }
  }
  

  "largeSet of contention" should {
    val labelName = testLabelName2
    val maxTgtId = 5
    val maxRetryNum = 10
    val maxTestNum = 10
    val maxTestIntervalNum = 10
    def testInner(src: Long) = {
{'fraction_non_alphanumeric': 0.17491263564465698, 'fraction_numerical': 0.02565753172705536, 'mean_word_length': 2.730703259005146, 'pattern_counts': {'":': 36, '<': 3, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7477603', 'n_tokens_mistral': 3763, 'n_tokens_neox': 3469, 'n_words': 758}