PageRenderTime 50ms CodeModel.GetById 10ms RepoModel.GetById 1ms app.codeStats 0ms

/test/com/growin/itrex/test/ControllersSuite.scala

https://bitbucket.org/valterfernandes/it-rex-api
Scala | 2103 lines | 1461 code | 546 blank | 96 comment | 8 complexity | fa4df559c70ae664373614b7049b799c MD5 | raw file
  1. package com.growin.itrex.test
  2. import java.time.Instant
  3. import java.util.UUID
  4. import com.growin.itrex.models._
  5. import com.growin.itrex.test.Helpers._
  6. import org.bson.types.ObjectId
  7. import org.mongodb.scala._
  8. import org.scalatestplus.play.PlaySpec
  9. import org.scalatestplus.play.guice.GuiceOneAppPerSuite
  10. import play.api.libs.json._
  11. import play.api.mvc.Result
  12. import play.api.test.FakeRequest
  13. import play.api.test.Helpers._
  14. import reactivemongo.bson.BSONObjectID
  15. import scala.concurrent.Future
  16. class ControllersSuite extends PlaySpec with GuiceOneAppPerSuite {
  17. // Mongo connections
  18. val mongoClient: MongoClient = MongoClient()
  19. val database: MongoDatabase = mongoClient.getDatabase("test")
  20. database.drop().results()
  21. // Collections
  22. val candidateCollection: MongoCollection[Document] = database.getCollection("candidates")
  23. val eventCollection: MongoCollection[Document] = database.getCollection("events")
  24. val userCollection: MongoCollection[Document] = database.getCollection("users")
  25. val takeoutCollection: MongoCollection[Document] = database.getCollection("takeout")
  26. val tokenCollection: MongoCollection[Document] = database.getCollection("token")
  27. /**
  28. * We need to wait for the API to finish it's job. Only after that can we access the database to check it's
  29. * side-effects. How long? magic number.
  30. * We use this function when we want to access the DB after a API request has been made.
  31. */
  32. def waitingOnApi(): Unit = Thread.sleep(2000)
  33. // Authentication
  34. "GET /login" should {
  35. userCollection.drop().results()
  36. val password: String = Generator.passGen
  37. val user: Document = ModelGenerator.generateDirector(password)
  38. val username: String = user.getString("username")
  39. userCollection.insertOne(user).results()
  40. "return BadRequest on missing parameters" in {
  41. val request = FakeRequest(GET, "/login")
  42. .withHeaders(HOST -> "localhost:9000")
  43. val result: Future[Result] = route(app, request).get
  44. status(result) mustEqual BAD_REQUEST
  45. }
  46. "return BadRequest when missing password" in {
  47. val request = FakeRequest(GET, s"/login?username=$username")
  48. .withHeaders(HOST -> "localhost:9000")
  49. val result: Future[Result] = route(app, request).get
  50. status(result) mustEqual BAD_REQUEST
  51. }
  52. "return BadRequest on empty password" in {
  53. val request = FakeRequest(GET, s"/login?username=$username&password=")
  54. .withHeaders(HOST -> "localhost:9000")
  55. val result: Future[Result] = route(app, request).get
  56. status(result) mustEqual BAD_REQUEST
  57. }
  58. "return BadRequest when giving null parameters" in {
  59. val request = FakeRequest(GET, "/login?username=null&password=null")
  60. .withHeaders(HOST -> "localhost:9000")
  61. val result: Future[Result] = route(app, request).get
  62. status(result) mustEqual BAD_REQUEST
  63. }
  64. "return BadRequest for an inactive user" in {
  65. val pass = Generator.passGen
  66. val user = ModelGenerator.generateInactiveUser(pass)
  67. val username: String = user.getString("username")
  68. userCollection.insertOne(user).results()
  69. val request = FakeRequest(GET, s"/login?username=$username&password=$pass")
  70. .withHeaders(HOST -> "localhost:9000")
  71. val result: Future[Result] = route(app, request).get
  72. status(result) mustEqual BAD_REQUEST
  73. }
  74. "return BadRequest on non-user login" in {
  75. val request = FakeRequest(GET, s"/login?username=${username.substring(1)}&password=$password")
  76. .withHeaders(HOST -> "localhost:9000")
  77. val result: Future[Result] = route(app, request).get
  78. status(result) mustEqual BAD_REQUEST
  79. }
  80. "return BadRequest on wrong password" in {
  81. val request = FakeRequest(GET, s"/login?username=$username&password=${password.substring(1)}")
  82. .withHeaders(HOST -> "localhost:9000")
  83. val result: Future[Result] = route(app, request).get
  84. status(result) mustEqual BAD_REQUEST
  85. }
  86. "return TooManyRequests on User 4th login attempt" in {
  87. val maxAttempts: Int = 4 // maximum number of attempts
  88. val pass: String = Generator.passGen
  89. val user: Document = ModelGenerator.generateInactiveUser(pass)
  90. val username: String = user.getString("username")
  91. userCollection.insertOne(user).results()
  92. (1 to 4).foreach { i =>
  93. val request = FakeRequest(GET, s"/login?username=$username&password=$pass")
  94. .withHeaders(HOST -> "localhost:9000")
  95. val result: Future[Result] = route(app, request).get
  96. if (i == 4) {
  97. // last attempt into backoff
  98. status(result) mustEqual TOO_MANY_REQUESTS
  99. contentAsJson(result).as[JsObject].value("reset").asOpt[Long].isDefined mustEqual true
  100. } else {
  101. status(result) mustEqual BAD_REQUEST
  102. contentAsJson(result).as[JsObject].value("remaining").as[Int] mustEqual (maxAttempts - i)
  103. }
  104. }
  105. }
  106. "return TooManyRequest on non-User 4th login attempt" in {
  107. val max: Int = 4
  108. val nonUsername: String = Generator.strGen.apply(20).sample.get
  109. (1 to 4).foreach {
  110. i =>
  111. val request = FakeRequest(GET, s"/login?username=$nonUsername&password=$password")
  112. .withHeaders(HOST -> "localhost:9000")
  113. val result: Future[Result] = route(app, request).get
  114. if (i == 4) {
  115. // last attempt into backoff
  116. status(result) mustEqual TOO_MANY_REQUESTS
  117. contentAsJson(result).as[JsObject].value("reset").asOpt[Long].isDefined mustEqual true
  118. } else {
  119. status(result) mustEqual BAD_REQUEST
  120. contentAsJson(result).as[JsObject].value("remaining").as[Int] mustEqual (max - i)
  121. }
  122. // TODO: check if this is necessary => accessing the DB many times in a row can create conflicts on expected results
  123. Thread.sleep(300)
  124. }
  125. }
  126. "return Ok for a Director's login" in {
  127. val request = FakeRequest(GET, s"/login?username=$username&password=$password")
  128. .withHeaders(HOST -> "localhost:9000")
  129. val result: Future[Result] = route(app, request).get
  130. status(result) mustEqual OK
  131. val keySet: Set[String] = Set("access_token", "refresh_token")
  132. contentAsJson(result).as[JsObject]
  133. .value.forall(p => keySet.contains(p._1)) mustEqual true
  134. }
  135. }
  136. "GET /logout" should {
  137. // create a user and save it in the database
  138. val pass: String = Generator.passGen
  139. val user: Document = ModelGenerator.generateActiveUser(pass)
  140. val username: String = user.getString("username")
  141. userCollection.insertOne(user).results()
  142. var jwt: String = ""
  143. "return Ok and token" in {
  144. // login with that user
  145. val loginRequest = FakeRequest(GET, s"/login?username=$username&password=$pass")
  146. .withHeaders(HOST -> "localhost:9000")
  147. val loginResult: Future[Result] = route(app, loginRequest).get
  148. status(loginResult) mustEqual OK
  149. jwt = contentAsJson(loginResult)
  150. .as[JsObject].value("access_token")
  151. .as[String]
  152. }
  153. "return NoContent on revoking access_token" in {
  154. val request = FakeRequest(GET, "/logout")
  155. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $jwt")
  156. val result: Future[Result] = route(app, request).get
  157. status(result) mustEqual NO_CONTENT
  158. }
  159. "return Unauthorized if access_token is reused" in {
  160. val request = FakeRequest(GET, "/logout")
  161. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $jwt")
  162. val result: Future[Result] = route(app, request).get
  163. status(result) mustEqual UNAUTHORIZED
  164. }
  165. }
  166. "GET /refresh_token" should {
  167. // create a user and save it in the database
  168. val pass: String = Generator.passGen
  169. val user: Document = ModelGenerator.generateActiveUser(pass)
  170. val username: String = user.getString("username")
  171. userCollection.insertOne(user).results()
  172. var jwt: String = ""
  173. var rt: String = ""
  174. "return Ok and token" in {
  175. // login with that user
  176. val loginRequest = FakeRequest(GET, s"/login?username=$username&password=$pass")
  177. .withHeaders(HOST -> "localhost:9000")
  178. val loginResult: Future[Result] = route(app, loginRequest).get
  179. status(loginResult) mustEqual OK
  180. jwt = contentAsJson(loginResult)
  181. .as[JsObject].value("access_token")
  182. .as[String]
  183. rt = contentAsJson(loginResult)
  184. .as[JsObject].value("refresh_token")
  185. .as[String]
  186. }
  187. "return BadRequest on missing parameter" in {
  188. val request = FakeRequest(GET, s"/refresh_token")
  189. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $jwt")
  190. val result: Future[Result] = route(app, request).get
  191. status(result) mustEqual BAD_REQUEST
  192. }
  193. "return BadRequest on null parameter" in {
  194. val request = FakeRequest(GET, s"/refresh_token?refresh_token=null")
  195. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $jwt")
  196. val result: Future[Result] = route(app, request).get
  197. status(result) mustEqual BAD_REQUEST
  198. }
  199. "return Ok on valid request" in {
  200. val request = FakeRequest(GET, s"/refresh_token?refresh_token=$rt")
  201. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $jwt")
  202. val result: Future[Result] = route(app, request).get
  203. status(result) mustEqual OK
  204. val keySet: Set[String] = Set("access_token", "refresh_token")
  205. contentAsJson(result).as[JsObject]
  206. .value.forall(p => keySet.contains(p._1)) mustEqual true
  207. jwt = contentAsJson(result)
  208. .as[JsObject].value("access_token")
  209. .as[String]
  210. rt = contentAsJson(result)
  211. .as[JsObject].value("refresh_token")
  212. .as[String]
  213. }
  214. "return BadRequest on inactive user jwt" in {
  215. val query = Document("username" -> username)
  216. // update the user status
  217. val updatedUser = user.+("active" -> false)
  218. userCollection.findOneAndUpdate(query, Document("$set" -> updatedUser)).results()
  219. val request = FakeRequest(GET, s"/refresh_token?refresh_token=$rt")
  220. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $jwt")
  221. val result = route(app, request).get
  222. status(result) mustEqual BAD_REQUEST
  223. }
  224. "return BadRequest on unexisting user jwt" in {
  225. //delete the user
  226. userCollection.deleteOne(Document("username" -> username)).results()
  227. val request = FakeRequest(GET, s"/refresh_token?refresh_token=$rt")
  228. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $jwt")
  229. val result = route(app, request).get
  230. status(result) mustEqual BAD_REQUEST
  231. }
  232. }
  233. "GET /revoke_user" should {
  234. // create a user and save it in the database
  235. val pass: String = Generator.passGen
  236. val user: Document = ModelGenerator.generateDirector(pass)
  237. val username: String = user.getString("username")
  238. userCollection.insertOne(user).results()
  239. var jwt: String = ""
  240. var rt: String = ""
  241. "return Ok and token" in {
  242. // login with that user
  243. val loginRequest = FakeRequest(GET, s"/login?username=$username&password=$pass")
  244. .withHeaders(HOST -> "localhost:9000")
  245. val loginResult: Future[Result] = route(app, loginRequest).get
  246. status(loginResult) mustEqual OK
  247. jwt = contentAsJson(loginResult)
  248. .as[JsObject].value("access_token")
  249. .as[String]
  250. rt = contentAsJson(loginResult)
  251. .as[JsObject].value("refresh_token")
  252. .as[String]
  253. }
  254. "return BadRequest on missing parameters" in {
  255. val request = FakeRequest(GET, s"/revoke_user")
  256. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $jwt")
  257. val result = route(app, request).get
  258. status(result) mustEqual BAD_REQUEST
  259. }
  260. "return NotFound on unexisting user" in {
  261. val request = FakeRequest(GET, s"/revoke_user?username=${username.substring(1)}")
  262. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $jwt")
  263. val result = route(app, request).get
  264. status(result) mustEqual BAD_REQUEST
  265. }
  266. "return NoContent on valid username" in {
  267. val request = FakeRequest(GET, s"/revoke_user?username=$username")
  268. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $jwt")
  269. val result = route(app, request).get
  270. status(result) mustEqual NO_CONTENT
  271. }
  272. "return Unauthorized after being revoked" in {
  273. val request = FakeRequest(GET, s"/revoke_user?username=$username")
  274. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $jwt")
  275. val result = route(app, request).get
  276. status(result) mustEqual UNAUTHORIZED
  277. }
  278. }
  279. "GET /revoke_tokens" should {
  280. "return NoContent and revoke all emitted tokens" in {
  281. val password: String = Generator.passGen // generate random password
  282. val users: Seq[Document] = (1 to 10).map(_ => ModelGenerator.generateDirector(password))
  283. userCollection.insertMany(users).results()
  284. // create 10 tokens with the same Api secret
  285. val tokens: Seq[(String, String)] = users.map { user =>
  286. val username: String = user.getString("username")
  287. val request = FakeRequest(GET, s"/login?username=$username&password=$password")
  288. .withHeaders(HOST -> "localhost:9000")
  289. val result = route(app, request).get
  290. status(result) mustEqual OK
  291. val keySet: Set[String] = Set("access_token", "refresh_token")
  292. contentAsJson(result).as[JsObject]
  293. .value.forall(p => keySet.contains(p._1)) mustEqual true
  294. val jwt = contentAsJson(result)
  295. .as[JsObject].value("access_token")
  296. .as[String]
  297. val rt = contentAsJson(result)
  298. .as[JsObject].value("refresh_token")
  299. .as[String]
  300. (jwt, rt)
  301. }
  302. // change the Api secret
  303. val request = FakeRequest(GET, s"/revoke_tokens")
  304. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer ${tokens.head._1}")
  305. val result = route(app, request).get
  306. status(result) mustEqual NO_CONTENT
  307. // check if all the emitted tokens are invalid.
  308. tokens.foreach { tokenPair =>
  309. val request = FakeRequest(GET, s"/revoke_tokens")
  310. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer ${tokenPair._1}")
  311. val result: Future[Result] = route(app, request).get
  312. status(result) mustEqual UNAUTHORIZED
  313. }
  314. }
  315. }
  316. // User
  317. "GET /users" should {
  318. // create a user and save it in the database
  319. val password: String = Generator.passGen
  320. val director: Document = ModelGenerator.generateDirector(password)
  321. userCollection.insertOne(director).results()
  322. var dirJwt: String = ""
  323. val manager: Document = ModelGenerator.generateManager(password)
  324. userCollection.insertOne(manager).results()
  325. var manJwt: String = ""
  326. "return Ok and token" in {
  327. // login with that user
  328. val dirRequest = FakeRequest(GET, s"/login?username=${director.getString("username")}&password=$password")
  329. .withHeaders(HOST -> "localhost:9000")
  330. val dirResult: Future[Result] = route(app, dirRequest).get
  331. status(dirResult) mustEqual OK
  332. dirJwt = contentAsJson(dirResult)
  333. .as[JsObject].value("access_token")
  334. .as[String]
  335. val manRequest = FakeRequest(GET, s"/login?username=${manager.getString("username")}&password=$password")
  336. .withHeaders(HOST -> "localhost:9000")
  337. val manResult: Future[Result] = route(app, manRequest).get
  338. status(manResult)
  339. manJwt = contentAsJson(manResult)
  340. .as[JsObject].value("access_token")
  341. .as[String]
  342. }
  343. val users: Seq[Document] = (0 to 20).map(_ => ModelGenerator.generateActiveUser(Generator.passGen))
  344. userCollection.insertMany(users).results()
  345. "return BadRequest on invalid parameters" in {
  346. val request = FakeRequest(GET, "/users?page=null&size=null")
  347. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $dirJwt")
  348. val result: Future[Result] = route(app, request).get
  349. status(result) mustEqual BAD_REQUEST
  350. }
  351. "return Ok and 20 Users" in {
  352. val request = FakeRequest(GET, "/users?page=1&size=20")
  353. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $dirJwt")
  354. val result: Future[Result] = route(app, request).get
  355. status(result) mustEqual OK
  356. val body: JsArray = contentAsJson(result).as[JsArray]
  357. body.value.size mustEqual 20
  358. body.value.forall(p => p.validateOpt[User].isSuccess) mustEqual true
  359. }
  360. "return Forbidden on a Managers jwt" in {
  361. val request = FakeRequest(GET, "/users?page=1&size=20")
  362. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $manJwt")
  363. val result: Future[Result] = route(app, request).get
  364. status(result) mustEqual FORBIDDEN
  365. }
  366. }
  367. "POST /users" should {
  368. // create a user and save it in the database
  369. val password: String = Generator.passGen
  370. val director: Document = ModelGenerator.generateDirector(password)
  371. userCollection.insertOne(director).results()
  372. var dirJwt: String = ""
  373. val manager: Document = ModelGenerator.generateManager(password)
  374. userCollection.insertOne(manager).results()
  375. var manJwt: String = ""
  376. "return Ok and token for both profiles" in {
  377. // login with directors profile
  378. val dirRequest = FakeRequest(GET, s"/login?username=${director.getString("username")}&password=$password")
  379. .withHeaders(HOST -> "localhost:9000")
  380. val dirResult: Future[Result] = route(app, dirRequest).get
  381. status(dirResult) mustEqual OK
  382. dirJwt = contentAsJson(dirResult)
  383. .as[JsObject].value("access_token")
  384. .as[String]
  385. // login with manager profile
  386. val manRequest = FakeRequest(GET, s"/login?username=${manager.getString("username")}&password=$password")
  387. .withHeaders(HOST -> "localhost:9000")
  388. val manResult: Future[Result] = route(app, manRequest).get
  389. status(manResult) mustEqual OK
  390. manJwt = contentAsJson(manResult)
  391. .as[JsObject].value("access_token")
  392. .as[String]
  393. }
  394. "return Forbidden on a Manager creating a new user" in {
  395. val user = ModelGenerator.generateDirector(password)
  396. val request = FakeRequest(POST, s"/users")
  397. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $manJwt", "X-Requested-With" -> "*")
  398. .withJsonBody(Json.parse(user.toJson()))
  399. val result = route(app, request).get
  400. status(result) mustEqual FORBIDDEN
  401. }
  402. "return Created on a Director creating a new user" in {
  403. val user = ModelGenerator.generateDirector(password)
  404. .-("password")
  405. val request = FakeRequest(POST, s"/users")
  406. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $dirJwt", "X-Requested-With" -> "*")
  407. .withJsonBody(Json.parse(user.toJson()))
  408. val result = route(app, request).get
  409. status(result) mustEqual CREATED
  410. }
  411. "return BadRequest on a Director creating a new user with an invalid email" in {
  412. val userBodyWithRepeatedFields = ModelGenerator.generateDirector(password)
  413. .+("email" -> Generator.strGen(20).sample.get)
  414. .-("password")
  415. val expectedReturn: Seq[String] = Seq("email")
  416. val request = FakeRequest(POST, s"/users")
  417. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $dirJwt", "X-Requested-With" -> "*")
  418. .withJsonBody(Json.parse(userBodyWithRepeatedFields.toJson))
  419. val result = route(app, request).get
  420. status(result) mustEqual BAD_REQUEST
  421. contentAsJson(result).as[Seq[String]].sortBy(_ (0)) mustEqual expectedReturn
  422. }
  423. "return BadRequest on a Director creating a new user with an numeral in place for a string field" in {
  424. val userBodyWithRepeatedFields = ModelGenerator.generateDirector(password)
  425. .+("name" -> Generator.integerGen(9).sample.get)
  426. .-("password")
  427. val expectedReturn: Seq[String] = Seq("name")
  428. val request = FakeRequest(POST, s"/users")
  429. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $dirJwt", "X-Requested-With" -> "*")
  430. .withJsonBody(Json.parse(userBodyWithRepeatedFields.toJson))
  431. val result = route(app, request).get
  432. status(result) mustEqual BAD_REQUEST
  433. contentAsJson(result).as[Seq[String]].sortBy(_ (0)) mustEqual expectedReturn
  434. }
  435. "return BadRequest on a Director creating a new user with an invalid role" in {
  436. val userBodyWithInvalidValues = ModelGenerator.generateDirector(password)
  437. .-("password")
  438. .+("role" -> "some_unvalid_role")
  439. val expectedReturn: Seq[String] = Seq("role")
  440. val request = FakeRequest(POST, s"/users")
  441. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $dirJwt", "X-Requested-With" -> "*")
  442. .withJsonBody(Json.parse(userBodyWithInvalidValues.toJson))
  443. val result = route(app, request).get
  444. status(result) mustEqual BAD_REQUEST
  445. contentAsJson(result).as[Seq[String]].sortBy(_ (0)) mustEqual expectedReturn.sortBy(_ (0))
  446. }
  447. "return BadRequest on a Director creating a new user with null values" in {
  448. val userBodyWithNulls: JsObject = Json.obj(
  449. "name" -> "Some valid Name",
  450. "email" -> JsNull,
  451. "role" -> JsNull,
  452. "username" -> JsNull,
  453. "active" -> JsNull)
  454. val expectedReturn: Seq[String] = Seq(
  455. "email",
  456. "role",
  457. "username",
  458. "active")
  459. val request = FakeRequest(POST, s"/users")
  460. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $dirJwt", "X-Requested-With" -> "*")
  461. .withJsonBody(userBodyWithNulls)
  462. val result = route(app, request).get
  463. status(result) mustEqual BAD_REQUEST
  464. contentAsJson(result).as[Seq[String]].sortBy(_ (0)) mustEqual expectedReturn.sortBy(_ (0))
  465. }
  466. }
  467. "GET /users/username_available" should {
  468. //userCollection.drop().results() // clear the users collection
  469. // create a user and save it in the database
  470. val pass: String = Generator.passGen
  471. val user: Document = ModelGenerator.generateDirector(pass)
  472. val username: String = user.getString("username")
  473. userCollection.insertOne(user).results()
  474. var jwt: String = ""
  475. "return Ok and token" in {
  476. // login with that user
  477. val loginRequest = FakeRequest(GET, s"/login?username=$username&password=$pass")
  478. .withHeaders(HOST -> "localhost:9000")
  479. val loginResult: Future[Result] = route(app, loginRequest).get
  480. status(loginResult) mustEqual OK
  481. jwt = contentAsJson(loginResult)
  482. .as[JsObject].value("access_token")
  483. .as[String]
  484. }
  485. "return BadRequest on missing parameter" in {
  486. val request = FakeRequest(GET, s"/users/username_available")
  487. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $jwt")
  488. val result = route(app, request).get
  489. status(result) mustEqual BAD_REQUEST
  490. }
  491. "return Ok your_name" in {
  492. val request = FakeRequest(GET, s"/users/username_available?username=$username")
  493. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $jwt")
  494. val result = route(app, request).get
  495. status(result) mustEqual OK
  496. contentAsJson(result).as[JsObject].value("valid").as[Boolean] mustEqual true
  497. contentAsJson(result).as[JsObject].value("reason").as[String] mustEqual "your_name"
  498. }
  499. "return Ok taken" in {
  500. val user: Document = ModelGenerator.generateDirector(pass)
  501. userCollection.insertOne(user).results()
  502. val request = FakeRequest(GET, s"/users/username_available?username=${user.getString("username")}")
  503. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $jwt")
  504. val result = route(app, request).get
  505. status(result) mustEqual OK
  506. contentAsJson(result).as[JsObject].value("valid").as[Boolean] mustEqual false
  507. contentAsJson(result).as[JsObject].value("reason").as[String] mustEqual "taken"
  508. }
  509. "return Ok available" in {
  510. val request = FakeRequest(GET, s"/users/username_available?username=${username.substring(1)}")
  511. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $jwt")
  512. val result = route(app, request).get
  513. status(result) mustEqual OK
  514. contentAsJson(result).as[JsObject].value("valid").as[Boolean] mustEqual true
  515. contentAsJson(result).as[JsObject].value("reason").as[String] mustEqual "available"
  516. }
  517. }
  518. "GET /user/:id" should {
  519. // create a user and save it in the database
  520. val password: String = Generator.passGen
  521. val director: Document = ModelGenerator.generateDirector(password)
  522. userCollection.insertOne(director).results()
  523. var dirJwt: String = ""
  524. val dirObjectId: ObjectId = userCollection.find(Document("username" -> director.getString("username")))
  525. .first().headResult().getObjectId("_id")
  526. val manager: Document = ModelGenerator.generateManager(password)
  527. userCollection.insertOne(manager).results()
  528. var manJwt: String = ""
  529. "return Ok and token for both profiles" in {
  530. // login with directors profile
  531. val dirRequest = FakeRequest(GET, s"/login?username=${director.getString("username")}&password=$password")
  532. .withHeaders(HOST -> "localhost:9000")
  533. val dirResult: Future[Result] = route(app, dirRequest).get
  534. status(dirResult) mustEqual OK
  535. dirJwt = contentAsJson(dirResult)
  536. .as[JsObject].value("access_token")
  537. .as[String]
  538. // login with manager profile
  539. val manRequest = FakeRequest(GET, s"/login?username=${manager.getString("username")}&password=$password")
  540. .withHeaders(HOST -> "localhost:9000")
  541. val manResult: Future[Result] = route(app, manRequest).get
  542. status(manResult) mustEqual OK
  543. manJwt = contentAsJson(manResult)
  544. .as[JsObject].value("access_token")
  545. .as[String]
  546. }
  547. "return Forbidden on Manager trying to retrieve" in {
  548. val request = FakeRequest(GET, s"/user/${dirObjectId.toHexString}")
  549. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $manJwt")
  550. val result = route(app, request).get
  551. status(result) mustEqual FORBIDDEN
  552. }
  553. "return Ok and a User" in {
  554. val request = FakeRequest(GET, s"/user/${dirObjectId.toHexString}")
  555. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $dirJwt")
  556. val result = route(app, request).get
  557. status(result) mustEqual OK
  558. contentAsJson(result).validate[User].isSuccess mustEqual true
  559. contentAsJson(result).as[User].password.isDefined mustEqual false
  560. }
  561. }
  562. "DELETE /user/:id" should {
  563. // create a user and save it in the database
  564. val password: String = Generator.passGen
  565. val director: Document = ModelGenerator.generateDirector(password)
  566. userCollection.insertOne(director).results()
  567. var dirJwt: String = ""
  568. val dirObjectId: ObjectId = userCollection.find(Document("username" -> director.getString("username")))
  569. .first().headResult().getObjectId("_id")
  570. val manager: Document = ModelGenerator.generateManager(password)
  571. userCollection.insertOne(manager).results()
  572. var manJwt: String = ""
  573. val manObjectId: ObjectId = userCollection.find(Document("username" -> manager.getString("username")))
  574. .first().headResult().getObjectId("_id")
  575. "return Ok and token for both profiles" in {
  576. // login with directors profile
  577. val dirRequest = FakeRequest(GET, s"/login?username=${director.getString("username")}&password=$password")
  578. .withHeaders(HOST -> "localhost:9000")
  579. val dirResult: Future[Result] = route(app, dirRequest).get
  580. status(dirResult) mustEqual OK
  581. dirJwt = contentAsJson(dirResult)
  582. .as[JsObject].value("access_token")
  583. .as[String]
  584. // login with manager profile
  585. val manRequest = FakeRequest(GET, s"/login?username=${manager.getString("username")}&password=$password")
  586. .withHeaders(HOST -> "localhost:9000")
  587. val manResult: Future[Result] = route(app, manRequest).get
  588. status(manResult) mustEqual OK
  589. manJwt = contentAsJson(manResult)
  590. .as[JsObject].value("access_token")
  591. .as[String]
  592. }
  593. "return BadRequest on user deleting himself" in {
  594. val request = FakeRequest(DELETE, s"/user/${dirObjectId.toHexString}")
  595. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $dirJwt", "X-Requested-With" -> "*")
  596. val result = route(app, request).get
  597. status(result) mustEqual BAD_REQUEST
  598. }
  599. "return Forbidden on Manager trying to delete" in {
  600. val request = FakeRequest(DELETE, s"/user/${dirObjectId.toHexString}")
  601. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $manJwt", "X-Requested-With" -> "*")
  602. val result = route(app, request).get
  603. status(result) mustEqual FORBIDDEN
  604. }
  605. "return NoContent on deleting user" in {
  606. val request = FakeRequest(DELETE, s"/user/${manObjectId.toHexString}")
  607. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $dirJwt", "X-Requested-With" -> "*")
  608. val result = route(app, request).get
  609. status(result) mustEqual ACCEPTED
  610. }
  611. "return Unauthorized on " in {
  612. // create a user and save it in the database
  613. val pass: String = Generator.passGen
  614. val user: Document = ModelGenerator.generateDirector(pass)
  615. val username: String = user.getString("username")
  616. userCollection.insertOne(user).results()
  617. val objectId: ObjectId = userCollection.find(Document("username" -> user.getString("username")))
  618. .first().headResult().getObjectId("_id")
  619. var jwt: String = ""
  620. val loginRequest = FakeRequest(GET, s"/login?username=$username&password=$pass")
  621. .withHeaders(HOST -> "localhost:9000")
  622. val loginResult = route(app, loginRequest).get
  623. status(loginResult) mustEqual OK
  624. jwt = contentAsJson(loginResult)
  625. .as[JsObject].value("access_token")
  626. .as[String]
  627. // delete a director with an access_token already emitted
  628. val request = FakeRequest(DELETE, s"/user/${objectId.toHexString}")
  629. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $dirJwt", "X-Requested-With" -> "*")
  630. val result = route(app, request).get
  631. status(result) mustEqual ACCEPTED
  632. // check if the emitted token is revoked as well
  633. val revokedRequest = FakeRequest(DELETE, s"/user/${manObjectId.toHexString}")
  634. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $jwt", "X-Requested-With" -> "*")
  635. val revokeResult = route(app, revokedRequest).get
  636. status(revokeResult) mustEqual UNAUTHORIZED
  637. }
  638. }
  639. "PATCH /user/:id" should {
  640. // create a user and save it in the database
  641. val password: String = Generator.passGen
  642. val director: Document = ModelGenerator.generateDirector(password)
  643. userCollection.insertOne(director).results()
  644. var dirJwt: String = ""
  645. val dirObjectId: ObjectId = userCollection.find(Document("username" -> director.getString("username")))
  646. .first().headResult().getObjectId("_id")
  647. val manager: Document = ModelGenerator.generateManager(password)
  648. userCollection.insertOne(manager).results()
  649. var manJwt: String = ""
  650. val manObjectId: ObjectId = userCollection.find(Document("username" -> manager.getString("username")))
  651. .first().headResult().getObjectId("_id")
  652. "return Ok and token for both profiles" in {
  653. // login with directors profile
  654. val dirRequest = FakeRequest(GET, s"/login?username=${director.getString("username")}&password=$password")
  655. .withHeaders(HOST -> "localhost:9000")
  656. val dirResult: Future[Result] = route(app, dirRequest).get
  657. status(dirResult) mustEqual OK
  658. dirJwt = contentAsJson(dirResult)
  659. .as[JsObject].value("access_token")
  660. .as[String]
  661. // login with manager profile
  662. val manRequest = FakeRequest(GET, s"/login?username=${manager.getString("username")}&password=$password")
  663. .withHeaders(HOST -> "localhost:9000")
  664. val manResult: Future[Result] = route(app, manRequest).get
  665. status(manResult) mustEqual OK
  666. manJwt = contentAsJson(manResult)
  667. .as[JsObject].value("access_token")
  668. .as[String]
  669. }
  670. "return Conflict on duplicated username" in {
  671. val request = FakeRequest(PATCH, s"/user/${dirObjectId.toHexString}")
  672. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $dirJwt", "X-Requested-With" -> "*")
  673. .withJsonBody(
  674. Json.arr(Patch("replace", "/username", Some(JsString(manager.getString("username")))))
  675. )
  676. val result = route(app, request).get
  677. status(result) mustEqual CONFLICT
  678. }
  679. "return Forbidden on Manager trying to update" in {
  680. val request = FakeRequest(PATCH, s"/user/${dirObjectId.toHexString}")
  681. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $manJwt", "X-Requested-With" -> "*")
  682. .withJsonBody(
  683. Json.arr(Patch("replace", "/username", Some(JsString(manager.getString("username")))))
  684. )
  685. val result = route(app, request).get
  686. status(result) mustEqual FORBIDDEN
  687. }
  688. "return BadRequest an user attempt to change his status" in {
  689. val request = FakeRequest(PATCH, s"/user/${dirObjectId.toHexString}")
  690. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $dirJwt", "X-Requested-With" -> "*")
  691. .withJsonBody(
  692. Json.arr(Patch("replace", "/active", Some(JsBoolean(false))))
  693. )
  694. val result = route(app, request).get
  695. status(result) mustEqual BAD_REQUEST
  696. }
  697. "return BadRequest on user attempt to change his privileges" in {
  698. val request = FakeRequest(PATCH, s"/user/${dirObjectId.toHexString}")
  699. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $dirJwt", "X-Requested-With" -> "*")
  700. .withJsonBody(
  701. Json.arr(Patch("replace", "/role", Some(JsString(Role.MANAGER))))
  702. )
  703. val result = route(app, request).get
  704. status(result) mustEqual BAD_REQUEST
  705. }
  706. "return BadRequest on invalid request body" in {
  707. val request = FakeRequest(PATCH, s"/user/${dirObjectId.toHexString}")
  708. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $dirJwt", "X-Requested-With" -> "*")
  709. .withJsonBody(Json.arr(
  710. Patch("replace", "/name", Some(JsNull)),
  711. Patch("replace", "/email", Some(JsNull))
  712. ))
  713. val result = route(app, request).get
  714. status(result) mustEqual BAD_REQUEST
  715. }
  716. "return Ok on update" in {
  717. val request = FakeRequest(PATCH, s"/user/${dirObjectId.toHexString}")
  718. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $dirJwt", "X-Requested-With" -> "*")
  719. .withJsonBody(Json.arr(
  720. Patch("replace", "/name", Some(JsString(Generator.strGen(20).sample.get))),
  721. Patch("replace", "/email", Some(JsString(Generator.emailAddressGen("growin").sample.get)))
  722. ))
  723. val result = route(app, request).get
  724. status(result) mustEqual NO_CONTENT
  725. }
  726. "return Forbidden on user trying to update an inactive user" in {
  727. // create the user that will later be deactivated
  728. val pass2: String = Generator.passGen
  729. val user2: Document = ModelGenerator.generateDirector(pass2)
  730. userCollection.insertOne(user2).results()
  731. val user2ObjectId = userCollection.find(Document("username" -> user2.getString("username")))
  732. .first().headResult().getObjectId("_id")
  733. // login with that user
  734. val request2 = FakeRequest(GET, s"/login?username=${user2.getString("username")}&password=$pass2")
  735. .withHeaders(HOST -> "localhost:9000")
  736. val result2 = route(app, request2).get
  737. status(result2) mustEqual OK
  738. val jwt2 = contentAsJson(result2)
  739. .as[JsObject].value("access_token")
  740. .as[String]
  741. // deactivate the user2
  742. val request3 = FakeRequest(PATCH, s"/user/${user2ObjectId.toHexString}")
  743. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $dirJwt", "X-Requested-With" -> "*")
  744. .withJsonBody(
  745. Json.arr(Patch("replace", "/active", Some(JsBoolean(false))))
  746. )
  747. val result3 = route(app, request3).get
  748. status(result3) mustEqual NO_CONTENT
  749. // try to use the user2 access_token to reactivate user2
  750. val request4 = FakeRequest(PATCH, s"/user/${user2ObjectId.toString}")
  751. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $jwt2", "X-Requested-With" -> "*")
  752. .withJsonBody(
  753. Json.arr(Patch("replace", "/active", Some(JsBoolean(true))))
  754. )
  755. val result4 = route(app, request4).get
  756. status(result4) mustEqual UNAUTHORIZED
  757. }
  758. }
  759. "GET /user/:id/table_settings" should {
  760. val password: String = Generator.passGen
  761. val user: Document = ModelGenerator.generateActiveUser(password)
  762. userCollection.insertOne(user).results()
  763. var jwt: String = ""
  764. val userId: ObjectId = userCollection.find(Document("username" -> user.getString("username")))
  765. .first().headResult().getObjectId("_id")
  766. "return Ok and a token" in {
  767. val request = FakeRequest(GET, s"/login?username=${user.getString("username")}&password=$password")
  768. .withHeaders(HOST -> "localhost:9000")
  769. val result = route(app, request).get
  770. status(result) mustEqual OK
  771. jwt = contentAsJson(result)
  772. .as[JsObject].value("access_token")
  773. .as[String]
  774. }
  775. "return Ok and table_settings model" in {
  776. val request = FakeRequest(GET, s"/user/${userId.toHexString}/table_settings")
  777. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $jwt")
  778. val result = route(app, request).get
  779. status(result) mustEqual OK
  780. contentAsJson(result).as[JsObject].values.forall(p => p == JsNumber(1))
  781. }
  782. }
  783. "PATCH /user/:id/table_settings" should {
  784. val password: String = Generator.passGen
  785. val user: Document = ModelGenerator.generateActiveUser(password)
  786. userCollection.insertOne(user).results()
  787. var jwt: String = ""
  788. val userId: ObjectId = userCollection.find(Document("username" -> user.getString("username")))
  789. .first().headResult().getObjectId("_id")
  790. "return Ok and a token" in {
  791. val request = FakeRequest(GET, s"/login?username=${user.getString("username")}&password=$password")
  792. .withHeaders(HOST -> "localhost:9000")
  793. val result = route(app, request).get
  794. status(result) mustEqual OK
  795. jwt = contentAsJson(result)
  796. .as[JsObject].value("access_token")
  797. .as[String]
  798. }
  799. "return BadRequest on invalid body" in {
  800. val request = FakeRequest(PATCH, s"/user/${userId.toHexString}/table_settings")
  801. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $jwt", "X-Requested-With" -> "*")
  802. .withJsonBody(Json.arr(
  803. Patch("remove", "/tableHeader/address", None),
  804. Patch("add", "/tableHeader/address", Some(JsNull))
  805. ))
  806. val result = route(app, request).get
  807. status(result) mustEqual BAD_REQUEST
  808. val request2 = FakeRequest(PATCH, s"/user/${userId.toHexString}/table_settings")
  809. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $jwt", "X-Requested-With" -> "*")
  810. .withJsonBody(Json.arr(
  811. Patch("remove", "/tableHeader/address", Some(JsNumber(1))),
  812. Patch("add", "/tableHeader/address", Some(JsNumber(1)))
  813. ))
  814. val result2 = route(app, request2).get
  815. status(result2) mustEqual BAD_REQUEST
  816. val request3 = FakeRequest(PATCH, s"/user/${userId.toHexString}/table_settings")
  817. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $jwt", "X-Requested-With" -> "*")
  818. .withJsonBody(Json.arr(
  819. Patch("remove", "/tableHeader/address", None),
  820. Patch("add", "/tableHeader/address", None)
  821. ))
  822. val result3 = route(app, request3).get
  823. status(result3) mustEqual BAD_REQUEST
  824. }
  825. "return NoContent" in {
  826. val request = FakeRequest(PATCH, s"/user/${userId.toHexString}/table_settings")
  827. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $jwt", "X-Requested-With" -> "*")
  828. .withJsonBody(Json.arr(
  829. Patch("remove", "/tableHeader/address", None),
  830. Patch("add", "/tableHeader/address", Some(JsNumber(1)))
  831. ))
  832. val result = route(app, request).get
  833. status(result) mustEqual NO_CONTENT
  834. }
  835. }
  836. "GET /user/:id/takeout" should {
  837. // create a user and save it in the database
  838. val password: String = Generator.passGen
  839. val director: Document = ModelGenerator.generateDirector(password)
  840. userCollection.insertOne(director).results()
  841. var dirJwt: String = ""
  842. val manager: Document = ModelGenerator.generateManager(password)
  843. userCollection.insertOne(manager).results()
  844. var manJwt: String = ""
  845. val userId = userCollection.find(Document("username" -> director.getString("username")))
  846. .first().headResult().getObjectId("_id")
  847. "return Ok and token" in {
  848. // login with that user
  849. val dirRequest = FakeRequest(GET, s"/login?username=${director.getString("username")}&password=$password")
  850. .withHeaders(HOST -> "localhost:9000")
  851. val dirResult: Future[Result] = route(app, dirRequest).get
  852. status(dirResult) mustEqual OK
  853. dirJwt = contentAsJson(dirResult)
  854. .as[JsObject].value("access_token")
  855. .as[String]
  856. val manRequest = FakeRequest(GET, s"/login?username=${manager.getString("username")}&password=$password")
  857. .withHeaders(HOST -> "localhost:9000")
  858. val manResult: Future[Result] = route(app, manRequest).get
  859. status(manResult)
  860. manJwt = contentAsJson(manResult)
  861. .as[JsObject].value("access_token")
  862. .as[String]
  863. }
  864. "return Forbidden on manager exporting a user" in {
  865. val request = FakeRequest(GET, s"/user/${userId.toHexString}/takeout")
  866. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $manJwt")
  867. val result = route(app, request).get
  868. status(result) mustEqual FORBIDDEN
  869. }
  870. "return BadRequest on invalid parameters" in {
  871. // invalid id
  872. val request1 = FakeRequest(GET, s"/user/null/takeout")
  873. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $dirJwt")
  874. val result1 = route(app, request1).get
  875. status(result1) mustEqual BAD_REQUEST
  876. }
  877. "Return NotFound on non-existent user" in {
  878. val id = BSONObjectID.generate().stringify
  879. val request = FakeRequest(GET, s"/user/$id/takeout")
  880. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $dirJwt")
  881. val result = route(app, request).get
  882. status(result) mustEqual NOT_FOUND
  883. }
  884. "return Ok and " in {
  885. val request = FakeRequest(GET, s"/user/${userId.toHexString}/takeout")
  886. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $dirJwt")
  887. val result = route(app, request).get
  888. status(result) mustEqual OK
  889. }
  890. }
  891. // Candidates
  892. "POST /candidates" should {
  893. val password: String = Generator.passGen
  894. val user: Document = ModelGenerator.generateActiveUser(password)
  895. userCollection.insertOne(user).results()
  896. var jwt: String = ""
  897. val candidate = ModelGenerator.generateCandidate
  898. candidateCollection.insertOne(candidate).results()
  899. val candidateId = candidateCollection.find(Document("email" -> candidate.getString("email")))
  900. .first().headResult().getObjectId("_id")
  901. "return Ok and a token" in {
  902. val request = FakeRequest(GET, s"/login?username=${user.getString("username")}&password=$password")
  903. .withHeaders(HOST -> "localhost:9000")
  904. val result = route(app, request).get
  905. status(result) mustEqual OK
  906. jwt = contentAsJson(result)
  907. .as[JsObject].value("access_token")
  908. .as[String]
  909. }
  910. "return Conflict" in {
  911. // Email
  912. val candidate2 = ModelGenerator.generateCandidate
  913. val request2 = FakeRequest(POST, s"/candidates")
  914. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $jwt", "X-Requested-With" -> "*")
  915. .withJsonBody(Json.parse(candidate2.+("email" -> candidate.getString("email")).toJson()))
  916. val result2 = route(app, request2).get
  917. status(result2) mustEqual CONFLICT
  918. // Name and Phone
  919. val candidate3 = ModelGenerator.generateCandidate
  920. val request3 = FakeRequest(POST, s"/candidates")
  921. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $jwt", "X-Requested-With" -> "*")
  922. .withJsonBody(Json.parse(candidate3
  923. .+("name" -> candidate.getString("name"))
  924. .+("phonenumber" -> candidate.getString("phonenumber"))
  925. .toJson())
  926. )
  927. val result3 = route(app, request3).get
  928. status(result3) mustEqual CONFLICT
  929. // Name and Birthdate
  930. val candidate4 = ModelGenerator.generateCandidate
  931. val request4 = FakeRequest(POST, s"/candidates")
  932. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $jwt", "X-Requested-With" -> "*")
  933. .withJsonBody(Json.parse(candidate3
  934. .+("name" -> candidate.getString("name"))
  935. .+("birthdate" -> candidate.getString("birthdate"))
  936. .toJson())
  937. )
  938. val result4 = route(app, request4).get
  939. status(result4) mustEqual CONFLICT
  940. }
  941. /*"return BadRequest" in {
  942. val candidate2 = ModelGenerator.generateCandidate
  943. val request2 = FakeRequest(POST, s"/candidates")
  944. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $jwt")
  945. .withJsonBody(Json.parse(candidate2
  946. .-("name")
  947. .+("email" -> "invalid")
  948. .toJson()))
  949. val result2 = route(app, request2).get
  950. status(result2) mustEqual BAD_REQUEST
  951. // have no ideia why this keeps failing
  952. }*/
  953. "return Created" in {
  954. val candidate2 = ModelGenerator.generateCandidate
  955. val request = FakeRequest(POST, s"/candidates")
  956. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $jwt", "X-Requested-With" -> "*")
  957. .withJsonBody(Json.parse(candidate2.toJson()))
  958. val result = route(app, request).get
  959. status(result) mustEqual CREATED
  960. }
  961. }
  962. "GET /candidate/:id" should {
  963. val password: String = Generator.passGen
  964. val user: Document = ModelGenerator.generateActiveUser(password)
  965. userCollection.insertOne(user).results()
  966. var jwt: String = ""
  967. val candidate = ModelGenerator.generateCandidate
  968. candidateCollection.insertOne(candidate).results()
  969. val candidateId: ObjectId = candidateCollection.find(Document("email" -> candidate.getString("email")))
  970. .first().headResult().getObjectId("_id")
  971. "return Ok and a token" in {
  972. val request = FakeRequest(GET, s"/login?username=${user.getString("username")}&password=$password")
  973. .withHeaders(HOST -> "localhost:9000")
  974. val result = route(app, request).get
  975. status(result) mustEqual OK
  976. jwt = contentAsJson(result)
  977. .as[JsObject].value("access_token")
  978. .as[String]
  979. }
  980. "return a Candidate" in {
  981. val request = FakeRequest(GET, s"/candidate/${candidateId.toHexString}")
  982. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $jwt")
  983. val result = route(app, request).get
  984. status(result) mustEqual OK
  985. contentAsJson(result).as[JsObject].\("id").isDefined mustEqual true
  986. }
  987. }
  988. "GET /candidate/:id/file/:file_ids" should {
  989. val password: String = Generator.passGen
  990. val user: Document = ModelGenerator.generateDirector(password)
  991. userCollection.insertOne(user).results()
  992. var jwt: String = ""
  993. val candidate = ModelGenerator.generateCandidate
  994. candidateCollection.insertOne(candidate).results()
  995. val candidateId: ObjectId = candidateCollection.find(Document("email" -> candidate.getString("email")))
  996. .first().headResult().getObjectId("_id")
  997. "return Ok and a token" in {
  998. val request = FakeRequest(GET, s"/login?username=${user.getString("username")}&password=$password")
  999. .withHeaders(HOST -> "localhost:9000")
  1000. val result = route(app, request).get
  1001. status(result) mustEqual OK
  1002. jwt = contentAsJson(result)
  1003. .as[JsObject].value("access_token")
  1004. .as[String]
  1005. }
  1006. "return a BadRequest when trying to delete a file with an id that does not have the correct formmat" in {
  1007. val request = FakeRequest(GET, s"/candidate/${candidateId.toHexString}/file/1234567890")
  1008. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $jwt")
  1009. val result = route(app, request).get
  1010. status(result) mustEqual BAD_REQUEST
  1011. }
  1012. "return a NotFound when trying to delete a file with an id that does not exist" in {
  1013. val request = FakeRequest(GET, s"/candidate/${candidateId.toHexString}/file/${BSONObjectID.generate().stringify}")
  1014. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $jwt")
  1015. val result = route(app, request).get
  1016. status(result) mustEqual NOT_FOUND
  1017. }
  1018. "return a NoContent deleting a file" in {
  1019. // inserting a virtual txt file as a candidate attachment
  1020. // TODO: actually try to materialize this virtual temporary file and check if it is deleted
  1021. val fileId = BSONObjectID.generate().stringify
  1022. val fileName = Document("fileName" -> "someattachmentName")
  1023. val storageName = Document("storageName" -> fileId)
  1024. val uploadTime = Document("uploadTime" -> "someattachmentName")
  1025. val modifier = Document("attachment" -> "")
  1026. val selector = Document("email" -> candidate.getString("email"))
  1027. candidateCollection.replaceOne(selector, modifier).results()
  1028. val request = FakeRequest(GET, s"/candidate/${candidateId.toHexString}")
  1029. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $jwt")
  1030. val result = route(app, request).get
  1031. status(result) mustEqual OK
  1032. contentAsJson(result).as[JsObject].\("id").isDefined mustEqual true
  1033. }
  1034. }
  1035. "DELETE /candidate/:id" should {
  1036. val password: String = Generator.passGen
  1037. val director: Document = ModelGenerator.generateDirector(password)
  1038. userCollection.insertOne(director).results()
  1039. var dirJwt: String = ""
  1040. val manager = ModelGenerator.generateManager(password)
  1041. userCollection.insertOne(manager).results()
  1042. var manJwt: String = ""
  1043. val candidate = ModelGenerator.generateCandidate
  1044. candidateCollection.insertOne(candidate).results()
  1045. val candidateId: ObjectId = candidateCollection.find(Document("email" -> candidate.getString("email")))
  1046. .first().headResult().getObjectId("_id")
  1047. "return Ok amd a token" in {
  1048. val request1 = FakeRequest(GET, s"/login?username=${director.getString("username")}&password=$password")
  1049. .withHeaders(HOST -> "localhost:9000")
  1050. val result1 = route(app, request1).get
  1051. status(result1) mustEqual OK
  1052. dirJwt = contentAsJson(result1)
  1053. .as[JsObject].value("access_token")
  1054. .as[String]
  1055. val request2 = FakeRequest(GET, s"/login?username=${manager.getString("username")}&password=$password")
  1056. .withHeaders(HOST -> "localhost:9000")
  1057. val result2 = route(app, request2).get
  1058. status(result2) mustEqual OK
  1059. manJwt = contentAsJson(result2)
  1060. .as[JsObject].value("access_token")
  1061. .as[String]
  1062. }
  1063. "return Forbidden manager deleting a candidate" in {
  1064. val request = FakeRequest(DELETE, s"/candidate/${candidateId.toHexString}")
  1065. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $manJwt", "X-Requested-With" -> "*")
  1066. val result = route(app, request).get
  1067. status(result) mustEqual FORBIDDEN
  1068. }
  1069. "return NoContent on deleting a candidate" in {
  1070. val request = FakeRequest(DELETE, s"/candidate/${candidateId.toHexString}")
  1071. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $dirJwt", "X-Requested-With" -> "*")
  1072. val result = route(app, request).get
  1073. status(result) mustEqual ACCEPTED
  1074. }
  1075. }
  1076. "GET /candidate/:id/takeout" should {
  1077. // create a user and save it in the database
  1078. val password: String = Generator.passGen
  1079. val director: Document = ModelGenerator.generateDirector(password)
  1080. userCollection.insertOne(director).results()
  1081. var dirJwt: String = ""
  1082. val manager: Document = ModelGenerator.generateManager(password)
  1083. userCollection.insertOne(manager).results()
  1084. var manJwt: String = ""
  1085. val candidate = ModelGenerator.generateCandidate
  1086. candidateCollection.insertOne(candidate).results()
  1087. val candidateId = candidateCollection.find(Document("email" -> candidate.getString("email")))
  1088. .first().headResult().getObjectId("_id")
  1089. "return Ok and token" in {
  1090. // login with that user
  1091. val dirRequest = FakeRequest(GET, s"/login?username=${director.getString("username")}&password=$password")
  1092. .withHeaders(HOST -> "localhost:9000")
  1093. val dirResult: Future[Result] = route(app, dirRequest).get
  1094. status(dirResult) mustEqual OK
  1095. dirJwt = contentAsJson(dirResult)
  1096. .as[JsObject].value("access_token")
  1097. .as[String]
  1098. val manRequest = FakeRequest(GET, s"/login?username=${manager.getString("username")}&password=$password")
  1099. .withHeaders(HOST -> "localhost:9000")
  1100. val manResult: Future[Result] = route(app, manRequest).get
  1101. status(manResult)
  1102. manJwt = contentAsJson(manResult)
  1103. .as[JsObject].value("access_token")
  1104. .as[String]
  1105. }
  1106. "return Forbidden on manager exporting a candidate" in {
  1107. val request = FakeRequest(GET, s"/candidate/${candidateId.toHexString}/takeout")
  1108. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $manJwt")
  1109. val result = route(app, request).get
  1110. status(result) mustEqual FORBIDDEN
  1111. }
  1112. "return BadRequest on invalid parameters" in {
  1113. // invalid id
  1114. val request1 = FakeRequest(GET, s"/candidate/null/takeout")
  1115. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $dirJwt")
  1116. val result1 = route(app, request1).get
  1117. status(result1) mustEqual BAD_REQUEST
  1118. }
  1119. "Return NotFound on non-existent candidate" in {
  1120. val id = BSONObjectID.generate().stringify
  1121. val request = FakeRequest(GET, s"/candidate/$id/takeout")
  1122. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $dirJwt")
  1123. val result = route(app, request).get
  1124. status(result) mustEqual NOT_FOUND
  1125. }
  1126. "return Ok and " in {
  1127. val request = FakeRequest(GET, s"/candidate/${candidateId.toHexString}/takeout")
  1128. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $dirJwt")
  1129. val result = route(app, request).get
  1130. status(result) mustEqual OK
  1131. }
  1132. }
  1133. // Events
  1134. "GET /candidate/:id/events" should {
  1135. val password: String = Generator.passGen
  1136. val user: Document = ModelGenerator.generateActiveUser(password)
  1137. userCollection.insertOne(user).results()
  1138. var jwt: String = ""
  1139. val candidate = ModelGenerator.generateCandidate
  1140. candidateCollection.insertOne(candidate).results()
  1141. val candidateId: ObjectId = candidateCollection.find(Document("email" -> candidate.getString("email")))
  1142. .first().headResult().getObjectId("_id")
  1143. val event = ModelGenerator.generateEventCandidateCreation(candidateId.toHexString)
  1144. eventCollection.insertOne(event).results()
  1145. eventCollection.insertMany(
  1146. (0 to 10).map(_ => ModelGenerator.generateEventActivity(candidateId.toHexString, user.getString("username")))
  1147. ).results()
  1148. eventCollection.insertMany(
  1149. (0 to 10).map(_ => ModelGenerator.generateEventInterview(candidateId.toHexString, user.getString("username")))
  1150. ).results()
  1151. "return Ok and a token" in {
  1152. val request = FakeRequest(GET, s"/login?username=${user.getString("username")}&password=$password")
  1153. .withHeaders(HOST -> "localhost:9000")
  1154. val result = route(app, request).get
  1155. status(result) mustEqual OK
  1156. jwt = contentAsJson(result)
  1157. .as[JsObject].value("access_token")
  1158. .as[String]
  1159. }
  1160. "return Ok a an event list" in {
  1161. val request = FakeRequest(GET, s"/candidate/${candidateId.toHexString}/events")
  1162. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $jwt")
  1163. val result = route(app, request).get
  1164. status(result) mustEqual OK
  1165. val body = contentAsJson(result).as[JsArray]
  1166. body.value.size mustEqual 20
  1167. body.value.forall(p => p.validateOpt[Event].isSuccess) mustEqual true
  1168. }
  1169. }
  1170. "POST /candidate/:id/events" should {
  1171. val password: String = Generator.passGen
  1172. val user: Document = ModelGenerator.generateActiveUser(password)
  1173. userCollection.insertOne(user).results()
  1174. var jwt: String = ""
  1175. val candidate = ModelGenerator.generateCandidate
  1176. candidateCollection.insertOne(candidate).results()
  1177. val candidateId: ObjectId = candidateCollection.find(Document("email" -> candidate.getString("email")))
  1178. .first().headResult().getObjectId("_id")
  1179. "return Ok and a token" in {
  1180. val request = FakeRequest(GET, s"/login?username=${user.getString("username")}&password=$password")
  1181. .withHeaders(HOST -> "localhost:9000")
  1182. val result = route(app, request).get
  1183. status(result) mustEqual OK
  1184. jwt = contentAsJson(result)
  1185. .as[JsObject].value("access_token")
  1186. .as[String]
  1187. }
  1188. "return NotFound on non-existent Candidate" in {
  1189. val request = FakeRequest(POST, "/candidate/591f70e01c773ed0aa5506d4/events")
  1190. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $jwt", "X-Requested-With" -> "*")
  1191. .withBody(Json.obj(
  1192. "kind" -> Interview,
  1193. "content" -> Generator.strGen(20).sample.get
  1194. ))
  1195. val result = route(app, request).get
  1196. status(result) mustEqual NOT_FOUND
  1197. }
  1198. "return BadRequest on invalid Event" in {
  1199. // missing event type
  1200. val request1 = FakeRequest(POST, s"/candidate/${candidateId.toHexString}/events")
  1201. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $jwt", "X-Requested-With" -> "*")
  1202. .withBody(Json.obj(
  1203. "content" -> Generator.strGen(20).sample.get
  1204. ))
  1205. val result1 = route(app, request1).get
  1206. status(result1) mustEqual BAD_REQUEST
  1207. // invalid event type
  1208. val request2 = FakeRequest(POST, s"/candidate/${candidateId.toHexString}/events")
  1209. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $jwt", "X-Requested-With" -> "*")
  1210. .withBody(Json.obj(
  1211. "kind" -> JsNull,
  1212. "content" -> Generator.strGen(20).sample.get
  1213. ))
  1214. val result2 = route(app, request2).get
  1215. status(result2) mustEqual BAD_REQUEST
  1216. }
  1217. "return Ok and saving the event" in {
  1218. val request = FakeRequest(POST, s"/candidate/${candidateId.toHexString}/events")
  1219. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $jwt", "X-Requested-With" -> "*")
  1220. .withBody(Json.obj(
  1221. "kind" -> Activity,
  1222. "content" -> Generator.strGen(20).sample.get
  1223. ))
  1224. val result = route(app, request).get
  1225. status(result) mustEqual CREATED
  1226. }
  1227. }
  1228. "GET /candidate/:id/event/:event_id" should {
  1229. val password: String = Generator.passGen
  1230. val user: Document = ModelGenerator.generateActiveUser(password)
  1231. userCollection.insertOne(user).results()
  1232. var jwt: String = ""
  1233. val candidate = ModelGenerator.generateCandidate
  1234. candidateCollection.insertOne(candidate).results()
  1235. val candidateId: ObjectId = candidateCollection.find(Document("email" -> candidate.getString("email")))
  1236. .first().headResult().getObjectId("_id")
  1237. val event = ModelGenerator.generateEventCandidateCreation(candidateId.toHexString)
  1238. eventCollection.insertOne(event).results()
  1239. val eventId: ObjectId = eventCollection.find(Document("candidateId" -> candidateId.toHexString))
  1240. .first().headResult().getObjectId("_id")
  1241. "return Ok and a token" in {
  1242. val request = FakeRequest(GET, s"/login?username=${user.getString("username")}&password=$password")
  1243. .withHeaders(HOST -> "localhost:9000")
  1244. val result = route(app, request).get
  1245. status(result) mustEqual OK
  1246. jwt = contentAsJson(result)
  1247. .as[JsObject].value("access_token")
  1248. .as[String]
  1249. }
  1250. "return an Ok and an Event" in {
  1251. val request = FakeRequest(GET, s"/candidate/${candidateId.toHexString}/event/${eventId.toHexString}")
  1252. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $jwt")
  1253. val result = route(app, request).get
  1254. status(result) mustEqual OK
  1255. contentAsJson(result).validate[Event].isSuccess mustEqual true
  1256. }
  1257. }
  1258. "PATCH /candidate/:id/event/:event_id" should {
  1259. val password: String = Generator.passGen
  1260. val user: Document = ModelGenerator.generateActiveUser(password)
  1261. userCollection.insertOne(user).results()
  1262. var jwt: String = ""
  1263. val candidate = ModelGenerator.generateCandidate
  1264. candidateCollection.insertOne(candidate).results()
  1265. val candidateId: ObjectId = candidateCollection.find(Document("email" -> candidate.getString("email")))
  1266. .first().headResult().getObjectId("_id")
  1267. val event = ModelGenerator.generateEventInterview(candidateId.toHexString, user.getString("username"))
  1268. eventCollection.insertOne(event).results()
  1269. val eventId: ObjectId = eventCollection.find(Document("candidateId" -> candidateId.toHexString))
  1270. .first().headResult().getObjectId("_id")
  1271. "return Ok and a token" in {
  1272. val request = FakeRequest(GET, s"/login?username=${user.getString("username")}&password=$password")
  1273. .withHeaders(HOST -> "localhost:9000")
  1274. val result = route(app, request).get
  1275. status(result) mustEqual OK
  1276. jwt = contentAsJson(result)
  1277. .as[JsObject].value("access_token")
  1278. .as[String]
  1279. }
  1280. "return BadRequest on invalid body" in {
  1281. // unsupported patch operation
  1282. val request1 = FakeRequest(PATCH, s"/candidate/${candidateId.toHexString}/event/${eventId.toHexString}")
  1283. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $jwt", "X-Requested-With" -> "*")
  1284. .withBody(Json.toJson(Patch("add", "/content", Some(JsString(Generator.strGen(20).sample.get)))))
  1285. val result1 = route(app, request1).get
  1286. status(result1) mustEqual BAD_REQUEST
  1287. // wrong patch path
  1288. val request2 = FakeRequest(PATCH, s"/candidate/${candidateId.toHexString}/event/${eventId.toHexString}")
  1289. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $jwt", "X-Requested-With" -> "*")
  1290. .withBody(Json.toJson(Patch("replace", null, Some(JsString(Generator.strGen(20).sample.get)))))
  1291. val result2 = route(app, request2).get
  1292. status(result2) mustEqual BAD_REQUEST
  1293. val request3 = FakeRequest(PATCH, s"/candidate/${candidateId.toHexString}/event/${eventId.toHexString}")
  1294. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $jwt", "X-Requested-With" -> "*")
  1295. .withBody(Json.toJson(Patch("replace", "/username", Some(JsString(Generator.strGen(20).sample.get)))))
  1296. val result3 = route(app, request3).get
  1297. status(result3) mustEqual BAD_REQUEST
  1298. // empty patch value
  1299. val request4 = FakeRequest(PATCH, s"/candidate/${candidateId.toHexString}/event/${eventId.toHexString}")
  1300. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $jwt", "X-Requested-With" -> "*")
  1301. .withBody(Json.toJson(Patch("replace", "/content", Some(JsString("")))))
  1302. val result4 = route(app, request4).get
  1303. status(result4) mustEqual BAD_REQUEST
  1304. }
  1305. "return Forbidden on different username" in {
  1306. val event2 = ModelGenerator.generateEventActivity(candidateId.toHexString, Generator.strGen(5).sample.get)
  1307. eventCollection.insertOne(event2).results()
  1308. val event2Id: ObjectId = eventCollection.find(Document("date" -> event2.getString("date")))
  1309. .first().headResult().getObjectId("_id")
  1310. val request = FakeRequest(PATCH, s"/candidate/${candidateId.toHexString}/event/${event2Id.toHexString}")
  1311. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $jwt", "X-Requested-With" -> "*")
  1312. .withBody(Json.toJson(Patch("replace", "/content", Some(JsString(Generator.strGen(20).sample.get)))))
  1313. val result = route(app, request).get
  1314. status(result) mustEqual FORBIDDEN
  1315. }
  1316. "return NoContent on successful patch" in {
  1317. val request = FakeRequest(PATCH, s"/candidate/${candidateId.toHexString}/event/${eventId.toHexString}")
  1318. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $jwt", "X-Requested-With" -> "*")
  1319. .withBody(Json.toJson(Patch("replace", "/content", Some(JsString(Generator.strGen(20).sample.get)))))
  1320. val result = route(app, request).get
  1321. status(result) mustEqual ACCEPTED
  1322. }
  1323. }
  1324. "DELETE /candidate/:id/event/:event_id" should {
  1325. val password: String = Generator.passGen
  1326. val user: Document = ModelGenerator.generateActiveUser(password)
  1327. userCollection.insertOne(user).results()
  1328. var jwt: String = ""
  1329. val candidate = ModelGenerator.generateCandidate
  1330. candidateCollection.insertOne(candidate).results()
  1331. val candidateId: ObjectId = candidateCollection.find(Document("email" -> candidate.getString("email")))
  1332. .first().headResult().getObjectId("_id")
  1333. val event = ModelGenerator.generateEventInterview(candidateId.toHexString, user.getString("username"))
  1334. eventCollection.insertOne(event).results()
  1335. val eventId: ObjectId = eventCollection.find(Document("candidateId" -> candidateId.toHexString))
  1336. .first().headResult().getObjectId("_id")
  1337. "return Ok and a token" in {
  1338. val request = FakeRequest(GET, s"/login?username=${user.getString("username")}&password=$password")
  1339. .withHeaders(HOST -> "localhost:9000")
  1340. val result = route(app, request).get
  1341. status(result) mustEqual OK
  1342. jwt = contentAsJson(result)
  1343. .as[JsObject].value("access_token")
  1344. .as[String]
  1345. }
  1346. "return Forbidden on different username" in {
  1347. val manager: Document = ModelGenerator.generateManager(password)
  1348. userCollection.insertOne(manager).results()
  1349. val login = FakeRequest(GET, s"/login?username=${manager.getString("username")}&password=$password")
  1350. .withHeaders(HOST -> "localhost:9000")
  1351. val response = route(app, login).get
  1352. status(response) mustEqual OK
  1353. val managerJwt = contentAsJson(response)
  1354. .as[JsObject].value("access_token")
  1355. .as[String]
  1356. val request = FakeRequest(DELETE, s"/candidate/${candidateId.toHexString}/event/${eventId.toHexString}")
  1357. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $managerJwt", "X-Requested-With" -> "*")
  1358. val result = route(app, request).get
  1359. status(result) mustEqual FORBIDDEN
  1360. }
  1361. "return NoContent on successful deletion" in {
  1362. val request = FakeRequest(DELETE, s"/candidate/${candidateId.toHexString}/event/${eventId.toHexString}")
  1363. .withHeaders(HOST -> "localhost:9000", "Authorization" -> s"Bearer $jwt", "X-Requested-With" -> "*")
  1364. val result = route(app, request).get
  1365. status(result) mustEqual ACCEPTED
  1366. }
  1367. }
  1368. // System
  1369. // WARNING: the endpoint /system/password_reset sends an email to the user!
  1370. // Before running this test, disable "email notification" by commenting those lines. Search for: "email notification"
  1371. "GET /system/forgot_password" should {
  1372. "return BadRequest when not providing the required parameter" in {
  1373. val request = FakeRequest(GET, "/system/forgot_password")
  1374. .withHeaders(HOST -> "localhost:9000")
  1375. val result: Future[Result] = route(app, request).get
  1376. status(result) mustEqual BAD_REQUEST
  1377. }
  1378. "return BadRequest when giving an invalid parameter key" in {
  1379. val userTest = ModelGenerator.generateActiveUser("123")
  1380. userCollection.insertOne(userTest).results()
  1381. val request = FakeRequest(GET, s"/system/forgot_password?www=${userTest.getString("username")}")
  1382. .withHeaders(HOST -> "localhost:9000")
  1383. val result: Future[Result] = route(app, request).get
  1384. status(result) mustEqual BAD_REQUEST
  1385. }
  1386. "return Accepted when giving an unknown username" in {
  1387. val request = FakeRequest(GET, "/system/forgot_password?username=qwerty")
  1388. .withHeaders(HOST -> "localhost:9000")
  1389. val result: Future[Result] = route(app, request).get
  1390. status(result) mustEqual ACCEPTED
  1391. }
  1392. "return Accepted when giving null as username" in {
  1393. val request = FakeRequest(GET, "/system/forgot_password?username=null")
  1394. .withHeaders(HOST -> "localhost:9000")
  1395. val result: Future[Result] = route(app, request).get
  1396. status(result) mustEqual ACCEPTED
  1397. }
  1398. "return Accepted and don't generate a token when user is inactive" in {
  1399. val userTest: Document = ModelGenerator.generateInactiveUser("123")
  1400. userCollection.insertOne(userTest).results()
  1401. val request = FakeRequest(GET, s"/system/forgot_password?username=${userTest.getString("username")}")
  1402. .withHeaders(HOST -> "localhost:9000")
  1403. val result: Future[Result] = route(app, request).get
  1404. status(result) mustEqual ACCEPTED
  1405. waitingOnApi()
  1406. // Token to change password should be sent to adminUser("username")
  1407. // Since we can't check that, we will see if the token was stored in the DB:
  1408. val selector: Document = Document("username" -> userTest("username"))
  1409. val findToken: Seq[Document] = tokenCollection.find(selector).results()
  1410. findToken.size mustEqual 0
  1411. }
  1412. "return Accepted and generate a token when giving a known active username" in {
  1413. tokenCollection.drop().results()
  1414. val userTest = ModelGenerator.generateActiveUser("123")
  1415. userCollection.insertOne(userTest).results()
  1416. val request = FakeRequest(GET, s"/system/forgot_password?username=${userTest.getString("username")}")
  1417. .withHeaders(HOST -> "localhost:9000")
  1418. val result: Future[Result] = route(app, request).get
  1419. status(result) mustEqual ACCEPTED
  1420. waitingOnApi()
  1421. // Check if the token was generated
  1422. val selector = Document("username" -> userTest.getString("username"))
  1423. val token = tokenCollection.find(selector).results()
  1424. token.size mustEqual 1
  1425. token.head.getString("username") mustEqual userTest.getString("username")
  1426. }
  1427. }
  1428. "POST /system/reset_password/:token" should {
  1429. "return NotFound when not providing the required username path parameter" in {
  1430. val request = FakeRequest(POST, "/system/reset_password")
  1431. .withHeaders(HOST -> "localhost:9000")
  1432. val result: Future[Result] = route(app, request).get
  1433. status(result) mustEqual NOT_FOUND
  1434. }
  1435. "return BadRequest when missing id is not UUID" in {
  1436. val request = FakeRequest(POST, s"/system/reset_password/123?pass1=123&pass2=123")
  1437. .withHeaders(HOST -> "localhost:9000")
  1438. val result: Future[Result] = route(app, request).get
  1439. status(result) mustEqual BAD_REQUEST
  1440. }
  1441. "return BadRequest when missing required parameters" in {
  1442. val request = FakeRequest(POST, s"/system/reset_password/${Generator.passGen}")
  1443. .withHeaders(HOST -> "localhost:9000")
  1444. val result: Future[Result] = route(app, request).get
  1445. status(result) mustEqual BAD_REQUEST
  1446. }
  1447. "return BadRequest when sending different passwords" in {
  1448. val user = ModelGenerator.generateActiveUser(Generator.passGen)
  1449. userCollection.insertOne(user).results()
  1450. val requestReset = FakeRequest(GET, s"/system/forgot_password?username=${user.getString("username")}")
  1451. .withHeaders(HOST -> "localhost:9000")
  1452. val resultReset: Future[Result] = route(app, requestReset).get
  1453. status(resultReset) mustEqual ACCEPTED
  1454. waitingOnApi()
  1455. // Checking if the token sent was stored in the DB.
  1456. val selector = Document("username" -> user.getString("username"))
  1457. val token = tokenCollection.find(selector).first().results()
  1458. token.size mustEqual 1
  1459. token.head.getString("username") mustEqual user.getString("username")
  1460. val id = token.head.getString("accessToken")
  1461. val newPass1 = Generator.passGen
  1462. val newPass2 = Generator.passGen
  1463. // changing password operation with the new same password
  1464. val requestChange = FakeRequest(POST, s"/system/reset_password/$id?pass1=$newPass1&pass2=$newPass2")
  1465. .withHeaders(HOST -> "localhost:9000")
  1466. val resultChange: Future[Result] = route(app, requestChange).get
  1467. status(resultChange) mustEqual BAD_REQUEST
  1468. }
  1469. "return Accepted when token has expired" in {
  1470. val user = ModelGenerator.generateActiveUser(Generator.passGen)
  1471. userCollection.insertOne(user).results()
  1472. val requestReset = FakeRequest(GET, s"/system/forgot_password?username=${user.getString("username")}")
  1473. .withHeaders(HOST -> "localhost:9000")
  1474. val resultReset: Future[Result] = route(app, requestReset).get
  1475. status(resultReset) mustEqual ACCEPTED
  1476. waitingOnApi()
  1477. // Checking if the token sent was stored in the DB.
  1478. val selector = Document("username" -> user.getString("username"))
  1479. val token = tokenCollection.find(selector).first().results()
  1480. token.size mustEqual 1
  1481. token.head.getString("username") mustEqual user.getString("username")
  1482. val outdatedToken = token.head.+("expiresAt" -> Instant.now.toString)
  1483. tokenCollection.replaceOne(token.head, outdatedToken).results()
  1484. val id = token.head.getString("accessToken")
  1485. val newPass = Generator.passGen
  1486. waitingOnApi()
  1487. // changing password operation with the new same password
  1488. val requestChange = FakeRequest(POST, s"/system/reset_password/$id?pass1=$newPass&pass2=$newPass")
  1489. .withHeaders(HOST -> "localhost:9000")
  1490. val resultChange: Future[Result] = route(app, requestChange).get
  1491. status(resultChange) mustEqual ACCEPTED
  1492. }
  1493. "return Accepted, delete token and don't change password when user is inactive but still has a token" in {
  1494. val userTest: Document = ModelGenerator.generateActiveUser(Generator.passGen)
  1495. val userTestInactive: Document = userTest.+("active" -> false)
  1496. userCollection.insertOne(userTest).results() // insert the active temporary user in DB
  1497. tokenCollection.drop().results() // make sure the token collection is empty for this test
  1498. val newPass: String = Generator.passGen
  1499. val requestReset = FakeRequest(GET, s"/system/forgot_password?username=${userTest.getString("username")}")
  1500. .withHeaders(HOST -> "localhost:9000")
  1501. val resultReset: Future[Result] = route(app, requestReset).get
  1502. status(resultReset) mustEqual ACCEPTED
  1503. waitingOnApi()
  1504. // Checking if the token sent was stored in the DB.
  1505. val selector = Document("username" -> userTest.getString("username"))
  1506. val token = tokenCollection.find(selector).first().results()
  1507. token.size mustEqual 1
  1508. token.head.getString("username") mustEqual userTest.getString("username")
  1509. // replace the temporary user for it's inactive clone
  1510. userCollection.replaceOne(userTest, userTestInactive).results()
  1511. val id = token.head.getString("accessToken")
  1512. // changing password operation with the new same password
  1513. val requestChange = FakeRequest(POST, s"/system/reset_password/$id?pass1=$newPass&pass2=$newPass")
  1514. .withHeaders(HOST -> "localhost:9000")
  1515. val resultChange: Future[Result] = route(app, requestChange).get
  1516. status(resultChange) mustEqual ACCEPTED
  1517. waitingOnApi()
  1518. // check if the token from this inactive user was deleted in the DB.
  1519. val tokenFound: Seq[Document] = tokenCollection.find(selector).results()
  1520. tokenFound.size mustEqual 0
  1521. // user's password should not have changed
  1522. val userFound: Seq[Document] = userCollection.find(selector).results()
  1523. userFound.size mustEqual 1
  1524. userFound.head.getString("username") mustEqual userTest.getString("username")
  1525. userTest.getString("password") mustEqual userFound.head.getString("password")
  1526. }
  1527. "return Accepted and change password to a known active username with a sha512 like password" in {
  1528. tokenCollection.drop().results()
  1529. val initialUser = ModelGenerator.generateDirector(Generator.passGen)
  1530. userCollection.insertOne(initialUser).results()
  1531. val requestReset = FakeRequest(GET,
  1532. s"/system/forgot_password?username=${initialUser.getString("username")}")
  1533. .withHeaders(HOST -> "localhost:9000")
  1534. val resultReset: Future[Result] = route(app, requestReset).get
  1535. status(resultReset) mustEqual ACCEPTED
  1536. waitingOnApi()
  1537. // Fetch the token id that was stored in the DB and use it to change the password
  1538. val selector = Document("username" -> initialUser.getString("username"))
  1539. val token: Seq[Document] = tokenCollection.find(selector).results()
  1540. token.size mustEqual 1
  1541. val id = token.head.getString("accessToken")
  1542. // changing password operation with the same password as before
  1543. val newPass: String = Generator.passGen
  1544. val requestChange = FakeRequest(POST, s"/system/reset_password/$id?pass1=$newPass&pass2=$newPass")
  1545. .withHeaders(HOST -> "localhost:9000")
  1546. val result: Future[Result] = route(app, requestChange).get
  1547. status(result) mustEqual ACCEPTED
  1548. waitingOnApi()
  1549. val finalUser: Seq[Document] = userCollection.find(selector).results()
  1550. tokenCollection.count().results().head mustEqual 0
  1551. finalUser.length mustEqual 1
  1552. initialUser != finalUser.head mustEqual true
  1553. }
  1554. }
  1555. }