chore: initialize go-sip repository
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
// Package callwindow enforces the fixed legal window for SIP outbound dialing.
|
||||
package callwindow
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
LocationName = "Asia/Shanghai"
|
||||
OpenHour = 9
|
||||
CloseHour = 20
|
||||
)
|
||||
|
||||
var shanghai = time.FixedZone(LocationName, 8*60*60)
|
||||
|
||||
// Allowed reports whether SIP outbound dialing is permitted at now. The
|
||||
// boundary is [09:00, 20:00) in Asia/Shanghai; the input's instant, not its
|
||||
// presentation timezone, is authoritative.
|
||||
func Allowed(now time.Time) bool {
|
||||
local := now.In(shanghai)
|
||||
minutes := local.Hour()*60 + local.Minute()
|
||||
return minutes >= OpenHour*60 && minutes < CloseHour*60
|
||||
}
|
||||
|
||||
// Check returns a stable, actionable error when outbound dialing is closed.
|
||||
func Check(now time.Time) error {
|
||||
local := now.In(shanghai)
|
||||
if Allowed(now) {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("SIP outbound dialing is closed at %s; allowed window is %02d:00-%02d:00 %s", local.Format("2006-01-02 15:04:05 -0700"), OpenHour, CloseHour, LocationName)
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package callwindow
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestAllowedBoundariesInShanghai(t *testing.T) {
|
||||
location := time.FixedZone("test", 8*60*60)
|
||||
tests := []struct {
|
||||
name string
|
||||
at time.Time
|
||||
want bool
|
||||
}{
|
||||
{name: "before opening", at: time.Date(2026, 9, 20, 8, 59, 59, 0, location), want: false},
|
||||
{name: "opening", at: time.Date(2026, 9, 20, 9, 0, 0, 0, location), want: true},
|
||||
{name: "before closing", at: time.Date(2026, 9, 20, 19, 59, 59, 0, location), want: true},
|
||||
{name: "closing", at: time.Date(2026, 9, 20, 20, 0, 0, 0, location), want: false},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := Allowed(tt.at); got != tt.want {
|
||||
t.Fatalf("Allowed(%s)=%v, want %v", tt.at, got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAllowedConvertsUTCToShanghai(t *testing.T) {
|
||||
if !Allowed(time.Date(2026, 9, 20, 1, 0, 0, 0, time.UTC)) {
|
||||
t.Fatal("01:00 UTC should be 09:00 Asia/Shanghai and allowed")
|
||||
}
|
||||
if Allowed(time.Date(2026, 9, 20, 12, 0, 0, 0, time.UTC)) {
|
||||
t.Fatal("12:00 UTC should be 20:00 Asia/Shanghai and rejected")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckExplainsClosedWindow(t *testing.T) {
|
||||
err := Check(time.Date(2026, 9, 20, 20, 0, 0, 0, time.FixedZone("test", 8*60*60)))
|
||||
if err == nil {
|
||||
t.Fatal("expected closed-window error")
|
||||
}
|
||||
for _, want := range []string{"09:00", "20:00", "Asia/Shanghai"} {
|
||||
if !strings.Contains(err.Error(), want) {
|
||||
t.Fatalf("error %q does not contain %q", err, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user