Polish Quartz endpoint documentation

See gh-10364
pull/25943/head
Andy Wilkinson 4 years ago
parent a07c8e6e18
commit ef986b13e5

@ -157,7 +157,12 @@ include::{snippets}/quartz/trigger-details-cron/curl-request.adoc[]
The preceding example retrieves the details of trigger identified by the `samples` group and `example` name.
The resulting response has a common structure and a specific additional object according to the trigger implementation.
[[quartz-trigger-common-response-structure]]
=== Common Response Structure
The response has a common structure and an additional object that is specific to the trigger's type.
There are five supported types:
* `cron` for `CronTrigger`
@ -166,9 +171,14 @@ There are five supported types:
* `calendarInterval` for `CalendarIntervalTrigger`
* `custom` for any other trigger implementations
The following table describes the structure of the common elements of the response:
[cols="2,1,3"]
include::{snippets}/quartz/trigger-details-common/response-fields.adoc[]
[[quartz-trigger-cron]]
[[quartz-trigger-cron-response-structure]]
=== Cron Trigger Response Structure
A cron trigger defines the cron expression that is used to determine when it has to fire.
@ -177,14 +187,16 @@ The resulting response for such a trigger implementation is similar to the follo
include::{snippets}/quartz/trigger-details-cron/http-response.adoc[]
The following table describes the structure of the response:
Much of the response is common to all trigger types.
The structure of the common elements of the response was <<quartz-trigger-common-response-structure,described previously>>.
The following table describes the structure of the parts of the response that are specific to cron triggers:
[cols="2,1,3"]
include::{snippets}/quartz/trigger-details-cron/response-fields.adoc[]
[[quartz-trigger-simple]]
[[quartz-trigger-simple-response-structure]]
=== Simple Trigger Response Structure
A simple trigger is used to fire a Job at a given moment in time, and optionally repeated at a specified interval.
@ -193,14 +205,16 @@ The resulting response for such a trigger implementation is similar to the follo
include::{snippets}/quartz/trigger-details-simple/http-response.adoc[]
The following table describes the structure of the response:
Much of the response is common to all trigger types.
The structure of the common elements of the response was <<quartz-trigger-common-response-structure,described previously>>.
The following table describes the structure of the parts of the response that are specific to simple triggers:
[cols="2,1,3"]
include::{snippets}/quartz/trigger-details-simple/response-fields.adoc[]
[[quartz-trigger-daily-time-interval]]
[[quartz-trigger-daily-time-interval-response-structure]]
=== Daily Time Interval Trigger Response Structure
A daily time interval trigger is used to fire a Job based upon daily repeating time intervals.
@ -209,30 +223,34 @@ The resulting response for such a trigger implementation is similar to the follo
include::{snippets}/quartz/trigger-details-daily-time-interval/http-response.adoc[]
The following table describes the structure of the response:
Much of the response is common to all trigger types.
The structure of the common elements of the response was <<quartz-trigger-common-response-structure,described previously>>.
The following table describes the structure of the parts of the response that are specific to daily time interval triggers:
[cols="2,1,3"]
include::{snippets}/quartz/trigger-details-daily-time-interval/response-fields.adoc[]
[[quartz-trigger-calendar-interval]]
[[quartz-trigger-calendar-interval-response-structure]]
=== Calendar Interval Trigger Response Structure
A daily time interval trigger is used to fire a Job based upon repeating calendar time intervals.
A calendar interval trigger is used to fire a Job based upon repeating calendar time intervals.
The resulting response for such a trigger implementation is similar to the following:
include::{snippets}/quartz/trigger-details-calendar-interval/http-response.adoc[]
The following table describes the structure of the response:
Much of the response is common to all trigger types.
The structure of the common elements of the response was <<quartz-trigger-common-response-structure,described previously>>.
The following table describes the structure of the parts of the response that are specific to calendar interval triggers:
[cols="2,1,3"]
include::{snippets}/quartz/trigger-details-calendar-interval/response-fields.adoc[]
[[quartz-trigger-custom]]
[[quartz-trigger-custom-response-structure]]
=== Custom Trigger Response Structure
A custom trigger is any other implementation.
@ -241,7 +259,9 @@ The resulting response for such a trigger implementation is similar to the follo
include::{snippets}/quartz/trigger-details-custom/http-response.adoc[]
The following table describes the structure of the response:
Much of the response is common to all trigger types.
The structure of the common elements of the response was <<quartz-trigger-common-response-structure,described previously>>.
The following table describes the structure of the parts of the response that are specific to custom triggers:
[cols="2,1,3"]
include::{snippets}/quartz/trigger-details-custom/response-fields.adoc[]

@ -59,7 +59,7 @@ import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWit
"management.endpoints.web.exposure.include=*", "spring.jackson.default-property-inclusion=non_null" })
public abstract class AbstractEndpointDocumentationTests {
protected String describeEnumValues(Class<? extends Enum<?>> enumType) {
protected static String describeEnumValues(Class<? extends Enum<?>> enumType) {
return StringUtils.collectionToDelimitedString(Stream.of(enumType.getEnumConstants())
.map((constant) -> "`" + constant.name() + "`").collect(Collectors.toList()), ", ");
}

@ -67,7 +67,9 @@ import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
import static org.springframework.restdocs.payload.PayloadDocumentation.relaxedResponseFields;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
import static org.springframework.restdocs.payload.PayloadDocumentation.subsectionWithPath;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@ -88,24 +90,24 @@ class QuartzEndpointDocumentationTests extends MockMvcEndpointDocumentationTests
private static final JobDetail jobThree = JobBuilder.newJob(Job.class).withIdentity("jobThree", "tests").build();
private static final CronTrigger triggerOne = TriggerBuilder.newTrigger().forJob(jobOne).withPriority(3)
private static final CronTrigger cronTrigger = TriggerBuilder.newTrigger().forJob(jobOne).withPriority(3)
.withDescription("3AM on weekdays").withIdentity("3am-weekdays", "samples")
.withSchedule(
CronScheduleBuilder.atHourAndMinuteOnGivenDaysOfWeek(3, 0, 1, 2, 3, 4, 5).inTimeZone(timeZone))
.build();
private static final SimpleTrigger triggerTwo = TriggerBuilder.newTrigger().forJob(jobOne).withPriority(7)
private static final SimpleTrigger simpleTrigger = TriggerBuilder.newTrigger().forJob(jobOne).withPriority(7)
.withDescription("Once a day").withIdentity("every-day", "samples")
.withSchedule(SimpleScheduleBuilder.repeatHourlyForever(24)).build();
private static final CalendarIntervalTrigger triggerThree = TriggerBuilder.newTrigger().forJob(jobTwo)
private static final CalendarIntervalTrigger calendarIntervalTrigger = TriggerBuilder.newTrigger().forJob(jobTwo)
.withDescription("Once a week").withIdentity("once-a-week", "samples")
.withSchedule(CalendarIntervalScheduleBuilder.calendarIntervalSchedule().withIntervalInWeeks(1)
.inTimeZone(timeZone))
.build();
private static final DailyTimeIntervalTrigger triggerFour = TriggerBuilder.newTrigger().forJob(jobThree)
.withDescription("Every hour between 9AM and 6PM on Tuesday and Thursday")
private static final DailyTimeIntervalTrigger dailyTimeIntervalTrigger = TriggerBuilder.newTrigger()
.forJob(jobThree).withDescription("Every hour between 9AM and 6PM on Tuesday and Thursday")
.withIdentity("every-hour-tue-thu")
.withSchedule(DailyTimeIntervalScheduleBuilder.dailyTimeIntervalSchedule()
.onDaysOfTheWeek(Calendar.TUESDAY, Calendar.THURSDAY)
@ -148,9 +150,10 @@ class QuartzEndpointDocumentationTests extends MockMvcEndpointDocumentationTests
fieldWithPath("name").description("Name of the trigger."),
fieldWithPath("description").description("Description of the trigger, if any."),
fieldWithPath("state")
.description("State of the trigger, can be NONE, NORMAL, PAUSED, COMPLETE, ERROR, or BLOCKED."),
.description("State of the trigger (" + describeEnumValues(TriggerState.class) + ")."),
fieldWithPath("type").description(
"Type of the trigger, determine the key of the object containing implementation-specific details."),
"Type of the trigger (`calendarInterval`, `cron`, `custom`, `dailyTimeInterval`, `simple`). "
+ "Determines the key of the object containing type-specific details."),
fieldWithPath("calendarName").description("Name of the Calendar associated with this Trigger, if any."),
startTime(""), endTime(""), previousFireTime(""), nextFireTime(""), priority(""),
fieldWithPath("finalFireTime").optional().type(JsonFieldType.STRING)
@ -164,7 +167,7 @@ class QuartzEndpointDocumentationTests extends MockMvcEndpointDocumentationTests
@Test
void quartzReport() throws Exception {
mockJobs(jobOne, jobTwo, jobThree);
mockTriggers(triggerOne, triggerTwo, triggerThree, triggerFour);
mockTriggers(cronTrigger, simpleTrigger, calendarIntervalTrigger, dailyTimeIntervalTrigger);
this.mockMvc.perform(get("/actuator/quartz")).andExpect(status().isOk())
.andDo(document("quartz/report",
responseFields(fieldWithPath("jobs.groups").description("An array of job group names."),
@ -181,7 +184,7 @@ class QuartzEndpointDocumentationTests extends MockMvcEndpointDocumentationTests
@Test
void quartzTriggers() throws Exception {
mockTriggers(triggerOne, triggerTwo, triggerThree, triggerFour);
mockTriggers(cronTrigger, simpleTrigger, calendarIntervalTrigger, dailyTimeIntervalTrigger);
this.mockMvc.perform(get("/actuator/quartz/triggers")).andExpect(status().isOk())
.andDo(document("quartz/triggers",
responseFields(fieldWithPath("groups").description("Trigger groups keyed by name."),
@ -202,16 +205,17 @@ class QuartzEndpointDocumentationTests extends MockMvcEndpointDocumentationTests
@Test
void quartzTriggerGroup() throws Exception {
CronTrigger cron = triggerOne.getTriggerBuilder().startAt(fromUtc("2020-11-30T17:00:00Z"))
CronTrigger cron = cronTrigger.getTriggerBuilder().startAt(fromUtc("2020-11-30T17:00:00Z"))
.endAt(fromUtc("2020-12-30T03:00:00Z")).withIdentity("3am-week", "tests").build();
setPreviousNextFireTime(cron, "2020-12-04T03:00:00Z", "2020-12-07T03:00:00Z");
SimpleTrigger simple = triggerTwo.getTriggerBuilder().withIdentity("every-day", "tests").build();
SimpleTrigger simple = simpleTrigger.getTriggerBuilder().withIdentity("every-day", "tests").build();
setPreviousNextFireTime(simple, null, "2020-12-04T12:00:00Z");
CalendarIntervalTrigger calendarInterval = triggerThree.getTriggerBuilder().withIdentity("once-a-week", "tests")
.startAt(fromUtc("2019-07-10T14:00:00Z")).endAt(fromUtc("2023-01-01T12:00:00Z")).build();
CalendarIntervalTrigger calendarInterval = calendarIntervalTrigger.getTriggerBuilder()
.withIdentity("once-a-week", "tests").startAt(fromUtc("2019-07-10T14:00:00Z"))
.endAt(fromUtc("2023-01-01T12:00:00Z")).build();
setPreviousNextFireTime(calendarInterval, "2020-12-02T14:00:00Z", "2020-12-08T14:00:00Z");
DailyTimeIntervalTrigger tueThuTrigger = triggerFour.getTriggerBuilder().withIdentity("tue-thu", "tests")
.build();
DailyTimeIntervalTrigger tueThuTrigger = dailyTimeIntervalTrigger.getTriggerBuilder()
.withIdentity("tue-thu", "tests").build();
Trigger customTrigger = mock(Trigger.class);
given(customTrigger.getKey()).willReturn(TriggerKey.triggerKey("once-a-year-custom", "tests"));
given(customTrigger.toString()).willReturn("com.example.CustomTrigger@fdsfsd");
@ -242,9 +246,9 @@ class QuartzEndpointDocumentationTests extends MockMvcEndpointDocumentationTests
@Test
void quartzJob() throws Exception {
mockJobs(jobOne);
CronTrigger firstTrigger = triggerOne.getTriggerBuilder().build();
CronTrigger firstTrigger = cronTrigger.getTriggerBuilder().build();
setPreviousNextFireTime(firstTrigger, null, "2020-12-07T03:00:00Z");
SimpleTrigger secondTrigger = triggerTwo.getTriggerBuilder().build();
SimpleTrigger secondTrigger = simpleTrigger.getTriggerBuilder().build();
setPreviousNextFireTime(secondTrigger, "2020-12-04T03:00:00Z", "2020-12-04T12:00:00Z");
mockTriggers(firstTrigger, secondTrigger);
given(this.scheduler.getTriggersOfJob(jobOne.getKey()))
@ -266,53 +270,71 @@ class QuartzEndpointDocumentationTests extends MockMvcEndpointDocumentationTests
previousFireTime("triggers.[]."), nextFireTime("triggers.[]."), priority("triggers.[]."))));
}
@Test
void quartzTriggerCommon() throws Exception {
setupTriggerDetails(cronTrigger.getTriggerBuilder(), TriggerState.NORMAL);
this.mockMvc.perform(get("/actuator/quartz/triggers/samples/example")).andExpect(status().isOk())
.andDo(document("quartz/trigger-details-common", responseFields(commonCronDetails).and(
subsectionWithPath("calendarInterval").description(
"Calendar time interval trigger details, if any. Present when `type` is `calendarInterval`.")
.optional().type(JsonFieldType.OBJECT),
subsectionWithPath("custom")
.description("Custom trigger details, if any. Present when `type` is `custom`.")
.optional().type(JsonFieldType.OBJECT),
subsectionWithPath("cron")
.description("Cron trigger details, if any. Present when `type` is `cron`.").optional()
.type(JsonFieldType.OBJECT),
subsectionWithPath("dailyTimeInterval").description(
"Daily time interval trigger details, if any. Present when `type` is `dailyTimeInterval`.")
.optional().type(JsonFieldType.OBJECT),
subsectionWithPath("simple")
.description("Simple trigger details, if any. Present when `type` is `simple`.")
.optional().type(JsonFieldType.OBJECT))));
}
@Test
void quartzTriggerCron() throws Exception {
setupTriggerDetails(triggerOne.getTriggerBuilder(), TriggerState.NORMAL);
setupTriggerDetails(cronTrigger.getTriggerBuilder(), TriggerState.NORMAL);
this.mockMvc.perform(get("/actuator/quartz/triggers/samples/example")).andExpect(status().isOk())
.andDo(document("quartz/trigger-details-cron",
responseFields(commonCronDetails)
.and(fieldWithPath("cron").description("Cron trigger specific details."))
relaxedResponseFields(fieldWithPath("cron").description("Cron trigger specific details."))
.andWithPrefix("cron.", cronTriggerSummary)));
}
@Test
void quartzTriggerSimple() throws Exception {
setupTriggerDetails(triggerTwo.getTriggerBuilder(), TriggerState.NORMAL);
setupTriggerDetails(simpleTrigger.getTriggerBuilder(), TriggerState.NORMAL);
this.mockMvc.perform(get("/actuator/quartz/triggers/samples/example")).andExpect(status().isOk())
.andDo(document("quartz/trigger-details-simple",
responseFields(commonCronDetails)
.and(fieldWithPath("simple").description("Simple trigger specific details."))
relaxedResponseFields(fieldWithPath("simple").description("Simple trigger specific details."))
.andWithPrefix("simple.", simpleTriggerSummary)
.and(repeatCount("simple."), timesTriggered("simple."))));
}
@Test
void quartzTriggerCalendarInterval() throws Exception {
setupTriggerDetails(triggerThree.getTriggerBuilder(), TriggerState.NORMAL);
setupTriggerDetails(calendarIntervalTrigger.getTriggerBuilder(), TriggerState.NORMAL);
this.mockMvc.perform(get("/actuator/quartz/triggers/samples/example")).andExpect(status().isOk())
.andDo(document("quartz/trigger-details-calendar-interval", responseFields(commonCronDetails)
.and(fieldWithPath("calendarInterval")
.description("Calendar interval trigger specific details."))
.andWithPrefix("calendarInterval.", calendarIntervalTriggerSummary)
.and(timesTriggered("calendarInterval."),
fieldWithPath("calendarInterval.preserveHourOfDayAcrossDaylightSavings").description(
"Whether to fire the trigger at the same time of day, regardless of daylight "
+ "saving time transitions."),
fieldWithPath("calendarInterval.skipDayIfHourDoesNotExist").description(
"Whether to skip if the hour of the day does not exist on a given day."))));
.andDo(document("quartz/trigger-details-calendar-interval", relaxedResponseFields(
fieldWithPath("calendarInterval").description("Calendar interval trigger specific details."))
.andWithPrefix("calendarInterval.", calendarIntervalTriggerSummary)
.and(timesTriggered("calendarInterval."), fieldWithPath(
"calendarInterval.preserveHourOfDayAcrossDaylightSavings").description(
"Whether to fire the trigger at the same time of day, regardless of daylight "
+ "saving time transitions."),
fieldWithPath("calendarInterval.skipDayIfHourDoesNotExist").description(
"Whether to skip if the hour of the day does not exist on a given day."))));
}
@Test
void quartzTriggerDailyTimeInterval() throws Exception {
setupTriggerDetails(triggerFour.getTriggerBuilder(), TriggerState.PAUSED);
setupTriggerDetails(dailyTimeIntervalTrigger.getTriggerBuilder(), TriggerState.PAUSED);
this.mockMvc.perform(get("/actuator/quartz/triggers/samples/example")).andExpect(status().isOk())
.andDo(document("quartz/trigger-details-daily-time-interval",
responseFields(commonCronDetails)
.and(fieldWithPath("dailyTimeInterval")
.description("Daily time interval trigger specific details."))
.andWithPrefix("dailyTimeInterval.", dailyTimeIntervalTriggerSummary)
.and(repeatCount("dailyTimeInterval."), timesTriggered("dailyTimeInterval."))));
relaxedResponseFields(fieldWithPath("dailyTimeInterval")
.description("Daily time interval trigger specific details."))
.andWithPrefix("dailyTimeInterval.", dailyTimeIntervalTriggerSummary)
.and(repeatCount("dailyTimeInterval."), timesTriggered("dailyTimeInterval."))));
}
@Test
@ -331,8 +353,7 @@ class QuartzEndpointDocumentationTests extends MockMvcEndpointDocumentationTests
mockTriggers(trigger);
this.mockMvc.perform(get("/actuator/quartz/triggers/samples/example")).andExpect(status().isOk())
.andDo(document("quartz/trigger-details-custom",
responseFields(commonCronDetails)
.and(fieldWithPath("custom").description("Custom trigger specific details."))
relaxedResponseFields(fieldWithPath("custom").description("Custom trigger specific details."))
.andWithPrefix("custom.", customTriggerSummary)));
}

Loading…
Cancel
Save