mattermost-plugin-shelfmark/server/configuration_test.go
Felipe M. 98f5c6d446
Fix concurrency bugs, error handling, and add comprehensive unit tests
Address 18 issues identified in codebase review:

- Fix doRequest body consumed on 401 retry by accepting []byte instead of io.Reader
- Fix race condition on httpClient.Timeout in DownloadFile using context.WithTimeout
- Fix data race on baseURL read in doRequest by reading under mutex
- Add sync.Mutex to taskStore for atomic index operations
- Replace all silent `_ = SaveTask()` calls with proper error logging via failTask helper
- Add notifyRequester calls to all processTaskComplete failure paths
- Mark missing Shelfmark tasks as failed instead of optimistically promoting to complete
- Remove goto in processTaskPending with structured control flow
- Validate ShelfmarkHost URL scheme in IsValid()
- Call IsValid() in OnConfigurationChange to warn on invalid config
- Guard ExecuteCommand against empty command panic
- Add EffectiveTitle() method on DownloadTask to deduplicate title fallback
- Add shelfmarkCredentials() to deduplicate TrimSpace calls
- Log ReleasesResponse.Errors when non-empty
- Batch-delete terminal tasks in ListActiveTasks instead of during iteration
- Log GetTask errors in ListActiveTasks instead of silently skipping
- Properly handle resp.Body.Close() errors throughout shelfmark client
- Add 93 unit tests across 8 new test files covering all packages

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 17:17:38 +01:00

139 lines
3.1 KiB
Go

package main
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestIsValid(t *testing.T) {
tests := []struct {
name string
config configuration
wantErr string
}{
{
name: "valid configuration",
config: configuration{
ShelfmarkHost: "http://shelfmark:8084",
ChannelID: "channel123",
},
},
{
name: "valid https",
config: configuration{
ShelfmarkHost: "https://shelfmark.example.com",
ChannelID: "channel123",
},
},
{
name: "missing host",
config: configuration{
ShelfmarkHost: "",
ChannelID: "channel123",
},
wantErr: "shelfmark server URL must be configured",
},
{
name: "whitespace-only host",
config: configuration{
ShelfmarkHost: " ",
ChannelID: "channel123",
},
wantErr: "shelfmark server URL must be configured",
},
{
name: "host without scheme",
config: configuration{
ShelfmarkHost: "shelfmark:8084",
ChannelID: "channel123",
},
wantErr: "shelfmark server URL must start with http:// or https://",
},
{
name: "missing channel",
config: configuration{
ShelfmarkHost: "http://shelfmark:8084",
ChannelID: "",
},
wantErr: "channel ID must be configured",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := tt.config.IsValid()
if tt.wantErr == "" {
require.NoError(t, err)
} else {
require.Error(t, err)
assert.Contains(t, err.Error(), tt.wantErr)
}
})
}
}
func TestGetDefaultLanguage(t *testing.T) {
tests := []struct {
name string
value string
expected string
}{
{"empty", "", ""},
{"whitespace", " ", ""},
{"en", "en", "en"},
{"trimmed", " es ", "es"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
c := &configuration{DefaultLanguage: tt.value}
assert.Equal(t, tt.expected, c.getDefaultLanguage())
})
}
}
func TestGetPostTemplate(t *testing.T) {
t.Run("empty returns default", func(t *testing.T) {
c := &configuration{PostTemplate: ""}
assert.Equal(t, "### {{.Title}}", c.getPostTemplate())
})
t.Run("whitespace returns default", func(t *testing.T) {
c := &configuration{PostTemplate: " "}
assert.Equal(t, "### {{.Title}}", c.getPostTemplate())
})
t.Run("custom value returned", func(t *testing.T) {
c := &configuration{PostTemplate: "**{{.Title}}** by {{.AuthorsList}}"}
assert.Equal(t, "**{{.Title}}** by {{.AuthorsList}}", c.getPostTemplate())
})
}
func TestClone(t *testing.T) {
original := &configuration{
ShelfmarkHost: "http://example.com",
ChannelID: "ch1",
}
clone := original.Clone()
clone.ShelfmarkHost = "http://other.com"
clone.ChannelID = "ch2"
assert.Equal(t, "http://example.com", original.ShelfmarkHost)
assert.Equal(t, "ch1", original.ChannelID)
}
func TestShelfmarkCredentials(t *testing.T) {
c := &configuration{
ShelfmarkHost: " http://example.com ",
ShelfmarkUsername: " user ",
ShelfmarkPassword: " pass ",
}
host, username, password := c.shelfmarkCredentials()
assert.Equal(t, "http://example.com", host)
assert.Equal(t, "user", username)
assert.Equal(t, "pass", password)
}