Skip to content
Snippets Groups Projects
Verified Commit 652e1d67 authored by Volker Schukai's avatar Volker Schukai :alien:
Browse files

fix: date format (pauseuntil, time schedule) results in error #29

parent fafc34f8
No related branches found
No related tags found
No related merge requests found
......@@ -35,6 +35,39 @@ type JobPersistence struct {
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;index" json:"-" yaml:"-"`
}
// UnmarshalJSON implements the json.Unmarshaler interface.
func (jp *JobPersistence) UnmarshalJSON(data []byte) error {
// Anonymous struct for unmarshalling with custom time format
type Alias JobPersistence
aux := &struct {
PauseUntil *string `json:"pauseUntil,omitempty"`
*Alias
}{
Alias: (*Alias)(jp),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
if aux.PauseUntil != nil {
var t time.Time
var err error
for _, format := range SupportedTimeFormats {
t, err = time.Parse(format, *aux.PauseUntil)
if err == nil {
break
}
}
if err != nil {
return err
}
jp.PauseUntil = &t
}
return nil
}
func (jp JobPersistence) GetLogs() []JobLog {
return jp.Logs
}
......
package jobqueue
import (
"encoding/json"
"github.com/robfig/cron/v3"
"github.com/stretchr/testify/assert"
"io/ioutil"
......@@ -132,3 +133,51 @@ func TestReadYAMLFile(t *testing.T) {
t.Errorf("Expected job with ID '1' and priority 1, got %+v", jobs)
}
}
func TestJobPersistenceUnmarshalJSON(t *testing.T) {
testCases := []struct {
name string
jsonInput string
expected *time.Time
wantErr bool
}{
{
name: "RFC3339 Format",
jsonInput: `{"pauseUntil":"2023-11-15T09:01:00Z"}`,
expected: parseTimeForTesting(t, "2023-11-15T09:01:00Z"),
wantErr: false,
},
{
name: "Date and Time",
jsonInput: `{"pauseUntil":"2023-11-15T09:01"}`,
expected: parseTimeForTesting(t, "2023-11-15T09:01"),
wantErr: false,
},
{
name: "Only Date",
jsonInput: `{"pauseUntil":"2023-11-15"}`,
expected: parseTimeForTesting(t, "2023-11-15"),
wantErr: false,
},
{
name: "Invalid Format",
jsonInput: `{"pauseUntil":"15. November 2023"}`,
expected: nil,
wantErr: true,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
var jp JobPersistence
err := json.Unmarshal([]byte(tc.jsonInput), &jp)
if tc.wantErr {
assert.Error(t, err)
} else {
assert.NoError(t, err)
assert.Equal(t, tc.expected, jp.PauseUntil)
}
})
}
}
package jobqueue
import (
"encoding/json"
"fmt"
"github.com/robfig/cron/v3"
"time"
......@@ -31,6 +32,39 @@ type SchedulerPersistence struct {
Executed bool `yaml:"executed,omitempty" json:"executed,omitempty" gorm:"column:executed"`
}
// UnmarshalJSON implements the json.Unmarshaler interface
func (sp *SchedulerPersistence) UnmarshalJSON(data []byte) error {
// Anonymous structure to avoid endless recursion
type Alias SchedulerPersistence
aux := &struct {
Time *string `json:"time,omitempty"`
*Alias
}{
Alias: (*Alias)(sp),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
if aux.Time != nil {
var t time.Time
var err error
for _, format := range SupportedTimeFormats {
t, err = time.Parse(format, *aux.Time)
if err == nil {
break
}
}
if err != nil {
return err
}
sp.Time = &t
}
return nil
}
// IntervalScheduler is a scheduler that schedules a job at a fixed interval
type IntervalScheduler struct {
Interval time.Duration
......
package jobqueue
import (
"encoding/json"
"github.com/robfig/cron/v3"
"github.com/stretchr/testify/assert"
"sync/atomic"
......@@ -292,3 +293,76 @@ func TestTimeScheduler_BasicFunctionality(t *testing.T) {
}
}
// TestSchedulerPersistenceUnmarshalJSON testet die Unmarshalling-Funktion mit verschiedenen Zeitformaten.
func TestSchedulerPersistenceUnmarshalJSON(t *testing.T) {
testCases := []struct {
name string
jsonInput string
expected *time.Time
wantErr bool
}{
{
name: "RFC3339 Format",
jsonInput: `{"type":"Time","time":"2023-11-15T09:01:00Z"}`,
expected: parseTimeForTesting(t, "2023-11-15T09:01:00Z"),
wantErr: false,
},
{
name: "Date and Time",
jsonInput: `{"type":"Time","time":"2023-11-15T09:01"}`,
expected: parseTimeForTesting(t, "2023-11-15T09:01"),
wantErr: false,
},
{
name: "Date and Time with Space",
jsonInput: `{"type":"Time","time":"2023-11-15 09:01"}`,
expected: parseTimeForTesting(t, "2023-11-15T09:01"),
wantErr: false,
},
{
name: "Date and Time with Space and Seconds",
jsonInput: `{"type":"Time","time":"2023-11-15 09:01:02"}`,
expected: parseTimeForTesting(t, "2023-11-15T09:01:02"),
wantErr: false,
},
{
name: "Only Date",
jsonInput: `{"type":"Time","time":"2023-11-15"}`,
expected: parseTimeForTesting(t, "2023-11-15"),
wantErr: false,
},
{
name: "Invalid Format",
jsonInput: `{"type":"Time","time":"15. November 2023"}`,
expected: nil,
wantErr: true,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
var sp SchedulerPersistence
err := json.Unmarshal([]byte(tc.jsonInput), &sp)
if tc.wantErr {
assert.Error(t, err)
} else {
assert.NoError(t, err)
assert.Equal(t, tc.expected, sp.Time)
}
})
}
}
func parseTimeForTesting(t *testing.T, value string) *time.Time {
for _, format := range SupportedTimeFormats {
parsedTime, err := time.Parse(format, value)
if err == nil {
return &parsedTime
}
}
t.Fatalf("Failed to parse time '%s' in any known format", value)
return nil
}
package jobqueue
import "time"
var SupportedTimeFormats = []string{
time.RFC3339,
"2006-01-02T15:04:05",
"2006-01-02T15:04",
"2006-01-02T15",
"2006-01-02 15:04:05",
"2006-01-02 15:04",
"2006-01-02 15",
"2006-01-02",
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment