diff --git a/.gitignore b/.gitignore index 4926a74..c84f480 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ src_managed/ project/boot/ project/plugins/project/ project/project/ +project/metals.sbt # Scala-IDE specific .scala_dependencies @@ -17,5 +18,5 @@ project/project/ .idea_modules .bsp .metals -.bloop/ -project/metals.sbt +.bloop +.vscode diff --git a/admin/app/Application.scala b/admin/app/Application.scala index b84ca05..94df120 100644 --- a/admin/app/Application.scala +++ b/admin/app/Application.scala @@ -27,6 +27,7 @@ class PiezoAdminComponents(context: Context) extends BuiltInComponentsFromContex lazy val schedulerFactory: WorkerSchedulerFactory = new WorkerSchedulerFactory() lazy val jobFormHelper: JobFormHelper = wire[JobFormHelper] + lazy val monitoringTeams: MonitoringTeams = MonitoringTeams(configuration) lazy val triggers: Triggers = wire[Triggers] lazy val jobs: Jobs = wire[Jobs] diff --git a/admin/app/com/lucidchart/piezo/admin/controllers/Jobs.scala b/admin/app/com/lucidchart/piezo/admin/controllers/Jobs.scala index d15b579..3ea4f98 100644 --- a/admin/app/com/lucidchart/piezo/admin/controllers/Jobs.scala +++ b/admin/app/com/lucidchart/piezo/admin/controllers/Jobs.scala @@ -14,6 +14,7 @@ import scala.jdk.CollectionConverters._ import scala.collection.mutable import scala.Some import scala.io.Source +import com.lucidchart.piezo.admin.models.MonitoringTeams trait ImportResult { val jobKey: Option[JobKey] @@ -35,14 +36,14 @@ trait ImportResult { case class ImportSuccess(val jobKey: Option[JobKey], val errorMessage: String = "", val success: Boolean=true) extends ImportResult case class ImportFailure(val jobKey: Option[JobKey], val errorMessage: String, val success: Boolean=false) extends ImportResult -class Jobs(schedulerFactory: WorkerSchedulerFactory, jobView: html.job, cc: ControllerComponents) extends AbstractController(cc) with Logging with ErrorLogging with play.api.i18n.I18nSupport { +class Jobs(schedulerFactory: WorkerSchedulerFactory, jobView: html.job, cc: ControllerComponents, monitoringTeams: MonitoringTeams) extends AbstractController(cc) with Logging with ErrorLogging with play.api.i18n.I18nSupport { val scheduler = logExceptions(schedulerFactory.getScheduler()) val properties = schedulerFactory.props val jobHistoryModel = logExceptions(new JobHistoryModel(properties)) val triggerMonitoringPriorityModel = logExceptions(new TriggerMonitoringModel(properties)) val jobFormHelper = new JobFormHelper() - val triggerFormHelper = new TriggerFormHelper(scheduler) + val triggerFormHelper = new TriggerFormHelper(scheduler, monitoringTeams) // Allow up to 1M private val maxFormSize = 1024 * 1024 @@ -235,7 +236,7 @@ class Jobs(schedulerFactory: WorkerSchedulerFactory, jobView: html.job, cc: Cont ImportFailure(Some(jobDetail.getKey), "Trigger Import Error:"+errorMessage) } else { val triggers = triggersBinding.flatMap(_.value) - triggers.foreach { case (trigger, monitoringPriority, errorTime, monitoringTeam) => + triggers.foreach { case TriggerFormValue(trigger, monitoringPriority, errorTime, monitoringTeam) => scheduler.scheduleJob(trigger) triggerMonitoringPriorityModel.setTriggerMonitoringRecord( trigger.getKey, diff --git a/admin/app/com/lucidchart/piezo/admin/controllers/TriggerFormHelper.scala b/admin/app/com/lucidchart/piezo/admin/controllers/TriggerFormHelper.scala index 0388e8a..6cdb8d1 100644 --- a/admin/app/com/lucidchart/piezo/admin/controllers/TriggerFormHelper.scala +++ b/admin/app/com/lucidchart/piezo/admin/controllers/TriggerFormHelper.scala @@ -2,6 +2,7 @@ package com.lucidchart.piezo.admin.controllers import com.lucidchart.piezo.TriggerMonitoringPriority import com.lucidchart.piezo.TriggerMonitoringPriority.TriggerMonitoringPriority +import com.lucidchart.piezo.admin.models.MonitoringTeams import com.lucidchart.piezo.admin.utils.CronHelper import java.text.ParseException import org.quartz._ @@ -11,7 +12,8 @@ import play.api.data.format.Formats.parsing import play.api.data.format.Formatter import play.api.data.validation.{Constraint, Constraints, Invalid, Valid, ValidationError} -class TriggerFormHelper(scheduler: Scheduler) extends JobDataHelper { +case class TriggerFormValue(trigger: Trigger, priority: TriggerMonitoringPriority, maxErrorTime: Int, monitoringTeam: Option[String]) +class TriggerFormHelper(scheduler: Scheduler, monitoringTeams: MonitoringTeams) extends JobDataHelper { private def simpleScheduleFormApply(repeatCount: Int, repeatInterval: Int): SimpleScheduleBuilder = { SimpleScheduleBuilder @@ -47,7 +49,7 @@ class TriggerFormHelper(scheduler: Scheduler) extends JobDataHelper { triggerMonitoringPriority: String, triggerMaxErrorTime: Int, triggerMonitoringTeam: Option[String], - ): (Trigger, TriggerMonitoringPriority, Int, Option[String]) = { + ): TriggerFormValue = { val newTrigger: Trigger = TriggerBuilder .newTrigger() .withIdentity(name, group) @@ -59,7 +61,7 @@ class TriggerFormHelper(scheduler: Scheduler) extends JobDataHelper { .forJob(jobName, jobGroup) .usingJobData(jobDataMap.getOrElse(new JobDataMap())) .build() - ( + TriggerFormValue( newTrigger, TriggerMonitoringPriority.withName(triggerMonitoringPriority), triggerMaxErrorTime, @@ -67,7 +69,7 @@ class TriggerFormHelper(scheduler: Scheduler) extends JobDataHelper { ) } - private def triggerFormUnapply(tp: (Trigger, TriggerMonitoringPriority, Int, Option[String])): Option[ + private def triggerFormUnapply(value: TriggerFormValue): Option[ ( String, String, @@ -83,7 +85,7 @@ class TriggerFormHelper(scheduler: Scheduler) extends JobDataHelper { Option[String], ), ] = { - val trigger = tp._1 + val trigger = value.trigger val (triggerType: String, simple, cron) = trigger match { case cron: CronTrigger => ("cron", None, Some(cron.getScheduleBuilder)) case simple: SimpleTrigger => ("simple", Some(simple.getScheduleBuilder), None) @@ -100,9 +102,9 @@ class TriggerFormHelper(scheduler: Scheduler) extends JobDataHelper { simple.asInstanceOf[Option[SimpleScheduleBuilder]], cron.asInstanceOf[Option[CronScheduleBuilder]], Some(trigger.getJobDataMap), - tp._2.toString, - tp._3, - tp._4, + value.priority.toString, + value.maxErrorTime, + value.monitoringTeam, ), ) } @@ -132,7 +134,7 @@ class TriggerFormHelper(scheduler: Scheduler) extends JobDataHelper { } } - def buildTriggerForm: Form[(Trigger, TriggerMonitoringPriority, Int, Option[String])] = Form( + def buildTriggerForm: Form[TriggerFormValue] = Form( mapping( "triggerType" -> nonEmptyText(), "group" -> nonEmptyText(), @@ -159,8 +161,14 @@ class TriggerFormHelper(scheduler: Scheduler) extends JobDataHelper { .verifying( "Job does not exist", fields => { - scheduler.checkExists(fields._1.getJobKey) + scheduler.checkExists(fields.trigger.getJobKey) }, + ) + .verifying( + "A valid team is required if monitoring is on", + fields => { + !monitoringTeams.teamsDefined || fields.priority == TriggerMonitoringPriority.Off || fields.monitoringTeam.exists(monitoringTeams.value.contains[String]) + } ), ) } diff --git a/admin/app/com/lucidchart/piezo/admin/controllers/Triggers.scala b/admin/app/com/lucidchart/piezo/admin/controllers/Triggers.scala index d8b4f5c..8ef213d 100644 --- a/admin/app/com/lucidchart/piezo/admin/controllers/Triggers.scala +++ b/admin/app/com/lucidchart/piezo/admin/controllers/Triggers.scala @@ -15,13 +15,14 @@ import scala.util.Try import play.api.Logging import play.api.i18n.I18nSupport -class Triggers(schedulerFactory: WorkerSchedulerFactory, cc: ControllerComponents) extends AbstractController(cc) with Logging with ErrorLogging with play.api.i18n.I18nSupport { +class Triggers(schedulerFactory: WorkerSchedulerFactory, cc: ControllerComponents, monitoringTeams: MonitoringTeams) + extends AbstractController(cc) with Logging with ErrorLogging with play.api.i18n.I18nSupport { val scheduler = logExceptions(schedulerFactory.getScheduler()) val properties = schedulerFactory.props val triggerHistoryModel = logExceptions(new TriggerHistoryModel(properties)) val triggerMonitoringPriorityModel = logExceptions(new TriggerMonitoringModel(properties)) - val triggerFormHelper = new TriggerFormHelper(scheduler) + val triggerFormHelper = new TriggerFormHelper(scheduler, monitoringTeams) def firesFirst(time: Date)(trigger1: Trigger, trigger2: Trigger): Boolean = { val time1 = trigger1.getFireTimeAfter(time) @@ -160,17 +161,17 @@ class Triggers(schedulerFactory: WorkerSchedulerFactory, cc: ControllerComponent case "simple" => new DummySimpleTrigger(jobGroup, jobName) } val newTriggerForm = triggerFormHelper.buildTriggerForm.fill( - (dummyTrigger, TriggerMonitoringPriority.Low, 300, None) + TriggerFormValue(dummyTrigger, TriggerMonitoringPriority.Low, 300, None) ) Ok( com.lucidchart.piezo.admin.views.html.editTrigger( TriggerHelper.getTriggersByGroup(scheduler), + monitoringTeams.value, newTriggerForm, formNewAction, false, false ) - (request, implicitly) ) } } @@ -194,28 +195,30 @@ class Triggers(schedulerFactory: WorkerSchedulerFactory, cc: ControllerComponent (TriggerMonitoringPriority.Low, 300, None) } val editTriggerForm = triggerFormHelper.buildTriggerForm.fill( - (triggerDetail, triggerMonitoringPriority, triggerMaxErrorTime, triggerMonitoringTeam) + TriggerFormValue(triggerDetail, triggerMonitoringPriority, triggerMaxErrorTime, triggerMonitoringTeam) ) if (isTemplate) { Ok( com.lucidchart.piezo.admin.views.html.editTrigger( TriggerHelper.getTriggersByGroup(scheduler), + monitoringTeams.value, editTriggerForm, formNewAction, false, isTemplate - )(request, implicitly) + ) ) } else { Ok( com.lucidchart.piezo.admin.views.html.editTrigger( TriggerHelper.getTriggersByGroup(scheduler), + monitoringTeams.value, editTriggerForm, formEditAction(group, name), true, isTemplate - )(request, implicitly) + ) ) } } @@ -231,6 +234,7 @@ class Triggers(schedulerFactory: WorkerSchedulerFactory, cc: ControllerComponent BadRequest( com.lucidchart.piezo.admin.views.html.editTrigger( TriggerHelper.getTriggersByGroup(scheduler), + monitoringTeams.value, formWithErrors, formEditAction(group, name), true, @@ -238,7 +242,7 @@ class Triggers(schedulerFactory: WorkerSchedulerFactory, cc: ControllerComponent ) ), value => { - val (trigger, triggerMonitoringPriority, triggerMaxErrorTime, triggerMonitoringTeam) = value + val TriggerFormValue(trigger, triggerMonitoringPriority, triggerMaxErrorTime, triggerMonitoringTeam) = value scheduler.rescheduleJob(trigger.getKey(), trigger) triggerMonitoringPriorityModel.setTriggerMonitoringRecord( trigger.getKey, @@ -258,6 +262,7 @@ class Triggers(schedulerFactory: WorkerSchedulerFactory, cc: ControllerComponent BadRequest( com.lucidchart.piezo.admin.views.html.editTrigger( TriggerHelper.getTriggersByGroup(scheduler), + monitoringTeams.value, formWithErrors, formNewAction, false, @@ -265,7 +270,7 @@ class Triggers(schedulerFactory: WorkerSchedulerFactory, cc: ControllerComponent ) ), value => { - val (trigger, triggerMonitoringPriority, triggerMaxErrorTime, triggerMonitoringTeam) = value + val TriggerFormValue(trigger, triggerMonitoringPriority, triggerMaxErrorTime, triggerMonitoringTeam) = value try { scheduler.scheduleJob(trigger) triggerMonitoringPriorityModel.setTriggerMonitoringRecord( @@ -279,17 +284,18 @@ class Triggers(schedulerFactory: WorkerSchedulerFactory, cc: ControllerComponent } catch { case alreadyExists: ObjectAlreadyExistsException => val form = triggerFormHelper.buildTriggerForm.fill( - (trigger, triggerMonitoringPriority, triggerMaxErrorTime, triggerMonitoringTeam) + TriggerFormValue(trigger, triggerMonitoringPriority, triggerMaxErrorTime, triggerMonitoringTeam) ) Ok( com.lucidchart.piezo.admin.views.html.editTrigger( TriggerHelper.getTriggersByGroup(scheduler), + monitoringTeams.value, form, formNewAction, false, false, errorMessage = Some("Please provide unique group-name pair") - )(request, implicitly) + ) ) } } diff --git a/admin/app/com/lucidchart/piezo/admin/models/MonitoringTeams.scala b/admin/app/com/lucidchart/piezo/admin/models/MonitoringTeams.scala new file mode 100644 index 0000000..4cbe6fc --- /dev/null +++ b/admin/app/com/lucidchart/piezo/admin/models/MonitoringTeams.scala @@ -0,0 +1,39 @@ +package com.lucidchart.piezo.admin.models + +import play.api.Configuration +import java.nio.file.Files +import play.api.libs.json.Json +import scala.util.Try +import java.io.File +import java.io.FileInputStream +import play.api.libs.json.JsArray +import play.api.Logging +import scala.util.control.NonFatal +import scala.util.Failure + +case class MonitoringTeams(value: Seq[String]) { + def teamsDefined: Boolean = value.nonEmpty +} +object MonitoringTeams extends Logging { + def apply(configuration: Configuration): MonitoringTeams = { + val path = configuration.getOptional[String]("com.lucidchart.piezo.admin.monitoringTeams.path") + + val value = path.flatMap { p => + Try { + Json.parse(new FileInputStream(p)) + .as[JsArray] + .value + .map(entry => (entry \ "name").as[String]) + .toSeq + }.recoverWith { + case NonFatal(e) => + logger.error(s"Error reading monitoring teams from $p", e) + Failure(e) + }.toOption + }.getOrElse(Seq.empty) + + MonitoringTeams(value) + } + + def empty: MonitoringTeams = MonitoringTeams(Seq.empty) +} diff --git a/admin/app/com/lucidchart/piezo/admin/views/editTrigger.scala.html b/admin/app/com/lucidchart/piezo/admin/views/editTrigger.scala.html index be423e8..8efc8d0 100644 --- a/admin/app/com/lucidchart/piezo/admin/views/editTrigger.scala.html +++ b/admin/app/com/lucidchart/piezo/admin/views/editTrigger.scala.html @@ -1,15 +1,16 @@ @( triggersByGroup: scala.collection.mutable.Buffer[(String, scala.collection.immutable.List[org.quartz.TriggerKey])], -triggerForm: Form[(org.quartz.Trigger, com.lucidchart.piezo.TriggerMonitoringPriority.Value, Int, Option[String])], +monitoringTeams: Seq[String], +triggerForm: Form[com.lucidchart.piezo.admin.controllers.TriggerFormValue], formAction: play.api.mvc.Call, existing: Boolean, isTemplate: Boolean, errorMessage: Option[String] = None, -scripts: List[String] = List[String]("js/jobData.js", "js/typeAhead.js") +scripts: List[String] = List[String]("js/jobData.js", "js/typeAhead.js", "js/triggerMonitoring.js") )( implicit request: play.api.mvc.Request[AnyContent], -messagesProvider: play.api.i18n.MessagesProvider +messagesProvider: play.api.i18n.MessagesProvider, ) @import com.lucidchart.piezo.TriggerMonitoringPriority @@ -67,12 +68,18 @@

@triggerForm.errors.filter(_.key == "").map(_.message).m } } @helper.select(triggerForm("triggerMonitoringPriority"), TriggerMonitoringPriority.values.map(tp => tp.name -> tp.name), Symbol("_label") -> "Monitoring Priority", Symbol("labelClass") -> "col-sm-2 text-right", Symbol("inputDivClass") -> "col-sm-4", Symbol("class") -> "form-control", Symbol("value") -> triggerForm.data.get("triggerMonitoringPriority").getOrElse(TriggerMonitoringPriority.Low), Symbol("placeholder") -> TriggerMonitoringPriority.Low) - @helper.input(triggerForm("triggerMaxErrorTime"), Symbol("_label") -> "Monitoring - Max Seconds Between Successes", Symbol("labelClass") -> "col-sm-2 text-right", Symbol("inputDivClass") -> "col-sm-4", Symbol("placeholder") -> "", Symbol("value") -> triggerForm.data.get("triggerMaxErrorTime").getOrElse(300)) { (id, name, value, args) => - - } - @helper.input(triggerForm("triggerMonitoringTeam"), Symbol("_label") -> "Monitoring team", Symbol("labelClass") -> "col-sm-2 text-right", Symbol("inputDivClass") -> "col-sm-4", Symbol("placeholder") -> "", Symbol("value") -> triggerForm.data.get("triggerMonitoringTeam").getOrElse(None)) { (id, name, value, args) => - - } +
+ @helper.input(triggerForm("triggerMaxErrorTime"), Symbol("_label") -> "Monitoring - Max Seconds Between Successes", Symbol("labelClass") -> "col-sm-2 text-right", Symbol("inputDivClass") -> "col-sm-4", Symbol("placeholder") -> "", Symbol("value") -> triggerForm.data.get("triggerMaxErrorTime").getOrElse(300)) { (id, name, value, args) => + + } + @if(monitoringTeams.nonEmpty) { + @helper.select(triggerForm("triggerMonitoringTeam"), monitoringTeams.map(mt => mt -> mt), Symbol("_default") -> "Select team", Symbol("_label") -> "Monitoring team", Symbol("labelClass") -> "col-sm-2 text-right", Symbol("inputDivClass") -> "col-sm-4", Symbol("class") -> "form-control", Symbol("value") -> triggerForm.data.get("triggerMonitoringTeam").getOrElse("")) + } else { + @helper.input(triggerForm("triggerMonitoringTeam"), Symbol("_label") -> "Monitoring team", Symbol("labelClass") -> "col-sm-2 text-right", Symbol("inputDivClass") -> "col-sm-4", Symbol("placeholder") -> "", Symbol("value") -> triggerForm.data.get("triggerMonitoringTeam").getOrElse(None)) { (id, name, value, args) => + + } + } +
@helper.input(triggerForm("description"), Symbol("_label") -> "Description", Symbol("labelClass") -> "col-sm-2 text-right", Symbol("inputDivClass") -> "col-sm-10", Symbol("placeholder") -> "Description", Symbol("value")-> triggerForm.data.get("description").getOrElse("")) { (id, name, value, args) => diff --git a/admin/conf/application.conf b/admin/conf/application.conf index 962802b..7907dbd 100644 --- a/admin/conf/application.conf +++ b/admin/conf/application.conf @@ -46,3 +46,14 @@ com.lucidchart.piezo.heartbeatFile="/tmp/piezo/workerHeartbeatFile" com.lucidchart.piezo.admin.production=false healthCheck.worker.minutesBetween=5 play.application.loader=com.lucidchart.piezo.admin.PiezoAdminApplicationLoader + +# Monitoring teams +# ~~~~~ +# Path to a JSON file that fills the "Monitoring Team" dropdown on editTrigger +# in the admin UI with a predefined set of team names. File format: +# [ +# {"name": "team1"}, +# {"name": "team2"} +# ] +# If this is left blank, monitoring team will be a freeform input. +# com.lucidchart.piezo.admin.monitoringTeams.path = "/etc/piezo/teams.json" diff --git a/admin/public/js/triggerMonitoring.js b/admin/public/js/triggerMonitoring.js new file mode 100644 index 0000000..ed4b648 --- /dev/null +++ b/admin/public/js/triggerMonitoring.js @@ -0,0 +1,15 @@ +window.addEventListener('load', () => { + const priorityInput = document.getElementById('triggerMonitoringPriority'); + const setMonitoringFieldVisibility = () => { + const priority = priorityInput.value; + const monitoringDetails = document.getElementById('triggerMonitoringDetails'); + if (priority == 'Off') { + monitoringDetails.style.display = 'none'; // hide + } else { + monitoringDetails.style.display = 'block'; // show + } + }; + + priorityInput.addEventListener('change', setMonitoringFieldVisibility); + setMonitoringFieldVisibility(); +}, {once: true}); diff --git a/admin/test/com/lucidchart/piezo/admin/controllers/JobsService.scala b/admin/test/com/lucidchart/piezo/admin/controllers/JobsService.scala index e283d33..2dfbc9d 100644 --- a/admin/test/com/lucidchart/piezo/admin/controllers/JobsService.scala +++ b/admin/test/com/lucidchart/piezo/admin/controllers/JobsService.scala @@ -1,7 +1,6 @@ package com.lucidchart.piezo.admin.controllers import org.specs2.mutable._ - import play.api.test._ import play.api.test.Helpers._ import com.lucidchart.piezo.jobs.monitoring.HeartBeat @@ -14,8 +13,8 @@ import com.lucidchart.piezo.util.DummyClassGenerator import play.api.mvc.{Result, AnyContentAsEmpty} import java.util.Properties import play.api.Configuration - import scala.concurrent.Future +import com.lucidchart.piezo.admin.models.MonitoringTeams /** * Add your spec here. @@ -39,7 +38,7 @@ class JobsService extends Specification { properties.load(propertiesStream) schedulerFactory.initialize(properties) - val jobsController = new Jobs(schedulerFactory, jobView, Helpers.stubControllerComponents()) + val jobsController = new Jobs(schedulerFactory, jobView, Helpers.stubControllerComponents(), MonitoringTeams.empty) val request: FakeRequest[AnyContentAsEmpty.type] = FakeRequest(GET, "/jobs/missinggroup/missingname") val missingJob: Future[Result] = jobsController.getJob("missinggroup", "missingname")(request) @@ -57,8 +56,7 @@ class JobsService extends Specification { val scheduler = schedulerFactory.getScheduler() createJob(scheduler) - - val jobsController = new Jobs(schedulerFactory, jobView, Helpers.stubControllerComponents()) + val jobsController = new Jobs(schedulerFactory, jobView, Helpers.stubControllerComponents(), MonitoringTeams.empty) val request: FakeRequest[AnyContentAsEmpty.type] = FakeRequest(GET, "/jobs/" + jobGroup + "/" + jobName) val validJob: Future[Result] = jobsController.getJob(jobGroup, jobName)(request) diff --git a/admin/test/com/lucidchart/piezo/admin/controllers/TriggersService.scala b/admin/test/com/lucidchart/piezo/admin/controllers/TriggersService.scala index 0c42bb7..4c3030d 100644 --- a/admin/test/com/lucidchart/piezo/admin/controllers/TriggersService.scala +++ b/admin/test/com/lucidchart/piezo/admin/controllers/TriggersService.scala @@ -1,7 +1,6 @@ package com.lucidchart.piezo.admin.controllers import org.specs2.mutable._ - import play.api.test._ import play.api.test.Helpers._ import com.lucidchart.piezo.WorkerSchedulerFactory @@ -9,49 +8,49 @@ import TestUtil._ import java.util.Properties import play.api.mvc.{AnyContentAsEmpty, Result} import scala.concurrent.Future +import com.lucidchart.piezo.admin.models.MonitoringTeams /** - * Add your spec here. - * You can mock out a whole application including requests, plugins etc. - * For more information, consult the wiki. - */ + * Add your spec here. You can mock out a whole application including requests, plugins etc. For more information, + * consult the wiki. + */ class TriggersService extends Specification { - "Triggers" should { - - "send 404 on a non-existent trigger request" in { - val schedulerFactory: WorkerSchedulerFactory = new WorkerSchedulerFactory() - - val propertiesStream = getClass().getResourceAsStream("/quartz_test.properties") - val properties = new Properties - properties.load(propertiesStream) - schedulerFactory.initialize(properties) - - val triggersController = new Triggers(schedulerFactory, Helpers.stubControllerComponents()) - val request: FakeRequest[AnyContentAsEmpty.type] = FakeRequest(GET, "/triggers/missinggroup/missingname") - val missingTrigger: Future[Result] = triggersController.getTrigger("missinggroup", "missingname")(request) - - status(missingTrigger) must equalTo(NOT_FOUND) - contentType(missingTrigger) must beSome.which(_ == "text/html") - contentAsString(missingTrigger) must contain ("Trigger missinggroup missingname not found") - } - - "send valid trigger details" in { - val schedulerFactory: WorkerSchedulerFactory = new WorkerSchedulerFactory() - val propertiesStream = getClass().getResourceAsStream("/quartz_test.properties") - val properties = new Properties - properties.load(propertiesStream) - schedulerFactory.initialize(properties) - val scheduler = schedulerFactory.getScheduler() - createJob(scheduler) - - val triggersController = new Triggers(schedulerFactory, Helpers.stubControllerComponents()) - val request: FakeRequest[AnyContentAsEmpty.type] = FakeRequest(GET, "/triggers/" + jobGroup + "/" + jobName) - val validTrigger: Future[Result] = triggersController.getTrigger(triggerGroup, triggerName)(request) - - status(validTrigger) must equalTo(OK) - contentType(validTrigger) must beSome.which(_ == "text/html") - contentAsString(validTrigger) must contain (triggerGroup) - contentAsString(validTrigger) must contain (triggerName) - } - } - } + "Triggers" should { + + "send 404 on a non-existent trigger request" in { + val schedulerFactory: WorkerSchedulerFactory = new WorkerSchedulerFactory() + + val propertiesStream = getClass().getResourceAsStream("/quartz_test.properties") + val properties = new Properties + properties.load(propertiesStream) + schedulerFactory.initialize(properties) + + val triggersController = new Triggers(schedulerFactory, Helpers.stubControllerComponents(), MonitoringTeams.empty) + val request: FakeRequest[AnyContentAsEmpty.type] = FakeRequest(GET, "/triggers/missinggroup/missingname") + val missingTrigger: Future[Result] = triggersController.getTrigger("missinggroup", "missingname")(request) + + status(missingTrigger) must equalTo(NOT_FOUND) + contentType(missingTrigger) must beSome.which(_ == "text/html") + contentAsString(missingTrigger) must contain("Trigger missinggroup missingname not found") + } + + "send valid trigger details" in { + val schedulerFactory: WorkerSchedulerFactory = new WorkerSchedulerFactory() + val propertiesStream = getClass().getResourceAsStream("/quartz_test.properties") + val properties = new Properties + properties.load(propertiesStream) + schedulerFactory.initialize(properties) + val scheduler = schedulerFactory.getScheduler() + createJob(scheduler) + + val triggersController = new Triggers(schedulerFactory, Helpers.stubControllerComponents(), MonitoringTeams.empty) + val request: FakeRequest[AnyContentAsEmpty.type] = FakeRequest(GET, "/triggers/" + jobGroup + "/" + jobName) + val validTrigger: Future[Result] = triggersController.getTrigger(triggerGroup, triggerName)(request) + + status(validTrigger) must equalTo(OK) + contentType(validTrigger) must beSome.which(_ == "text/html") + contentAsString(validTrigger) must contain(triggerGroup) + contentAsString(validTrigger) must contain(triggerName) + } + } +}