Skip to content

Commit bc72b05

Browse files
authored
Merge pull request #2 from orltom/shiftplan-tests
Test schedule plan generation
2 parents c4db09f + 8db2a3b commit bc72b05

File tree

7 files changed

+219
-17
lines changed

7 files changed

+219
-17
lines changed

.golangci.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ linters:
1111
- lll
1212
- mnd
1313
- gomnd
14+
- testpackage
15+
- wsl
16+
- paralleltest
1417

1518
linters-settings:
1619
goimports:
@@ -51,4 +54,7 @@ issues:
5154
exclude-rules:
5255
- path: cmd/.*
5356
linters:
54-
- forbidigo
57+
- forbidigo
58+
- path: _test.go
59+
linters:
60+
- funlen

cmd/main.go

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,34 +15,34 @@ func main() {
1515
rotationFlag := flag.Int("rotation", 24*7, "Rotation time in hours. Default is one week")
1616
startFlag := flag.String("start", "", "Shift start date")
1717
endFlag := flag.String("end", "", "Shift end date")
18-
configFileFlag := flag.String("config", "config.json", "Config file path")
18+
configFileFlag := flag.String("config", "", "Config file path")
1919
flag.Parse()
2020

21-
start, err := time.Parse("2006-01-02", *startFlag)
21+
config, err := os.ReadFile(*configFileFlag)
2222
if err != nil {
2323
flag.PrintDefaults()
24-
fmt.Println("Invalid start time")
24+
fmt.Println("Config file not found or invalid")
2525
os.Exit(1)
2626
}
2727

28-
end, err := time.Parse("2006-01-02", *endFlag)
29-
if err != nil {
28+
var c apis.Config
29+
if err := json.Unmarshal(config, &c); err != nil {
3030
flag.PrintDefaults()
31-
fmt.Println("Invalid end time")
31+
fmt.Println("Config file could not be parsed")
3232
os.Exit(1)
3333
}
3434

35-
config, err := os.ReadFile(*configFileFlag)
35+
start, err := time.Parse("2006-01-02", *startFlag)
3636
if err != nil {
3737
flag.PrintDefaults()
38-
fmt.Println("Config file not found or invalid")
38+
fmt.Println("Invalid start time")
3939
os.Exit(1)
4040
}
4141

42-
var c apis.Config
43-
if err := json.Unmarshal(config, &c); err != nil {
42+
end, err := time.Parse("2006-01-02", *endFlag)
43+
if err != nil {
4444
flag.PrintDefaults()
45-
fmt.Println("Config file could not be parsed")
45+
fmt.Println("Invalid end time")
4646
os.Exit(1)
4747
}
4848

internal/shift/plan.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ func (sr *ShiftRotation) Plan(start time.Time, end time.Time, rotation time.Dura
4141
secondary := sr.findSecondary(shiftplan, s, e)
4242
sr.team = remove(sr.team, secondary)
4343

44-
shift := apis.Shift{Start: s, End: e, Primary: primary, Secondary: secondary}
44+
shift := apis.Shift{Start: s, End: e, Primary: primary.ID, Secondary: secondary.ID}
4545
shiftplan = append(shiftplan, shift)
4646

4747
sr.team = append(sr.team, secondary, primary)

internal/shift/plan_test.go

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
package shift
2+
3+
import (
4+
"reflect"
5+
"testing"
6+
"time"
7+
8+
"github.com/orltom/on-call-schedule/pkg/apis"
9+
)
10+
11+
func TestNewDefaultShiftRotationShiftRotation_Plan(t *testing.T) {
12+
type args struct {
13+
start time.Time
14+
end time.Time
15+
rotation time.Duration
16+
}
17+
tests := []struct {
18+
name string
19+
employees []apis.Employee
20+
args args
21+
want []apis.Shift
22+
}{
23+
{
24+
name: "Daily Schedule without vacation days",
25+
employees: []apis.Employee{
26+
{
27+
ID: "a@test.ch",
28+
Name: "a",
29+
VacationDays: nil,
30+
},
31+
{
32+
ID: "b@test.ch",
33+
Name: "b",
34+
VacationDays: nil,
35+
},
36+
},
37+
args: args{
38+
start: date("2020-04-01"),
39+
end: date("2020-04-04"),
40+
rotation: 24 * time.Hour,
41+
},
42+
want: []apis.Shift{
43+
{
44+
Start: date("2020-04-01"),
45+
End: date("2020-04-02"),
46+
Primary: "a@test.ch",
47+
Secondary: "b@test.ch",
48+
},
49+
{
50+
Start: date("2020-04-02"),
51+
End: date("2020-04-03"),
52+
Primary: "b@test.ch",
53+
Secondary: "a@test.ch",
54+
},
55+
{
56+
Start: date("2020-04-03"),
57+
End: date("2020-04-04"),
58+
Primary: "a@test.ch",
59+
Secondary: "b@test.ch",
60+
},
61+
},
62+
},
63+
{
64+
name: "Should not schedule Primary on holiday days",
65+
employees: []apis.Employee{
66+
{
67+
ID: "a@test.ch",
68+
Name: "a",
69+
VacationDays: []time.Time{date("2020-04-01")},
70+
},
71+
{
72+
ID: "b@test.ch",
73+
Name: "b",
74+
VacationDays: nil,
75+
},
76+
{
77+
ID: "c@test.ch",
78+
Name: "c",
79+
VacationDays: nil,
80+
},
81+
{
82+
ID: "d@test.ch",
83+
Name: "d",
84+
VacationDays: nil,
85+
},
86+
},
87+
args: args{
88+
start: date("2020-04-01"),
89+
end: date("2020-04-05"),
90+
rotation: 24 * time.Hour,
91+
},
92+
want: []apis.Shift{
93+
{
94+
Start: date("2020-04-01"),
95+
End: date("2020-04-02"),
96+
Primary: "b@test.ch",
97+
Secondary: "c@test.ch",
98+
},
99+
{
100+
Start: date("2020-04-02"),
101+
End: date("2020-04-03"),
102+
Primary: "a@test.ch",
103+
Secondary: "d@test.ch",
104+
},
105+
{
106+
Start: date("2020-04-03"),
107+
End: date("2020-04-04"),
108+
Primary: "c@test.ch",
109+
Secondary: "b@test.ch",
110+
},
111+
{
112+
Start: date("2020-04-04"),
113+
End: date("2020-04-05"),
114+
Primary: "d@test.ch",
115+
Secondary: "a@test.ch",
116+
},
117+
},
118+
},
119+
{
120+
name: "Should not schedule Secondary on holiday days",
121+
employees: []apis.Employee{
122+
{
123+
ID: "a@test.ch",
124+
Name: "a",
125+
VacationDays: nil,
126+
},
127+
{
128+
ID: "b@test.ch",
129+
Name: "b",
130+
VacationDays: []time.Time{date("2020-04-01")},
131+
},
132+
{
133+
ID: "c@test.ch",
134+
Name: "c",
135+
VacationDays: nil,
136+
},
137+
{
138+
ID: "d@test.ch",
139+
Name: "d",
140+
VacationDays: nil,
141+
},
142+
},
143+
args: args{
144+
start: date("2020-04-01"),
145+
end: date("2020-04-05"),
146+
rotation: 24 * time.Hour,
147+
},
148+
want: []apis.Shift{
149+
{
150+
Start: date("2020-04-01"),
151+
End: date("2020-04-02"),
152+
Primary: "a@test.ch",
153+
Secondary: "c@test.ch",
154+
},
155+
{
156+
Start: date("2020-04-02"),
157+
End: date("2020-04-03"),
158+
Primary: "b@test.ch",
159+
Secondary: "d@test.ch",
160+
},
161+
{
162+
Start: date("2020-04-03"),
163+
End: date("2020-04-04"),
164+
Primary: "c@test.ch",
165+
Secondary: "a@test.ch",
166+
},
167+
{
168+
Start: date("2020-04-04"),
169+
End: date("2020-04-05"),
170+
Primary: "d@test.ch",
171+
Secondary: "b@test.ch",
172+
},
173+
},
174+
},
175+
}
176+
for _, tt := range tests {
177+
t.Run(tt.name, func(t *testing.T) {
178+
shiftRotation := NewDefaultShiftRotation(tt.employees)
179+
if got := shiftRotation.Plan(tt.args.start, tt.args.end, tt.args.rotation); !reflect.DeepEqual(got, tt.want) {
180+
t.Errorf("Plan() = %v, want %v", got, tt.want)
181+
}
182+
})
183+
}
184+
}
185+
186+
func date(s string) time.Time {
187+
t, err := time.Parse("2006-01-02", s)
188+
if err != nil {
189+
panic(err)
190+
}
191+
192+
return t
193+
}

internal/shift/rules.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ func InvolvedInLastSift(e apis.Employee, shifts []apis.Shift, _ time.Time, _ tim
2727
}
2828

2929
lastShift := shifts[len(shifts)-1]
30-
if lastShift.Primary.Name == e.Name || lastShift.Secondary.Name == e.Name {
30+
if lastShift.Primary == e.ID || lastShift.Secondary == e.ID {
3131
return true
3232
}
3333

pkg/apis/config.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@ type Config struct {
66
Employees []Employee `json:"employees"`
77
}
88

9+
type EmployeeID string
10+
911
type Employee struct {
12+
ID EmployeeID `json:"id"`
1013
Name string `json:"name"`
1114
VacationDays []time.Time `json:"vacationDays,omitempty"`
1215
}

pkg/apis/shift.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ import (
88
type Shift struct {
99
Start time.Time
1010
End time.Time
11-
Primary Employee
12-
Secondary Employee
11+
Primary EmployeeID
12+
Secondary EmployeeID
1313
}
1414

1515
func (s Shift) String() string {
16-
return fmt.Sprintf("%s - %s = %s (%s)\n", s.Start.Format("2006-01-02"), s.End.Format("2006-01-02"), s.Primary.Name, s.Secondary.Name)
16+
return fmt.Sprintf("%s - %s = %s (%s)\n", s.Start.Format("2006-01-02"), s.End.Format("2006-01-02"), s.Primary, s.Secondary)
1717
}
1818

1919
type ShiftConflictChecker func(primary Employee, shifts []Shift, start time.Time, end time.Time) bool

0 commit comments

Comments
 (0)