Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Complete DateTimeUtils tests #595

Merged
merged 1 commit into from
Dec 10, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ Current

### Added:

- [Complete DateTimeUtils tests](https://github.com/yahoo/fili/pull/595)
* Add tests for all un-tested methods in `DateTimeUtils`.

- [Enable checkstyle to detect incorrect package header](https://github.com/yahoo/fili/pull/594)
* Fili was able to pass the build with wrong package headers in some source files. This needs to be fixed, and it's
fixed in this PR by adding PackageDeclaration checkstyle rule.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,17 @@ package com.yahoo.bard.webservice.util

import static com.yahoo.bard.webservice.data.time.DefaultTimeGrain.DAY
import static com.yahoo.bard.webservice.data.time.DefaultTimeGrain.HOUR
import static com.yahoo.bard.webservice.data.time.DefaultTimeGrain.MINUTE
import static com.yahoo.bard.webservice.data.time.DefaultTimeGrain.MONTH
import static com.yahoo.bard.webservice.data.time.DefaultTimeGrain.QUARTER
import static com.yahoo.bard.webservice.data.time.DefaultTimeGrain.WEEK
import static com.yahoo.bard.webservice.data.time.DefaultTimeGrain.YEAR

import com.yahoo.bard.webservice.data.time.DefaultTimeGrain
import com.yahoo.bard.webservice.data.time.ZonedTimeGrain

import org.joda.time.DateTime
import org.joda.time.DateTimeZone
import org.joda.time.Interval

import spock.lang.Specification
Expand All @@ -17,57 +23,89 @@ import spock.lang.Unroll
class DateTimeUtilsSpec extends Specification {

@Unroll
def "check if #c = #a + #b"() {
def "check if #sum = #dateTime + #timeGrain"() {
expect:
DateTimeUtils.addTimeGrain(new DateTime(a), b) == new DateTime(c)
DateTimeUtils.addTimeGrain(new DateTime(dateTime), timeGrain) == new DateTime(sum)

where:
a | b || c
"2014-01-01T10:00:00.000" | HOUR || "2014-01-01T11:00:00.000"
"2014-01-01" | DAY || "2014-01-02"
"2014-01-31" | DAY || "2014-02-01"
"2014-04-30" | DAY || "2014-05-01"
"2012-02-29" | DAY || "2012-03-01"
"2014-02-28" | DAY || "2014-03-01"
"2012-02-28" | DAY || "2012-02-29"
"2014-02-28" | WEEK || "2014-03-07"
"2012-02-28" | WEEK || "2012-03-06"
"2014-01-01" | WEEK || "2014-01-08"
"2014-02-01" | WEEK || "2014-02-08"
"2014-01-01" | MONTH || "2014-02-01"
"2014-02-01" | MONTH || "2014-03-01"
"2014-04-01" | MONTH || "2014-05-01"
"2012-02-01" | MONTH || "2012-03-01"
"2012-01-01" | YEAR || "2013-01-01"
"2014-07-01" | YEAR || "2015-07-01"
dateTime | timeGrain | sum
"2014-01-01T10:00:00.000" | HOUR | "2014-01-01T11:00:00.000"
"2014-01-01" | DAY | "2014-01-02"
"2014-01-31" | DAY | "2014-02-01"
"2014-04-30" | DAY | "2014-05-01"
"2012-02-29" | DAY | "2012-03-01"
"2014-02-28" | DAY | "2014-03-01"
"2012-02-28" | DAY | "2012-02-29"
"2014-02-28" | WEEK | "2014-03-07"
"2012-02-28" | WEEK | "2012-03-06"
"2014-01-01" | WEEK | "2014-01-08"
"2014-02-01" | WEEK | "2014-02-08"
"2014-01-01" | MONTH | "2014-02-01"
"2014-02-01" | MONTH | "2014-03-01"
"2014-04-01" | MONTH | "2014-05-01"
"2012-02-01" | MONTH | "2012-03-01"
"2012-01-01" | YEAR | "2013-01-01"
"2014-07-01" | YEAR | "2015-07-01"
}

def buildIntervalSet(List<String> intervalStrList) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This helper method has been moved to the bottom of this file for organization purpose

Set<Interval> intervals = new TreeSet<>(new IntervalStartComparator())

intervalStrList.each {
intervals.add(new Interval(it))
}
@Unroll
def "check for proper merging of #intervals into a set"() {
expect:
DateTimeUtils.mergeIntervalSet(buildIntervalSet(intervals)) == buildIntervalSet(merged)

intervals
where:
// CHECKSTYLE:OFF
intervals | merged
["2014-01-01/2014-01-03", "2014-01-05/2014-01-07", "2014-01-12/2014-01-15", "2014-01-09/2014-01-10"] | ["2014-01-01/2014-01-03", "2014-01-05/2014-01-07", "2014-01-09/2014-01-10", "2014-01-12/2014-01-15"]
["2014-01-01/2014-01-03", "2014-01-05/2014-01-07", "2014-01-12/2014-01-15", "2014-01-07/2014-01-09"] | ["2014-01-01/2014-01-03", "2014-01-05/2014-01-09", "2014-01-12/2014-01-15"]
["2014-01-01/2014-01-03", "2014-01-05/2014-01-07", "2014-01-12/2014-01-15", "2014-01-06/2014-01-09"] | ["2014-01-01/2014-01-03", "2014-01-05/2014-01-09", "2014-01-12/2014-01-15"]
["2014-01-01/2014-01-03", "2014-01-05/2014-01-07", "2014-01-12/2014-01-15", "2014-01-06/2014-01-14"] | ["2014-01-01/2014-01-03", "2014-01-05/2014-01-15"]
["2014-01-01/2014-01-03", "2014-01-05/2014-01-07", "2014-01-12/2014-01-15", "2014-01-02/2014-01-14"] | ["2014-01-01/2014-01-15"]
// CHECKSTYLE:ON
}

@Unroll
def "check for proper merging of #b into given interval set"() {
def "check for proper merging of #singleInterval into given interval set"() {
expect:
DateTimeUtils.mergeIntervalToSet(buildIntervalSet(a), new Interval(b)) == buildIntervalSet(c)
DateTimeUtils.mergeIntervalToSet(buildIntervalSet(intervals), new Interval(singleInterval)) == buildIntervalSet(merged)

where:
// CHECKSTYLE:OFF
a | b || c
["2014-01-01/2014-01-03", "2014-01-05/2014-01-07", "2014-01-12/2014-01-15"] | "2014-01-09/2014-01-10" || ["2014-01-01/2014-01-03", "2014-01-05/2014-01-07", "2014-01-09/2014-01-10", "2014-01-12/2014-01-15"]
["2014-01-01/2014-01-03", "2014-01-05/2014-01-07", "2014-01-12/2014-01-15"] | "2014-01-07/2014-01-09" || ["2014-01-01/2014-01-03", "2014-01-05/2014-01-09", "2014-01-12/2014-01-15"]
["2014-01-01/2014-01-03", "2014-01-05/2014-01-07", "2014-01-12/2014-01-15"] | "2014-01-06/2014-01-09" || ["2014-01-01/2014-01-03", "2014-01-05/2014-01-09", "2014-01-12/2014-01-15"]
["2014-01-01/2014-01-03", "2014-01-05/2014-01-07", "2014-01-12/2014-01-15"] | "2014-01-06/2014-01-14" || ["2014-01-01/2014-01-03", "2014-01-05/2014-01-15"]
["2014-01-01/2014-01-03", "2014-01-05/2014-01-07", "2014-01-12/2014-01-15"] | "2014-01-02/2014-01-14" || ["2014-01-01/2014-01-15"]
intervals | singleInterval | merged
["2014-01-01/2014-01-03", "2014-01-05/2014-01-07", "2014-01-12/2014-01-15"] | "2014-01-09/2014-01-10" | ["2014-01-01/2014-01-03", "2014-01-05/2014-01-07", "2014-01-09/2014-01-10", "2014-01-12/2014-01-15"]
["2014-01-01/2014-01-03", "2014-01-05/2014-01-07", "2014-01-12/2014-01-15"] | "2014-01-07/2014-01-09" | ["2014-01-01/2014-01-03", "2014-01-05/2014-01-09", "2014-01-12/2014-01-15"]
["2014-01-01/2014-01-03", "2014-01-05/2014-01-07", "2014-01-12/2014-01-15"] | "2014-01-06/2014-01-09" | ["2014-01-01/2014-01-03", "2014-01-05/2014-01-09", "2014-01-12/2014-01-15"]
["2014-01-01/2014-01-03", "2014-01-05/2014-01-07", "2014-01-12/2014-01-15"] | "2014-01-06/2014-01-14" | ["2014-01-01/2014-01-03", "2014-01-05/2014-01-15"]
["2014-01-01/2014-01-03", "2014-01-05/2014-01-07", "2014-01-12/2014-01-15"] | "2014-01-02/2014-01-14" | ["2014-01-01/2014-01-15"]
// CHECKSTYLE:ON
}

@Unroll
def "findFullAvailabilityGaps returns the gaps, #gaps, in #available vs #needed interval sets in the case of #description"() {
expect:
DateTimeUtils.findFullAvailabilityGaps(buildIntervalSet(available), buildIntervalSet(needed)) ==
buildIntervalSet(gaps) as SortedSet

where:
available | needed | gaps | description
["2014-01-01/2014-01-03"] | ["2014-01-01/2014-01-03"] | [] | "available interval = needed interval"
["2014-01-01/2014-01-03", "2014-01-07/2014-01-08"] | ["2014-01-01/2014-01-03", "2014-01-07/2014-01-08"] | [] | "available intervals = needed intervals"
["2014-01-01/2014-01-03"] | ["2014-01-05/2014-01-06"] | ["2014-01-05/2014-01-06"] | "no overlap"
["2014-01-01/2014-01-03", "2014-01-04/2014-01-05"] | ["2014-01-07/2014-01-08", "2014-01-09/2014-01-10"] | ["2014-01-07/2014-01-08", "2014-01-09/2014-01-10"] | "no overlaps"
["2014-01-01/2014-01-03"] | ["2014-01-02/2014-01-05"] | ["2014-01-02/2014-01-05"] | "overlap between available right and needed left"
["2014-01-01/2014-01-03"] | ["2014-01-02/2014-01-05", "2014-01-02/2014-01-04"] | ["2014-01-02/2014-01-05", "2014-01-02/2014-01-04"] | "overlaps between available right and needed left"
["2014-01-01/2014-01-03", "2014-01-03/2014-01-04"] | ["2014-01-02/2014-01-05"] | ["2014-01-02/2014-01-05"] | "overlaps between available right and needed left"
["2014-01-02/2014-01-05"] | ["2014-01-01/2014-01-03"] | ["2014-01-01/2014-01-03"] | "overlap between available left and needed right"
["2014-01-02/2014-01-05"] | ["2014-01-01/2014-01-03", "2014-01-01/2014-01-04"] | ["2014-01-01/2014-01-03", "2014-01-01/2014-01-04"] | "overlap between available left and needed right"
["2014-01-02/2014-01-03", "2014-01-02/2014-01-05"] | ["2014-01-01/2014-01-03"] | ["2014-01-01/2014-01-03"] | "overlap between available left and needed right"
["2014-01-01/2014-01-03"] | ["2014-01-03/2014-01-04"] | ["2014-01-03/2014-01-04"] | "available right abuts needed left"
["2014-01-02/2014-01-03"] | ["2014-01-01/2014-01-02"] | ["2014-01-01/2014-01-02"] | "available left abuts needed right"
["2014-01-01/2014-01-05"] | ["2014-01-02/2014-01-03"] | [] | "available interval contain needed interval"
["2014-01-01/2014-01-03", "2014-01-02/2014-01-05"] | ["2014-01-02/2014-01-03"] | [] | "available intervals contain needed interval"
["2014-01-01/2014-01-05"] | ["2014-01-02/2014-01-03"] | [] | "available interval contain needed interval"
["2014-01-01/2014-01-03", "2014-01-02/2014-01-05"] | ["2014-01-02/2014-01-03", "2014-01-04/2014-01-05"] | [] | "available intervals contain needed intervals"
}

@Unroll
def "Verify if intervalToString() method formats interval #a to string #b"() {
expect:
Expand All @@ -79,6 +117,50 @@ class DateTimeUtilsSpec extends Specification {
"2014-07-01/2014-07-02" || "2014-07-01 00:00:00.000/2014-07-02 00:00:00.000"
}

def "sliceIntervals throws IllegalArgumentException when interval is not aligned with time grain"() {
given:
Interval interval = new Interval("2014-07-05/2014-07-31")

when:
DateTimeUtils.sliceIntervals(interval, MONTH)

then:
Exception exception = thrown()
exception instanceof IllegalArgumentException
("Interval must be aligned to the TimeGrain starting " + MONTH.roundFloor(interval.start)).equals(
exception.message
)
}

def "sliceIntervals throws IllegalArgumentException when interval is not a multiple of time grain"() {
given:
Interval interval = new Interval("2014-07-01/2014-12-10")

when:
DateTimeUtils.sliceIntervals(interval, MONTH)

then:
Exception exception = thrown()
exception instanceof IllegalArgumentException
"Interval must be a multiple of the TimeGrain".equals(exception.message)
}

@Unroll
def "sliceIntervals slices #interval into #expected of the timeGrain #timeGrain"() {
expect:
DateTimeUtils.sliceIntervals(new Interval(interval), timeGrain) == (buildIntervalSet(expected) as List)

where:
interval | timeGrain | expected
"2014-07-01T00:00:00.000/2014-07-01T00:02:00.000" | MINUTE | ["2014-07-01T00:00:00.000/2014-07-01T00:01:00.000", "2014-07-01T00:01:00.000/2014-07-01T00:02:00.000"]
"2014-07-01T00:00:00.000/2014-07-01T02:00:00.000" | HOUR | ["2014-07-01T00:00:00.000/2014-07-01T01:00:00.000", "2014-07-01T01:00:00.000/2014-07-01T02:00:00.000"]
"2014-07-01T00:00:00.000/2014-07-03T00:00:00.000" | DAY | ["2014-07-01T00:00:00.000/2014-07-02T00:00:00.000", "2014-07-02T00:00:00.000/2014-07-03T00:00:00.000"]
"2014-06-30T00:00:00.000/2014-07-14T00:00:00.000" | WEEK | ["2014-06-30T00:00:00.000/2014-07-07T00:00:00.000", "2014-07-07T00:00:00.000/2014-07-14T00:00:00.000"]
"2014-07-01T00:00:00.000/2014-09-01T00:00:00.000" | MONTH | ["2014-07-01T00:00:00.000/2014-08-01T00:00:00.000", "2014-08-01T00:00:00.000/2014-09-01T00:00:00.000"]
"2014-07-01T00:00:00.000/2015-01-01T00:00:00.000" | QUARTER | ["2014-07-01T00:00:00.000/2014-10-01T00:00:00.000", "2014-10-01T00:00:00.000/2015-01-01T00:00:00.000"]
"2014-01-01T00:00:00.000/2016-01-01T00:00:00.000" | YEAR | ["2014-01-01T00:00:00.000/2015-01-01T00:00:00.000", "2015-01-01T00:00:00.000/2016-01-01T00:00:00.000"]
}

@Unroll
def "The start of the quarter containing #datetime is #startOfQuarter"() {
expect:
Expand All @@ -101,4 +183,28 @@ class DateTimeUtilsSpec extends Specification {
new DateTime(2016, 05, 03, 5, 0) | new DateTime(2016, 04, 01, 0, 0)
new DateTime(2016, 06, 30, 0, 0) | new DateTime(2016, 04, 01, 0, 0)
}

def "A ZonedTimeGrain produces a correct time zone"() {
given:
ZonedTimeGrain granularity = Mock(ZonedTimeGrain)
granularity.getTimeZone() >> DateTimeZone.UTC

expect:
DateTimeUtils.getTimeZone(granularity) == DateTimeZone.UTC
}

def "A granularity that is not a ZonedTimeGrain produces a default timezone"() {
expect:
DateTimeUtils.getTimeZone(DefaultTimeGrain.HOUR) == DateTimeZone.default
}

def buildIntervalSet(List<String> intervalStrList) {
Set<Interval> intervals = new TreeSet<>(new IntervalStartComparator())

intervalStrList.each {
intervals.add(new Interval(it))
}

intervals
}
}