Add KeepAlive duration to IaR struct and update related functionality; remove obsolete test file
All checks were successful
Golan Testing / testing (1.25.x, ubuntu-latest) (push) Successful in 24s
All checks were successful
Golan Testing / testing (1.25.x, ubuntu-latest) (push) Successful in 24s
This commit is contained in:
@@ -41,6 +41,7 @@ type IaR struct {
|
||||
PagerGroupID string
|
||||
PagerGroupName string
|
||||
Type string
|
||||
KeepAlive time.Duration
|
||||
}
|
||||
|
||||
// New function creates a New MySubaru API client
|
||||
@@ -52,6 +53,7 @@ func New(credentials *config.Credentials, logger *slog.Logger) (*Client, error)
|
||||
PagerGroupID: "",
|
||||
PagerGroupName: "",
|
||||
Type: "",
|
||||
KeepAlive: 15 * time.Minute,
|
||||
},
|
||||
isAlive: false,
|
||||
logger: logger,
|
||||
@@ -86,6 +88,7 @@ func (c *Client) KeepAlive() error {
|
||||
c.IAR.PagerGroupID = pg.ID
|
||||
c.IAR.PagerGroupName = pg.Name
|
||||
c.IAR.Type = pg.Type
|
||||
c.IAR.KeepAlive = time.Duration(resp.Data.GetTTDSetting.KeyValue) * time.Second
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -118,11 +121,11 @@ func (c *Client) Alert(audioBase64 string) error {
|
||||
}
|
||||
|
||||
// ServeKeepAlive starts a goroutine that sends keep-alive requests at the specified interval.
|
||||
func (c *Client) ServeKeepAlive(ctx context.Context, interval time.Duration) {
|
||||
ticker := time.NewTicker(interval)
|
||||
func (c *Client) ServeKeepAlive(ctx context.Context) {
|
||||
ticker := time.NewTicker(c.IAR.KeepAlive)
|
||||
defer ticker.Stop()
|
||||
|
||||
slog.Info("Starting keep-alive sender", "interval", interval)
|
||||
slog.Info("Starting keep-alive sender", slog.Duration("interval", c.IAR.KeepAlive))
|
||||
|
||||
for {
|
||||
select {
|
||||
|
@@ -1,179 +0,0 @@
|
||||
package client_test
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"git.savin.nyc/alex/go-iar-notificator/client"
|
||||
)
|
||||
|
||||
const keepAliveResponse = `{
|
||||
"data": {
|
||||
"getMutualPagerGroupsList": [
|
||||
{
|
||||
"_id": "672783715f6ed07deb857afb",
|
||||
"subscriberId": 536873008,
|
||||
"name": "NPFD - 672783715f6ed07deb857afb",
|
||||
"type": "ab tone",
|
||||
"tone_tolerance": 0.02,
|
||||
"gaplength": 0,
|
||||
"ignore_after": 60,
|
||||
"record_delay": 2,
|
||||
"record_seconds": 15,
|
||||
"release_time": 3,
|
||||
"playback_during_record": 0,
|
||||
"post_email_command": "",
|
||||
"alert_command": "",
|
||||
"atone": 1656.4,
|
||||
"btone": 656.1,
|
||||
"atonelength": 0.9,
|
||||
"btonelength": 3,
|
||||
"longtone": null,
|
||||
"longtonelength": null,
|
||||
"createDate": "2024-11-03T14:06:41.765Z"
|
||||
}
|
||||
],
|
||||
"getTTDSetting": {
|
||||
"keySetting": "pollingSeconds",
|
||||
"keyValue": "900"
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
const preAlertResponse = `{
|
||||
"data": {
|
||||
"addAlert": {
|
||||
"_id": "68bb90e0b91373858dd8f214",
|
||||
"textAlert": "NPFD Received at 21:39:44 09/05/2025",
|
||||
"pagerGroup": "NPFD",
|
||||
"subscriberId": 536873008
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
const alertResponse = `{
|
||||
"data": {
|
||||
"addAlert": {
|
||||
"_id": "68bb90e0b91373858dd8f214",
|
||||
"textAlert": "NPFD Received at 21:40:05 09/05/2025",
|
||||
"pagerGroup": "NPFD",
|
||||
"audioUrl": "https://storage.iamresponding.com/v3/xzPAzU4ZEXlRtMLtj2NlquvalB26xQfS.mp3",
|
||||
"subscriberId": 536873008
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
// patchClientHTTP replaces the HTTPClient's transport with a test server
|
||||
func patchClientHTTP(c *client.Client, handler http.HandlerFunc) {
|
||||
ts := httptest.NewServer(handler)
|
||||
c.HTTPClient.SetBaseURL(ts.URL)
|
||||
}
|
||||
|
||||
func TestClient_KeepAlive_Success(t *testing.T) {
|
||||
logger := mockLogger()
|
||||
creds := mockCredentials()
|
||||
c, err := client.New(creds, logger)
|
||||
if err != nil {
|
||||
t.Fatalf("New() error: %v", err)
|
||||
}
|
||||
|
||||
patchClientHTTP(c, func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(keepAliveResponse))
|
||||
})
|
||||
|
||||
err = c.KeepAlive()
|
||||
if err != nil {
|
||||
t.Errorf("KeepAlive() error = %v, want nil", err)
|
||||
}
|
||||
if !c.IsAlive() {
|
||||
t.Error("expected client to be alive after successful KeepAlive")
|
||||
}
|
||||
// Check if IAR is set
|
||||
if c.IAR.PagerGroupID != "672783715f6ed07deb857afb" {
|
||||
t.Errorf("expected PagerGroupID to be set, got %s", c.IAR.PagerGroupID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClient_KeepAlive_Failure(t *testing.T) {
|
||||
logger := mockLogger()
|
||||
creds := mockCredentials()
|
||||
c, err := client.New(creds, logger)
|
||||
if err != nil {
|
||||
t.Fatalf("New() error: %v", err)
|
||||
}
|
||||
|
||||
patchClientHTTP(c, func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(`{"error": "fail"}`))
|
||||
})
|
||||
|
||||
err = c.KeepAlive()
|
||||
if err == nil {
|
||||
t.Error("expected error from KeepAlive, got nil")
|
||||
}
|
||||
if c.IsAlive() {
|
||||
t.Error("expected client to not be alive after failed KeepAlive")
|
||||
}
|
||||
}
|
||||
|
||||
func TestClient_PreAlert_Success(t *testing.T) {
|
||||
logger := mockLogger()
|
||||
creds := mockCredentials()
|
||||
c, err := client.New(creds, logger)
|
||||
if err != nil {
|
||||
t.Fatalf("New() error: %v", err)
|
||||
}
|
||||
// Set IAR
|
||||
c.IAR.PagerGroupID = "test_group"
|
||||
|
||||
patchClientHTTP(c, func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(preAlertResponse))
|
||||
})
|
||||
|
||||
alertID, err := c.PreAlert()
|
||||
if err != nil {
|
||||
t.Errorf("PreAlert() error = %v, want nil", err)
|
||||
}
|
||||
expectedID := "68bb90e0b91373858dd8f214"
|
||||
if alertID != expectedID {
|
||||
t.Errorf("expected alertID %s, got %s", expectedID, alertID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClient_Alert_Success(t *testing.T) {
|
||||
logger := mockLogger()
|
||||
creds := mockCredentials()
|
||||
c, err := client.New(creds, logger)
|
||||
if err != nil {
|
||||
t.Fatalf("New() error: %v", err)
|
||||
}
|
||||
// Set IAR
|
||||
c.IAR.PagerGroupID = "test_group"
|
||||
|
||||
callCount := 0
|
||||
patchClientHTTP(c, func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
if callCount == 0 {
|
||||
// First call is preAlert
|
||||
w.Write([]byte(preAlertResponse))
|
||||
} else {
|
||||
// Second call is Alert
|
||||
w.Write([]byte(alertResponse))
|
||||
}
|
||||
callCount++
|
||||
})
|
||||
|
||||
err = c.Alert("base64_audio")
|
||||
if err != nil {
|
||||
t.Errorf("Alert() error = %v, want nil", err)
|
||||
}
|
||||
if callCount != 2 {
|
||||
t.Errorf("expected 2 HTTP calls, got %d", callCount)
|
||||
}
|
||||
}
|
@@ -4,6 +4,8 @@ import (
|
||||
"context"
|
||||
"io"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -11,6 +13,62 @@ import (
|
||||
"git.savin.nyc/alex/go-iar-notificator/config"
|
||||
)
|
||||
|
||||
const keepAliveResponse = `{
|
||||
"data": {
|
||||
"getMutualPagerGroupsList": [
|
||||
{
|
||||
"_id": "672783715f6ed07deb857afb",
|
||||
"subscriberId": 536873008,
|
||||
"name": "NPFD - 672783715f6ed07deb857afb",
|
||||
"type": "ab tone",
|
||||
"tone_tolerance": 0.02,
|
||||
"gaplength": 0,
|
||||
"ignore_after": 60,
|
||||
"record_delay": 2,
|
||||
"record_seconds": 15,
|
||||
"release_time": 3,
|
||||
"playback_during_record": 0,
|
||||
"post_email_command": "",
|
||||
"alert_command": "",
|
||||
"atone": 1656.4,
|
||||
"btone": 656.1,
|
||||
"atonelength": 0.9,
|
||||
"btonelength": 3,
|
||||
"longtone": null,
|
||||
"longtonelength": null,
|
||||
"createDate": "2024-11-03T14:06:41.765Z"
|
||||
}
|
||||
],
|
||||
"getTTDSetting": {
|
||||
"keySetting": "pollingSeconds",
|
||||
"keyValue": "900"
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
const preAlertResponse = `{
|
||||
"data": {
|
||||
"addAlert": {
|
||||
"_id": "68bb90e0b91373858dd8f214",
|
||||
"textAlert": "NPFD Received at 21:39:44 09/05/2025",
|
||||
"pagerGroup": "NPFD",
|
||||
"subscriberId": 536873008
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
const alertResponse = `{
|
||||
"data": {
|
||||
"addAlert": {
|
||||
"_id": "68bb90e0b91373858dd8f214",
|
||||
"textAlert": "NPFD Received at 21:40:05 09/05/2025",
|
||||
"pagerGroup": "NPFD",
|
||||
"audioUrl": "https://storage.iamresponding.com/v3/xzPAzU4ZEXlRtMLtj2NlquvalB26xQfS.mp3",
|
||||
"subscriberId": 536873008
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
// mockLogger returns a no-op slog.Logger for testing
|
||||
func mockLogger() *slog.Logger {
|
||||
return slog.New(slog.NewTextHandler(io.Discard, &slog.HandlerOptions{}))
|
||||
@@ -50,9 +108,128 @@ func TestServeKeepAliveCancel(t *testing.T) {
|
||||
creds := mockCredentials()
|
||||
c, _ := client.New(creds, logger)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
go c.ServeKeepAlive(ctx, 10*time.Millisecond)
|
||||
go c.ServeKeepAlive(ctx)
|
||||
// Let it run briefly
|
||||
time.Sleep(20 * time.Millisecond)
|
||||
cancel()
|
||||
// No panic or deadlock expected
|
||||
}
|
||||
|
||||
// patchClientHTTP replaces the HTTPClient's transport with a test server
|
||||
func patchClientHTTP(c *client.Client, handler http.HandlerFunc) {
|
||||
ts := httptest.NewServer(handler)
|
||||
c.HTTPClient.SetBaseURL(ts.URL)
|
||||
}
|
||||
|
||||
func TestClient_KeepAlive_Success(t *testing.T) {
|
||||
logger := mockLogger()
|
||||
creds := mockCredentials()
|
||||
c, err := client.New(creds, logger)
|
||||
if err != nil {
|
||||
t.Fatalf("New() error: %v", err)
|
||||
}
|
||||
|
||||
patchClientHTTP(c, func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(keepAliveResponse))
|
||||
})
|
||||
|
||||
err = c.KeepAlive()
|
||||
if err != nil {
|
||||
t.Errorf("KeepAlive() error = %v, want nil", err)
|
||||
}
|
||||
if !c.IsAlive() {
|
||||
t.Error("expected client to be alive after successful KeepAlive")
|
||||
}
|
||||
// Check if IAR is set
|
||||
if c.IAR.PagerGroupID != "672783715f6ed07deb857afb" {
|
||||
t.Errorf("expected PagerGroupID to be set, got %s", c.IAR.PagerGroupID)
|
||||
}
|
||||
// Check if KeepAlive duration is set from API response (900 seconds = 15 minutes)
|
||||
expectedDuration := 900 * time.Second
|
||||
if c.IAR.KeepAlive != expectedDuration {
|
||||
t.Errorf("expected KeepAlive duration to be %v, got %v", expectedDuration, c.IAR.KeepAlive)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClient_KeepAlive_Failure(t *testing.T) {
|
||||
logger := mockLogger()
|
||||
creds := mockCredentials()
|
||||
c, err := client.New(creds, logger)
|
||||
if err != nil {
|
||||
t.Fatalf("New() error: %v", err)
|
||||
}
|
||||
|
||||
patchClientHTTP(c, func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(`{"error": "fail"}`))
|
||||
})
|
||||
|
||||
err = c.KeepAlive()
|
||||
if err == nil {
|
||||
t.Error("expected error from KeepAlive, got nil")
|
||||
}
|
||||
if c.IsAlive() {
|
||||
t.Error("expected client to not be alive after failed KeepAlive")
|
||||
}
|
||||
}
|
||||
|
||||
func TestClient_PreAlert_Success(t *testing.T) {
|
||||
logger := mockLogger()
|
||||
creds := mockCredentials()
|
||||
c, err := client.New(creds, logger)
|
||||
if err != nil {
|
||||
t.Fatalf("New() error: %v", err)
|
||||
}
|
||||
// Set IAR
|
||||
c.IAR.PagerGroupID = "test_group"
|
||||
|
||||
patchClientHTTP(c, func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(preAlertResponse))
|
||||
})
|
||||
|
||||
alertID, err := c.PreAlert()
|
||||
if err != nil {
|
||||
t.Errorf("PreAlert() error = %v, want nil", err)
|
||||
}
|
||||
expectedID := "68bb90e0b91373858dd8f214"
|
||||
if alertID != expectedID {
|
||||
t.Errorf("expected alertID %s, got %s", expectedID, alertID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClient_Alert_Success(t *testing.T) {
|
||||
logger := mockLogger()
|
||||
creds := mockCredentials()
|
||||
c, err := client.New(creds, logger)
|
||||
if err != nil {
|
||||
t.Fatalf("New() error: %v", err)
|
||||
}
|
||||
// Set IAR
|
||||
c.IAR.PagerGroupID = "test_group"
|
||||
|
||||
callCount := 0
|
||||
patchClientHTTP(c, func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
if callCount == 0 {
|
||||
// First call is preAlert
|
||||
w.Write([]byte(preAlertResponse))
|
||||
} else {
|
||||
// Second call is Alert
|
||||
w.Write([]byte(alertResponse))
|
||||
}
|
||||
callCount++
|
||||
})
|
||||
|
||||
err = c.Alert("base64_audio")
|
||||
if err != nil {
|
||||
t.Errorf("Alert() error = %v, want nil", err)
|
||||
}
|
||||
if callCount != 2 {
|
||||
t.Errorf("expected 2 HTTP calls, got %d", callCount)
|
||||
}
|
||||
}
|
||||
|
@@ -30,7 +30,7 @@ type PagerGroup struct {
|
||||
|
||||
type TTDSetting struct {
|
||||
KeySetting string `json:"keySetting"`
|
||||
KeyValue string `json:"keyValue"`
|
||||
KeyValue int `json:"keyValue,string"`
|
||||
}
|
||||
|
||||
type AddAlert struct {
|
||||
|
6
main.go
6
main.go
@@ -70,14 +70,14 @@ func main() {
|
||||
// Start directory watcher in a goroutine
|
||||
go watcher.WatchDirectory(ctx, config.Directory, eb, logger)
|
||||
|
||||
// Start keep-alive sender in a goroutine
|
||||
go iar.ServeKeepAlive(ctx, 15*time.Minute)
|
||||
|
||||
err = iar.KeepAlive()
|
||||
if err != nil {
|
||||
slog.Error("Initial keep-alive failed", "error", err)
|
||||
}
|
||||
|
||||
// Start keep-alive sender in a goroutine
|
||||
go iar.ServeKeepAlive(ctx)
|
||||
|
||||
// Handle OS signals for shutdown
|
||||
sigCh := make(chan os.Signal, 1)
|
||||
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
|
||||
|
Reference in New Issue
Block a user