<commit_before>/*
 * Copyright (C) 2016 <NAME> <<EMAIL>>
 * SPDX-License-Identifier: AGPL-3.0
 *
 * This file is part of the Hub of All Things project (HAT).
 *
 * HAT is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License
 * as published by the Free Software Foundation, version 3 of
 * the License.
 *
 * HAT is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
 * the GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General
 * Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */

package hatdex.hat.api.endpoints

import akka.event.LoggingAdapter
import hatdex.hat.api.TestDataCleanup
import hatdex.hat.api.actors.DalExecutionContext
import hatdex.hat.api.endpoints.jsonExamples.{DataExamples, EntityExamples}
import hatdex.hat.api.json.JsonProtocol
import hatdex.hat.api.models._
import hatdex.hat.authentication.HatAuthTestHandler
import hatdex.hat.authentication.authenticators.{AccessTokenHandler, UserPassHandler}
import org.specs2.mutable.Specification
import org.specs2.specification.{BeforeAfterAll, Scope}
import spray.http.HttpHeaders.RawHeader
import spray.http.HttpMethods._
import spray.http.StatusCodes._
import spray.http.{HttpEntity, HttpRequest, MediaTypes}
import spray.httpx.SprayJsonSupport._
import spray.json._
import spray.testkit.Specs2RouteTest

import scala.concurrent.Await
import scala.concurrent.duration.Duration

class LocationSpec extends Specification with Specs2RouteTest with Location with BeforeAfterAll with DalExecutionContext {
  def actorRefFactory = system

  val logger: LoggingAdapter = system.log

  val thingEndpoint = new Thing with DalExecutionContext {
    def actorRefFactory = system
    override def accessTokenHandler = AccessTokenHandler.AccessTokenAuthenticator(authenticator = HatAuthTestHandler.AccessTokenHandler.authenticator).apply()
    val logger: LoggingAdapter = system.log
  }

  val typeEndpoint = new Type with DalExecutionContext {
    def actorRefFactory = system
    override def accessTokenHandler = AccessTokenHandler.AccessTokenAuthenticator(authenticator = HatAuthTestHandler.AccessTokenHandler.authenticator).apply()
    val logger: LoggingAdapter = system.log
  }

  override def accessTokenHandler = AccessTokenHandler.AccessTokenAuthenticator(authenticator = HatAuthTestHandler.AccessTokenHandler.authenticator).apply()

  import JsonProtocol._

  def beforeAll() = {
    Await.result(TestDataCleanup.cleanupAll, Duration("20 seconds"))
  }

  // Clean up all data
  def afterAll() = {
//    TestDataCleanup.cleanupAll
  }

  val ownerAuthToken = HatAuthTestHandler.validUsers.find(_.role == "owner").map(_.userId).flatMap { ownerId =>
    HatAuthTestHandler.validAccessTokens.find(_.userId == ownerId).map(_.accessToken)
  } getOrElse ("")
  val ownerAuthHeader = RawHeader("X-Auth-Token", ownerAuthToken)

  def createNewValidLocation = HttpRequest(POST, "/location")
    .withHeaders(ownerAuthHeader)
    .withEntity(HttpEntity(MediaTypes.`application/json`, EntityExamples.locationValid)) ~>
    sealRoute(routes) ~> check {
      eventually {
        response.status should be equalTo Created
        responseAs[String] must contain("home")
      }
      responseAs[ApiLocation]
    }

  def createSubLocation = HttpRequest(POST, "/location")
    .withHeaders(ownerAuthHeader)
    .withEntity(HttpEntity(MediaTypes.`application/json`, EntityExamples.locationHomeStairs)) ~>
    sealRoute(routes) ~> check {
      eventually {
        response.status should be equalTo Created
        responseAs[String] must contain("stairs")
      }
      responseAs[ApiLocation]
    }

  "LocationsService" should {
    "Accept new locations created" in {
      //test createEntity
      val newLocation = createNewValidLocation
      newLocation.id must beSome
    }

    "Accept relationships with locations created" in {
      val newLocation = createNewValidLocation
      newLocation.id must beSome

      val subLocation = createSubLocation
      subLocation.id must beSome

      //test linkToLocation
      HttpRequest(POST, s"/location/${newLocation.id.get}/location/${subLocation.id.get}")
        .withHeaders(ownerAuthHeader)
        .withEntity(HttpEntity(MediaTypes.`application/json`, DataExamples.relationshipParent)) ~>
        sealRoute(routes) ~>
        check {
          eventually {
            response.status should be equalTo Created
            responseAs[String] must contain("id")
          }
        }
    }

    "Reject unsuported relationships" in {
      val newLocation = createNewValidLocation
      newLocation.id must beSome

      HttpRequest(POST, s"/location/${newLocation.id.get}/organisation/1")
        .withHeaders(ownerAuthHeader)
        .withEntity(HttpEntity(MediaTypes.`application/json`, DataExamples.relationshipParent)) ~>
        sealRoute(routes) ~>
        check {
          eventually {
            response.status should be equalTo BadRequest
            responseAs[ErrorMessage].cause must contain("Operation Not Supprted")
          }
        }

      HttpRequest(POST, s"/location/${newLocation.id.get}/person/1")
        .withHeaders(ownerAuthHeader)
        .withEntity(HttpEntity(MediaTypes.`application/json`, DataExamples.relationshipParent)) ~>
        sealRoute(routes) ~>
        check {
          eventually {
            response.status should be equalTo BadRequest
            responseAs[ErrorMessage].cause must contain("Operation Not Supprted")
          }
        }

      HttpRequest(POST, s"/location/${newLocation.id.get}/event/1")
        .withHeaders(ownerAuthHeader)
        .withEntity(HttpEntity(MediaTypes.`application/json`, DataExamples.relationshipParent)) ~>
        sealRoute(routes) ~>
        check {
          eventually {
            response.status should be equalTo BadRequest
            responseAs[ErrorMessage].cause must contain("Operation Not Supprted")
          }
        }
    }

    "Retrieve created locations" in {
      val newLocation = createNewValidLocation
      newLocation.id must beSome

      HttpRequest(GET, s"/location/${newLocation.id.get}")
        .withHeaders(ownerAuthHeader) ~>
        sealRoute(routes) ~>
        check {
          eventually {
            response.status should be equalTo OK
            responseAs[String] must contain("home")
            responseAs[ApiLocation]
            responseAs[String] must contain(s"${newLocation.id.get}")
          }
        }
    }

    "Accept retrieval of things and locations linked" in {
      val newLocation = createNewValidLocation
      newLocation.id must beSome

      val someThing = HttpRequest(POST, "/thing")
        .withHeaders(ownerAuthHeader)
        .withEntity(HttpEntity(MediaTypes.`application/json`, EntityExamples.thingValid)) ~>
        sealRoute(thingEndpoint.routes) ~>
        check {
          eventually {
            response.status should be equalTo Created
            responseAs[String] must contain("tv")
            responseAs[ApiThing]
          }
        }

      someThing.id must beSome<commit_msg>'eventualizes' remaining tests in Location spec<commit_after>/*
 * Copyright (C) 2016 <NAME> <<EMAIL>>
 * SPDX-License-Identifier: AGPL-3.0
 *
 * This file is part of the Hub of All Things project (HAT).
 *
 * HAT is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License
 * as published by the Free Software Foundation, version 3 of
 * the License.
 *
 * HAT is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
 * the GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General
 * Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */

package hatdex.hat.api.endpoints

import akka.event.LoggingAdapter
import hatdex.hat.api.TestDataCleanup
import hatdex.hat.api.actors.DalExecutionContext
import hatdex.hat.api.endpoints.jsonExamples.{DataExamples, EntityExamples}
import hatdex.hat.api.json.JsonProtocol
import hatdex.hat.api.models._
import hatdex.hat.authentication.HatAuthTestHandler
import hatdex.hat.authentication.authenticators.{AccessTokenHandler, UserPassHandler}
import org.specs2.mutable.Specification
import org.specs2.specification.{BeforeAfterAll, Scope}
import spray.http.HttpHeaders.RawHeader
import spray.http.HttpMethods._
import spray.http.StatusCodes._
import spray.http.{HttpEntity, HttpRequest, MediaTypes}
import spray.httpx.SprayJsonSupport._
import spray.json._
import spray.testkit.Specs2RouteTest

import scala.concurrent.Await
import scala.concurrent.duration.Duration

class LocationSpec extends Specification with Specs2RouteTest with Location with BeforeAfterAll with DalExecutionContext {
  def actorRefFactory = system

  val logger: LoggingAdapter = system.log

  val thingEndpoint = new Thing with DalExecutionContext {
    def actorRefFactory = system
    override def accessTokenHandler = AccessTokenHandler.AccessTokenAuthenticator(authenticator = HatAuthTestHandler.AccessTokenHandler.authenticator).apply()
    val logger: LoggingAdapter = system.log
  }

  val typeEndpoint = new Type with DalExecutionContext {
    def actorRefFactory = system
    override def accessTokenHandler = AccessTokenHandler.AccessTokenAuthenticator(authenticator = HatAuthTestHandler.AccessTokenHandler.authenticator).apply()
    val logger: LoggingAdapter = system.log
  }

  override def accessTokenHandler = AccessTokenHandler.AccessTokenAuthenticator(authenticator = HatAuthTestHandler.AccessTokenHandler.authenticator).apply()

  import JsonProtocol._

  def beforeAll() = {
    Await.result(TestDataCleanup.cleanupAll, Duration("20 seconds"))
  }

  // Clean up all data
  def afterAll() = {
//    TestDataCleanup.cleanupAll
  }

  val ownerAuthToken = HatAuthTestHandler.validUsers.find(_.role == "owner").map(_.userId).flatMap { ownerId =>
    HatAuthTestHandler.validAccessTokens.find(_.userId == ownerId).map(_.accessToken)
  } getOrElse ("")
  val ownerAuthHeader = RawHeader("X-Auth-Token", ownerAuthToken)

  def createNewValidLocation = HttpRequest(POST, "/location")
    .withHeaders(ownerAuthHeader)
    .withEntity(HttpEntity(MediaTypes.`application/json`, EntityExamples.locationValid)) ~>
    sealRoute(routes) ~> check {
      eventually {
        response.status should be equalTo Created
        responseAs[String] must contain("home")
      }
      responseAs[ApiLocation]
    }

  def createSubLocation = HttpRequest(POST, "/location")
    .withHeaders(ownerAuthHeader)
    .withEntity(HttpEntity(MediaTypes.`application/json`, EntityExamples.locationHomeStairs)) ~>
    sealRoute(routes) ~> check {
      eventually {
        response.status should be equalTo Created
        responseAs[String] must contain("stairs")
      }
      responseAs[ApiLocation]
    }

  "LocationsService" should {
    "Accept new locations created" in {
      //test createEntity
      val newLocation = createNewValidLocation
      newLocation.id must beSome
    }

    "Accept relationships with locations created" in {
      val newLocation = createNewValidLocation
      newLocation.id must beSome

      val subLocation = createSubLocation
      subLocation.id must beSome

      //test linkToLocation
      HttpRequest(POST, s"/location/${newLocation.id.get}/location/${subLocation.id.get}")
        .withHeaders(ownerAuthHeader)
        .withEntity(HttpEntity(MediaTypes.`application/json`, DataExamples.relationshipParent)) ~>
        sealRoute(routes) ~>
        check {
          eventually {
            response.status should be equalTo Created
            responseAs[String] must contain("id")
          }
        }
    }

    "Reject unsuported relationships" in {
      val newLocation = createNewValidLocation
      newLocation.id must beSome

      HttpRequest(POST, s"/location/${newLocation.id.get}/organisation/1")
        .withHeaders(ownerAuthHeader)
        .withEntity(HttpEntity(MediaTypes.`application/json`, DataExamples.relationshipParent)) ~>
        sealRoute(routes) ~>
        check {
          eventually {
            response.status should be equalTo BadRequest
            responseAs[ErrorMessage].cause must contain("Operation Not Supprted")
          }
        }

      HttpRequest(POST, s"/location/${newLocation.id.get}/person/1")
        .withHeaders(ownerAuthHeader)
        .withEntity(HttpEntity(MediaTypes.`application/json`, DataExamples.relationshipParent)) ~>
        sealRoute(routes) ~>
        check {
          eventually {
            response.status should be equalTo BadRequest
            responseAs[ErrorMessage].cause must contain("Operation Not Supprted")
          }
        }

      HttpRequest(POST, s"/location/${newLocation.id.get}/event/1")
        .withHeaders(ownerAuthHeader)
        .withEntity(HttpEntity(MediaTypes.`application/json`, DataExamples.relationshipParent)) ~>
        sealRoute(routes) ~>
        check {
          eventually {
            response.status should be equalTo BadRequest
            responseAs[ErrorMessage].cause must contain("Operation Not Supprted")
          }
        }
    }

    "Retrieve created locations" in {
      val newLocation = createNewValidLocation
      newLocation.id must beSome

      HttpRequest(GET, s"/location/${newLocation.id.get}")
        .withHeaders(ownerAuthHeader) ~>
        sealRoute(routes) ~>
        check {
          eventually {
            response.status should be equalTo OK
            responseAs[String] must contain("home")
            responseAs[ApiLocation]
            responseAs[String] must contain(s"${newLocation.id.get}")
          }
        }
    }

    "Accept retrieval of things and locations linked" in {
      val newLocation = createNewValidLocation
      newLocation.id must beSome

      val someThing = HttpRequest(POST, "/thing")
        .withHeaders(ownerAuthHeader)
        .withEntity(HttpEntity(MediaTypes.`application/json`, EntityExamples.thingValid)) ~>
        sealRoute(thingEndpoint.routes) ~>
        check {
          eventually {
            response.status should be equalTo Created
            responseAs[String] must contain("tv")
          }
          responseAs[ApiThing]
        }

      someThing.id must beSome
{'fraction_non_alphanumeric': 0.08857456742653118, 'fraction_numerical': 0.0021971985718209283, 'mean_word_length': 3.271260997067449, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 45, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, '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': '5524852', 'n_tokens_mistral': 3937, 'n_tokens_neox': 3890, 'n_words': 924}