diff --git a/check/check_suite_test.go b/check/check_suite_test.go deleted file mode 100644 index e5180db..0000000 --- a/check/check_suite_test.go +++ /dev/null @@ -1,32 +0,0 @@ -package main_test - -import ( - "os" - "testing" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - "github.com/onsi/gomega/gexec" -) - -var checkPath string - -var _ = BeforeSuite(func() { - var err error - - if _, err = os.Stat("/opt/resource/check"); err == nil { - checkPath = "/opt/resource/check" - } else { - checkPath, err = gexec.Build("github.com/concourse/time-resource/check") - Expect(err).NotTo(HaveOccurred()) - } -}) - -var _ = AfterSuite(func() { - gexec.CleanupBuildArtifacts() -}) - -func TestCheck(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Check Suite") -} diff --git a/check/main.go b/check/main.go index f44d40b..1431503 100644 --- a/check/main.go +++ b/check/main.go @@ -4,9 +4,8 @@ import ( "encoding/json" "fmt" "os" - "time" - "github.com/concourse/time-resource/lord" + resource "github.com/concourse/time-resource" "github.com/concourse/time-resource/models" ) @@ -19,38 +18,13 @@ func main() { os.Exit(1) } - err = request.Source.Validate() + command := resource.CheckCommand{} + + versions, err := command.Run(request) if err != nil { - fmt.Fprintln(os.Stderr, "invalid configuration:", err) + fmt.Fprintln(os.Stderr, "running command:", err.Error()) os.Exit(1) } - previousTime := request.Version.Time - currentTime := time.Now().UTC() - - specifiedLocation := request.Source.Location - if specifiedLocation != nil { - currentTime = currentTime.In((*time.Location)(specifiedLocation)) - } - - tl := lord.TimeLord{ - PreviousTime: previousTime, - Location: specifiedLocation, - Start: request.Source.Start, - Stop: request.Source.Stop, - Interval: request.Source.Interval, - Days: request.Source.Days, - } - - versions := []models.Version{} - - if !previousTime.IsZero() { - versions = append(versions, models.Version{Time: previousTime}) - } - - if tl.Check(currentTime) { - versions = append(versions, models.Version{Time: currentTime}) - } - json.NewEncoder(os.Stdout).Encode(versions) } diff --git a/check_command.go b/check_command.go new file mode 100644 index 0000000..afdee69 --- /dev/null +++ b/check_command.go @@ -0,0 +1,47 @@ +package resource + +import ( + "time" + + "github.com/concourse/time-resource/lord" + "github.com/concourse/time-resource/models" +) + +type CheckCommand struct { +} + +func (*CheckCommand) Run(request models.CheckRequest) ([]models.Version, error) { + err := request.Source.Validate() + if err != nil { + return nil, err + } + + previousTime := request.Version.Time + currentTime := time.Now().UTC() + + specifiedLocation := request.Source.Location + if specifiedLocation != nil { + currentTime = currentTime.In((*time.Location)(specifiedLocation)) + } + + tl := lord.TimeLord{ + PreviousTime: previousTime, + Location: specifiedLocation, + Start: request.Source.Start, + Stop: request.Source.Stop, + Interval: request.Source.Interval, + Days: request.Source.Days, + } + + versions := []models.Version{} + + if !previousTime.IsZero() { + versions = append(versions, models.Version{Time: previousTime}) + } + + if tl.Check(currentTime) { + versions = append(versions, models.Version{Time: currentTime}) + } + + return versions, nil +} diff --git a/check/check_test.go b/check_command_test.go similarity index 72% rename from check/check_test.go rename to check_command_test.go index 378df50..755334e 100644 --- a/check/check_test.go +++ b/check_command_test.go @@ -1,63 +1,44 @@ -package main_test +package resource_test import ( - "encoding/json" - "fmt" - "os/exec" "time" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - "github.com/onsi/gomega/gbytes" - "github.com/onsi/gomega/gexec" - + resource "github.com/concourse/time-resource" "github.com/concourse/time-resource/models" ) var _ = Describe("Check", func() { var ( - checkCmd *exec.Cmd - now time.Time + now time.Time ) BeforeEach(func() { now = time.Now().UTC() }) - BeforeEach(func() { - checkCmd = exec.Command(checkPath) - }) - Context("when executed", func() { - var source map[string]interface{} - var version *models.Version + var source models.Source + var version models.Version var response models.CheckResponse BeforeEach(func() { - source = map[string]interface{}{} - version = nil + source = models.Source{} + version = models.Version{} response = models.CheckResponse{} }) JustBeforeEach(func() { - stdin, err := checkCmd.StdinPipe() - Expect(err).NotTo(HaveOccurred()) - - session, err := gexec.Start(checkCmd, GinkgoWriter, GinkgoWriter) - Expect(err).NotTo(HaveOccurred()) + command := resource.CheckCommand{} - err = json.NewEncoder(stdin).Encode(map[string]interface{}{ - "source": source, - "version": version, + var err error + response, err = command.Run(models.CheckRequest{ + Source: source, + Version: version, }) Expect(err).NotTo(HaveOccurred()) - - <-session.Exited - Expect(session.ExitCode()).To(Equal(0)) - - err = json.Unmarshal(session.Out.Contents(), &response) - Expect(err).NotTo(HaveOccurred()) }) Context("when nothing is specified", func() { @@ -74,7 +55,7 @@ var _ = Describe("Check", func() { Context("when the resource has already triggered on the current day", func() { BeforeEach(func() { prev = time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 0, now.Second(), now.Nanosecond(), now.Location()) - version = &models.Version{Time: prev} + version.Time = prev }) It("outputs a supplied version", func() { @@ -86,7 +67,7 @@ var _ = Describe("Check", func() { Context("when the resource was triggered yesterday", func() { BeforeEach(func() { prev = now.Add(-24 * time.Hour) - version = &models.Version{Time: prev} + version.Time = prev }) It("outputs a version containing the current time and supplied version", func() { @@ -104,8 +85,8 @@ var _ = Describe("Check", func() { start := now.Add(-1 * time.Hour) stop := now.Add(1 * time.Hour) - source["start"] = tod(start.Hour(), start.Minute(), 0) - source["stop"] = tod(stop.Hour(), stop.Minute(), 0) + source.Start = tod(start.Hour(), start.Minute(), 0) + source.Stop = tod(stop.Hour(), stop.Minute(), 0) }) Context("when no version is given", func() { @@ -115,32 +96,13 @@ var _ = Describe("Check", func() { }) }) - Context("when the range is given in another timezone", func() { - BeforeEach(func() { - loc := time.FixedZone("LaLaLand", -(60 * 60 * 4)) - - start := now.Add(-1 * time.Hour).In(loc) - stop := now.Add(1 * time.Hour).In(loc) - - source["start"] = tod(start.Hour(), start.Minute(), -4) - source["stop"] = tod(stop.Hour(), stop.Minute(), -4) - }) - - Context("when no version is given", func() { - It("outputs a version containing the current time", func() { - Expect(response).To(HaveLen(1)) - Expect(response[0].Time.Unix()).To(BeNumerically("~", time.Now().Unix(), 1)) - }) - }) - }) - Context("when a version is given", func() { var prev time.Time Context("when the resource has already triggered with in the current time range", func() { BeforeEach(func() { prev = now.Add(-30 * time.Minute) - version = &models.Version{Time: prev} + version.Time = prev }) It("outputs a supplied version", func() { @@ -152,7 +114,7 @@ var _ = Describe("Check", func() { Context("when the resource was triggered yesterday near the end of the time frame", func() { BeforeEach(func() { prev = now.Add(-23 * time.Hour) - version = &models.Version{Time: prev} + version.Time = prev }) It("outputs a version containing the current time and supplied version", func() { @@ -165,7 +127,7 @@ var _ = Describe("Check", func() { Context("when the resource was triggered last year near the end of the time frame", func() { BeforeEach(func() { prev = now.AddDate(-1, 0, 0) - version = &models.Version{Time: prev} + version.Time = prev }) It("outputs a version containing the current time and supplied version", func() { @@ -178,7 +140,7 @@ var _ = Describe("Check", func() { Context("when the resource was triggered yesterday in the current time frame", func() { BeforeEach(func() { prev = now.Add(-24 * time.Hour) - version = &models.Version{Time: prev} + version.Time = prev }) It("outputs a version containing the current time and supplied version", func() { @@ -191,7 +153,8 @@ var _ = Describe("Check", func() { Context("when an interval is specified", func() { BeforeEach(func() { - source["interval"] = "1m" + interval := models.Interval(time.Minute) + source.Interval = &interval }) Context("when no version is given", func() { @@ -207,7 +170,7 @@ var _ = Describe("Check", func() { Context("when the interval has not elapsed", func() { BeforeEach(func() { prev = now - version = &models.Version{Time: prev} + version.Time = prev }) It("outputs only the supplied version", func() { @@ -219,7 +182,7 @@ var _ = Describe("Check", func() { Context("when the interval has elapsed", func() { BeforeEach(func() { prev = now.Add(-1 * time.Minute) - version = &models.Version{Time: prev} + version.Time = prev }) It("outputs a version containing the current time and supplied version", func() { @@ -232,7 +195,7 @@ var _ = Describe("Check", func() { Context("with its time N intervals ago", func() { BeforeEach(func() { prev = now.Add(-5 * time.Minute) - version = &models.Version{Time: prev} + version.Time = prev }) It("outputs a version containing the current time and supplied version", func() { @@ -246,9 +209,9 @@ var _ = Describe("Check", func() { Context("when the current day is specified", func() { BeforeEach(func() { - source["days"] = []string{ - now.Weekday().String(), - now.AddDate(0, 0, 2).Weekday().String(), + source.Days = []models.Weekday{ + models.Weekday(now.Weekday()), + models.Weekday(now.AddDate(0, 0, 2).Weekday()), } }) @@ -260,9 +223,9 @@ var _ = Describe("Check", func() { Context("when we are out of the specified day", func() { BeforeEach(func() { - source["days"] = []string{ - now.AddDate(0, 0, 1).Weekday().String(), - now.AddDate(0, 0, 2).Weekday().String(), + source.Days = []models.Weekday{ + models.Weekday(now.AddDate(0, 0, 1).Weekday()), + models.Weekday(now.AddDate(0, 0, 2).Weekday()), } }) @@ -277,8 +240,8 @@ var _ = Describe("Check", func() { start := now.Add(6 * time.Hour) stop := now.Add(7 * time.Hour) - source["start"] = tod(start.Hour(), start.Minute(), 0) - source["stop"] = tod(stop.Hour(), stop.Minute(), 0) + source.Start = tod(start.Hour(), start.Minute(), 0) + source.Stop = tod(stop.Hour(), stop.Minute(), 0) }) Context("when no version is given", func() { @@ -292,9 +255,11 @@ var _ = Describe("Check", func() { start := now.Add(6 * time.Hour) stop := now.Add(7 * time.Hour) - source["start"] = tod(start.Hour(), start.Minute(), 0) - source["stop"] = tod(stop.Hour(), stop.Minute(), 0) - source["interval"] = "1m" + source.Start = tod(start.Hour(), start.Minute(), 0) + source.Stop = tod(stop.Hour(), stop.Minute(), 0) + + interval := models.Interval(time.Minute) + source.Interval = &interval }) It("does not output any versions", func() { @@ -311,7 +276,8 @@ var _ = Describe("Check", func() { loc, err = time.LoadLocation("America/Indiana/Indianapolis") Expect(err).ToNot(HaveOccurred()) - source["location"] = loc.String() + srcLoc := models.Location(*loc) + source.Location = &srcLoc now = now.In(loc) }) @@ -321,8 +287,8 @@ var _ = Describe("Check", func() { start := now.Add(-1 * time.Hour) stop := now.Add(1 * time.Hour) - source["start"] = tod(start.Hour(), start.Minute(), 0) - source["stop"] = tod(stop.Hour(), stop.Minute(), 0) + source.Start = tod(start.Hour(), start.Minute(), 0) + source.Stop = tod(stop.Hour(), stop.Minute(), 0) }) Context("when no version is given", func() { @@ -338,7 +304,7 @@ var _ = Describe("Check", func() { Context("when the resource has already triggered with in the current time range", func() { BeforeEach(func() { prev = now.Add(-30 * time.Minute) - version = &models.Version{Time: prev} + version.Time = prev }) It("outputs a supplied version", func() { @@ -350,7 +316,7 @@ var _ = Describe("Check", func() { Context("when the resource was triggered yesterday near the end of the time frame", func() { BeforeEach(func() { prev = now.Add(-23 * time.Hour) - version = &models.Version{Time: prev} + version.Time = prev }) It("outputs a version containing the current time and supplied version", func() { @@ -363,7 +329,7 @@ var _ = Describe("Check", func() { Context("when the resource was triggered yesterday in the current time frame", func() { BeforeEach(func() { prev = now.AddDate(0, 0, -1) - version = &models.Version{Time: prev} + version.Time = prev }) It("outputs a version containing the current time and supplied version", func() { @@ -376,7 +342,8 @@ var _ = Describe("Check", func() { Context("when an interval is specified", func() { BeforeEach(func() { - source["interval"] = "1m" + interval := models.Interval(time.Minute) + source.Interval = &interval }) Context("when no version is given", func() { @@ -392,7 +359,7 @@ var _ = Describe("Check", func() { Context("with its time within the interval", func() { BeforeEach(func() { prev = now - version = &models.Version{Time: prev} + version.Time = prev }) It("outputs the given version", func() { @@ -404,7 +371,7 @@ var _ = Describe("Check", func() { Context("with its time one interval ago", func() { BeforeEach(func() { prev = now.Add(-1 * time.Minute) - version = &models.Version{Time: prev} + version.Time = prev }) It("outputs a version containing the current time and supplied version", func() { @@ -417,7 +384,7 @@ var _ = Describe("Check", func() { Context("with its time N intervals ago", func() { BeforeEach(func() { prev = now.Add(-5 * time.Minute) - version = &models.Version{Time: prev} + version.Time = prev }) It("outputs a version containing the current time and supplied version", func() { @@ -431,9 +398,9 @@ var _ = Describe("Check", func() { Context("when the current day is specified", func() { BeforeEach(func() { - source["days"] = []string{ - now.Weekday().String(), - now.AddDate(0, 0, 2).Weekday().String(), + source.Days = []models.Weekday{ + models.Weekday(now.Weekday()), + models.Weekday(now.AddDate(0, 0, 2).Weekday()), } }) @@ -445,9 +412,9 @@ var _ = Describe("Check", func() { Context("when we are out of the specified day", func() { BeforeEach(func() { - source["days"] = []string{ - now.AddDate(0, 0, 1).Weekday().String(), - now.AddDate(0, 0, 2).Weekday().String(), + source.Days = []models.Weekday{ + models.Weekday(now.AddDate(0, 0, 1).Weekday()), + models.Weekday(now.AddDate(0, 0, 2).Weekday()), } }) @@ -462,8 +429,8 @@ var _ = Describe("Check", func() { start := now.Add(6 * time.Hour) stop := now.Add(7 * time.Hour) - source["start"] = tod(start.Hour(), start.Minute(), 0) - source["stop"] = tod(stop.Hour(), stop.Minute(), 0) + source.Start = tod(start.Hour(), start.Minute(), 0) + source.Stop = tod(stop.Hour(), stop.Minute(), 0) }) Context("when no version is given", func() { @@ -477,10 +444,11 @@ var _ = Describe("Check", func() { start := now.Add(6 * time.Hour) stop := now.Add(7 * time.Hour) - source["start"] = tod(start.Hour(), start.Minute(), 0) - source["stop"] = tod(stop.Hour(), stop.Minute(), 0) + source.Start = tod(start.Hour(), start.Minute(), 0) + source.Stop = tod(stop.Hour(), stop.Minute(), 0) - source["interval"] = "1m" + interval := models.Interval(time.Minute) + source.Interval = &interval }) It("does not output any versions", func() { @@ -493,7 +461,8 @@ var _ = Describe("Check", func() { Context("when an interval is specified", func() { BeforeEach(func() { - source["interval"] = "1m" + interval := models.Interval(time.Minute) + source.Interval = &interval }) Context("when no version is given", func() { @@ -509,7 +478,7 @@ var _ = Describe("Check", func() { Context("with its time within the interval", func() { BeforeEach(func() { prev = now - version = &models.Version{Time: prev} + version.Time = prev }) It("outputs a supplied version", func() { @@ -521,7 +490,7 @@ var _ = Describe("Check", func() { Context("with its time one interval ago", func() { BeforeEach(func() { prev = now.Add(-1 * time.Minute) - version = &models.Version{Time: prev} + version.Time = prev }) It("outputs a version containing the current time and supplied version", func() { @@ -534,7 +503,7 @@ var _ = Describe("Check", func() { Context("with its time N intervals ago", func() { BeforeEach(func() { prev = now.Add(-5 * time.Minute) - version = &models.Version{Time: prev} + version.Time = prev }) It("outputs a version containing the current time and supplied version", func() { @@ -546,66 +515,16 @@ var _ = Describe("Check", func() { }) }) }) - - Context("with invalid inputs", func() { - var source map[string]interface{} - var version map[string]string - var session *gexec.Session - - BeforeEach(func() { - source = map[string]interface{}{} - version = nil - }) - - JustBeforeEach(func() { - stdin, err := checkCmd.StdinPipe() - Expect(err).NotTo(HaveOccurred()) - - session, err = gexec.Start(checkCmd, GinkgoWriter, GinkgoWriter) - Expect(err).NotTo(HaveOccurred()) - - err = json.NewEncoder(stdin).Encode(map[string]interface{}{ - "source": source, - "version": version, - }) - Expect(err).NotTo(HaveOccurred()) - }) - - Context("with a missing stop", func() { - BeforeEach(func() { - source["start"] = tod(3, 4, -7) - }) - - It("returns an error", func() { - <-session.Exited - - Expect(session.Err).To(gbytes.Say("must configure 'stop' if 'start' is set")) - Expect(session.ExitCode()).To(Equal(1)) - }) - }) - - Context("with a missing start", func() { - BeforeEach(func() { - source["stop"] = tod(3, 4, -7) - }) - - It("returns an error", func() { - <-session.Exited - - Expect(session.Err).To(gbytes.Say("must configure 'start' if 'stop' is set")) - Expect(session.ExitCode()).To(Equal(1)) - }) - }) - }) }) -func tod(hours, minutes, offset int) string { - var o string - if offset < 0 { - o = fmt.Sprintf(" -%02d00", -offset) - } else if offset > 0 { - o = fmt.Sprintf(" +%02d00", offset) +func tod(hours, minutes, offset int) *models.TimeOfDay { + loc := time.UTC + if offset != 0 { + loc = time.FixedZone("UnitTest", 60*60*offset) } - return fmt.Sprintf("%d:%02d%s", hours, minutes, o) + now := time.Now() + tod := models.NewTimeOfDay(time.Date(now.Year(), now.Month(), now.Day(), hours, minutes, 0, 0, loc)) + + return &tod } diff --git a/in/in_suite_test.go b/in/in_suite_test.go deleted file mode 100644 index eee1908..0000000 --- a/in/in_suite_test.go +++ /dev/null @@ -1,32 +0,0 @@ -package main_test - -import ( - "os" - "testing" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - "github.com/onsi/gomega/gexec" -) - -var inPath string - -var _ = BeforeSuite(func() { - var err error - - if _, err = os.Stat("/opt/resource/check"); err == nil { - inPath = "/opt/resource/in" - } else { - inPath, err = gexec.Build("github.com/concourse/time-resource/in") - Expect(err).NotTo(HaveOccurred()) - } -}) - -var _ = AfterSuite(func() { - gexec.CleanupBuildArtifacts() -}) - -func TestIn(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "In Suite") -} diff --git a/in/main.go b/in/main.go index 3d02271..56c2797 100644 --- a/in/main.go +++ b/in/main.go @@ -2,11 +2,10 @@ package main import ( "encoding/json" - "io" + "fmt" "os" - "path/filepath" - "time" + resource "github.com/concourse/time-resource" "github.com/concourse/time-resource/models" ) @@ -18,39 +17,21 @@ func main() { destination := os.Args[1] - err := os.MkdirAll(destination, 0755) - if err != nil { - fatal("creating destination", err) - } + var request models.InRequest - file, err := os.Create(filepath.Join(destination, "input")) + err := json.NewDecoder(os.Stdin).Decode(&request) if err != nil { - fatal("creating input file", err) + fmt.Fprintln(os.Stderr, "parse error:", err.Error()) + os.Exit(1) } - defer file.Close() - - var request models.InRequest + command := resource.InCommand{} - err = json.NewDecoder(io.TeeReader(os.Stdin, file)).Decode(&request) + response, err := command.Run(destination, request) if err != nil { - fatal("reading request", err) - } - - versionTime := request.Version.Time - if versionTime.IsZero() { - versionTime = time.Now() + fmt.Fprintln(os.Stderr, "running command:", err.Error()) + os.Exit(1) } - inVersion := request.Version - inVersion.Time = versionTime - - json.NewEncoder(os.Stdout).Encode(models.InResponse{ - Version: inVersion, - }) -} - -func fatal(doing string, err error) { - println("error " + doing + ": " + err.Error()) - os.Exit(1) + json.NewEncoder(os.Stdout).Encode(response) } diff --git a/in_command.go b/in_command.go new file mode 100644 index 0000000..2ebc666 --- /dev/null +++ b/in_command.go @@ -0,0 +1,43 @@ +package resource + +import ( + "encoding/json" + "fmt" + "os" + "path/filepath" + "time" + + "github.com/concourse/time-resource/models" +) + +type InCommand struct { +} + +func (*InCommand) Run(destination string, request models.InRequest) (models.InResponse, error) { + err := os.MkdirAll(destination, 0755) + if err != nil { + return models.InResponse{}, fmt.Errorf("creating destination: %w", err) + } + + file, err := os.Create(filepath.Join(destination, "input")) + if err != nil { + return models.InResponse{}, fmt.Errorf("creating input file: %w", err) + } + + defer file.Close() + + err = json.NewEncoder(file).Encode(request) + if err != nil { + return models.InResponse{}, fmt.Errorf("writing input file: %w", err) + } + + versionTime := request.Version.Time + if versionTime.IsZero() { + versionTime = time.Now() + } + + inVersion := models.Version{Time: versionTime} + response := models.InResponse{Version: inVersion} + + return response, nil +} diff --git a/in/in_test.go b/in_command_test.go similarity index 50% rename from in/in_test.go rename to in_command_test.go index 36ea49c..1edb52f 100644 --- a/in/in_test.go +++ b/in_command_test.go @@ -1,35 +1,51 @@ -package main_test +package resource_test import ( "encoding/json" "io/ioutil" "os" - "os/exec" "path" "path/filepath" "time" + resource "github.com/concourse/time-resource" "github.com/concourse/time-resource/models" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - "github.com/onsi/gomega/gexec" ) var _ = Describe("In", func() { - var tmpdir string - var destination string + var ( + tmpdir string + destination string - var inCmd *exec.Cmd + source models.Source + version models.Version + response models.InResponse - BeforeEach(func() { - var err error + err error + ) + BeforeEach(func() { tmpdir, err = ioutil.TempDir("", "in-destination") Expect(err).NotTo(HaveOccurred()) destination = path.Join(tmpdir, "in-dir") - inCmd = exec.Command(inPath, destination) + version = models.Version{Time: time.Now()} + + interval := models.Interval(time.Second) + source = models.Source{Interval: &interval} + + response = models.InResponse{} + }) + + JustBeforeEach(func() { + command := resource.InCommand{} + response, err = command.Run(destination, models.InRequest{ + Source: source, + Version: version, + }) }) AfterEach(func() { @@ -37,39 +53,13 @@ var _ = Describe("In", func() { }) Context("when executed", func() { - var request models.InRequest - var response models.InResponse BeforeEach(func() { - interval := models.Interval(time.Second) - - request = models.InRequest{ - Version: models.Version{Time: time.Now()}, - Source: models.Source{Interval: &interval}, - } - - response = models.InResponse{} - }) - - JustBeforeEach(func() { - stdin, err := inCmd.StdinPipe() - Expect(err).NotTo(HaveOccurred()) - - session, err := gexec.Start(inCmd, GinkgoWriter, GinkgoWriter) - Expect(err).NotTo(HaveOccurred()) - - err = json.NewEncoder(stdin).Encode(request) - Expect(err).NotTo(HaveOccurred()) - - <-session.Exited - Expect(session.ExitCode()).To(Equal(0)) - - err = json.Unmarshal(session.Out.Contents(), &response) Expect(err).NotTo(HaveOccurred()) }) It("reports the version's time as the version", func() { - Expect(response.Version.Time.UnixNano()).To(Equal(request.Version.Time.UnixNano())) + Expect(response.Version.Time.UnixNano()).To(Equal(version.Time.UnixNano())) }) It("writes the requested version and source to the destination", func() { @@ -80,13 +70,13 @@ var _ = Describe("In", func() { err = json.NewDecoder(input).Decode(&requested) Expect(err).NotTo(HaveOccurred()) - Expect(requested.Version.Time.Unix()).To(Equal(request.Version.Time.Unix())) - Expect(requested.Source).To(Equal(request.Source)) + Expect(requested.Version.Time.Unix()).To(Equal(version.Time.Unix())) + Expect(requested.Source).To(Equal(source)) }) Context("when the request has no time in its version", func() { BeforeEach(func() { - request.Version = models.Version{} + version = models.Version{} }) It("reports the current time as the version", func() { diff --git a/models/models_suite_test.go b/models/models_suite_test.go new file mode 100644 index 0000000..2d4c6de --- /dev/null +++ b/models/models_suite_test.go @@ -0,0 +1,13 @@ +package models_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "testing" +) + +func TestModels(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Models Suite") +} diff --git a/models/source_test.go b/models/source_test.go new file mode 100644 index 0000000..a5d44c0 --- /dev/null +++ b/models/source_test.go @@ -0,0 +1,76 @@ +package models_test + +import ( + "encoding/json" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/concourse/time-resource/models" +) + +var _ = Describe("Source", func() { + var ( + config string + + source models.Source + err error + ) + + BeforeEach(func() { + config = "" + source = models.Source{} + err = nil + }) + + JustBeforeEach(func() { + err = json.Unmarshal([]byte(config), &source) + }) + + Context("a start with no stop", func() { + BeforeEach(func() { + config = `{ "start": "3:04" }` + }) + + It("generates a validation error", func() { + Expect(err).ToNot(HaveOccurred()) + + err = source.Validate() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(Equal("must configure 'stop' if 'start' is set")) + }) + }) + + Context("a stop with no start", func() { + BeforeEach(func() { + config = `{ "stop": "3:04" }` + }) + + It("generates a validation error", func() { + Expect(err).ToNot(HaveOccurred()) + + err = source.Validate() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(Equal("must configure 'start' if 'stop' is set")) + }) + }) + + Context("when the range is given in another timezone", func() { + BeforeEach(func() { + config = `{ "start": "3:04 -0100", "stop": "9:04 -0700" }` + }) + + It("is valid", func() { + Expect(err).ToNot(HaveOccurred()) + + err = source.Validate() + Expect(err).ToNot(HaveOccurred()) + + Expect(source.Start).ToNot(BeNil()) + Expect(source.Stop).ToNot(BeNil()) + + Expect(source.Stop.Minute()).To(Equal(source.Start.Minute())) + Expect(source.Stop.Hour()).To(Equal(source.Start.Hour() + 12)) + }) + }) +}) diff --git a/out/main.go b/out/main.go index 972e145..fb634ef 100644 --- a/out/main.go +++ b/out/main.go @@ -4,8 +4,8 @@ import ( "encoding/json" "fmt" "os" - "time" + resource "github.com/concourse/time-resource" "github.com/concourse/time-resource/models" ) @@ -18,17 +18,13 @@ func main() { os.Exit(1) } - currentTime := time.Now().UTC() - specifiedLocation := request.Source.Location - if specifiedLocation != nil { - currentTime = currentTime.In((*time.Location)(specifiedLocation)) - } + command := resource.OutCommand{} - outVersion := models.Version{ - Time: currentTime, + response, err := command.Run(request) + if err != nil { + fmt.Fprintln(os.Stderr, "running command:", err.Error()) + os.Exit(1) } - json.NewEncoder(os.Stdout).Encode(models.OutResponse{ - Version: outVersion, - }) + json.NewEncoder(os.Stdout).Encode(response) } diff --git a/out/out_suite_test.go b/out/out_suite_test.go deleted file mode 100644 index a79271f..0000000 --- a/out/out_suite_test.go +++ /dev/null @@ -1,32 +0,0 @@ -package main_test - -import ( - "os" - "testing" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - "github.com/onsi/gomega/gexec" -) - -var outPath string - -var _ = BeforeSuite(func() { - var err error - - if _, err = os.Stat("/opt/resource/out"); err == nil { - outPath = "/opt/resource/out" - } else { - outPath, err = gexec.Build("github.com/concourse/time-resource/out") - Expect(err).NotTo(HaveOccurred()) - } -}) - -var _ = AfterSuite(func() { - gexec.CleanupBuildArtifacts() -}) - -func TestOut(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Out Suite") -} diff --git a/out_command.go b/out_command.go new file mode 100644 index 0000000..29ac433 --- /dev/null +++ b/out_command.go @@ -0,0 +1,23 @@ +package resource + +import ( + "time" + + "github.com/concourse/time-resource/models" +) + +type OutCommand struct { +} + +func (*OutCommand) Run(request models.OutRequest) (models.OutResponse, error) { + currentTime := time.Now().UTC() + specifiedLocation := request.Source.Location + if specifiedLocation != nil { + currentTime = currentTime.In((*time.Location)(specifiedLocation)) + } + + outVersion := models.Version{Time: currentTime} + response := models.OutResponse{Version: outVersion} + + return response, nil +} diff --git a/out/out_test.go b/out_command_test.go similarity index 56% rename from out/out_test.go rename to out_command_test.go index 5f0fd29..3d2faab 100644 --- a/out/out_test.go +++ b/out_command_test.go @@ -1,37 +1,43 @@ -package main_test +package resource_test import ( - "encoding/json" "io/ioutil" "os" - "os/exec" - "path" "strings" "time" + resource "github.com/concourse/time-resource" "github.com/concourse/time-resource/models" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - "github.com/onsi/gomega/gexec" ) var _ = Describe("Out", func() { - var tmpdir string - var source string + var ( + now time.Time - var outCmd *exec.Cmd - var now time.Time + tmpdir string + + source models.Source + response models.OutResponse + + err error + ) BeforeEach(func() { - var err error + now = time.Now().UTC() tmpdir, err = ioutil.TempDir("", "out-source") Expect(err).NotTo(HaveOccurred()) - source = path.Join(tmpdir, "out-dir") + source = models.Source{} + }) - outCmd = exec.Command(outPath, source) - now = time.Now().UTC() + JustBeforeEach(func() { + command := resource.OutCommand{} + response, err = command.Run(models.OutRequest{ + Source: source, + }) }) AfterEach(func() { @@ -39,42 +45,19 @@ var _ = Describe("Out", func() { }) Context("when executed", func() { - var source map[string]interface{} - var response models.OutResponse - - BeforeEach(func() { - source = map[string]interface{}{} - response = models.OutResponse{} - }) JustBeforeEach(func() { - stdin, err := outCmd.StdinPipe() - Expect(err).NotTo(HaveOccurred()) - - session, err := gexec.Start(outCmd, GinkgoWriter, GinkgoWriter) - Expect(err).NotTo(HaveOccurred()) - - err = json.NewEncoder(stdin).Encode(map[string]interface{}{ - "source": source, - }) - Expect(err).NotTo(HaveOccurred()) - - <-session.Exited - Expect(session.ExitCode()).To(Equal(0)) - - err = json.Unmarshal(session.Out.Contents(), &response) Expect(err).NotTo(HaveOccurred()) }) Context("when a location is specified", func() { - var loc *time.Location BeforeEach(func() { - var err error - loc, err = time.LoadLocation("America/Indiana/Indianapolis") + loc, err := time.LoadLocation("America/Indiana/Indianapolis") Expect(err).ToNot(HaveOccurred()) - source["location"] = loc.String() + srcLoc := models.Location(*loc) + source.Location = &srcLoc now = now.In(loc) })