Add four new infrastructure packages with CLI commands: - pkg/config: layered configuration (defaults → file → env → flags) - pkg/crypt: crypto primitives (Argon2id, AES-GCM, ChaCha20, HMAC, checksums) - pkg/plugin: plugin system with GitHub-based install/update/remove - pkg/collect: collection subsystem (GitHub, BitcoinTalk, market, papers, excavate) Fix all golangci-lint issues across the entire codebase (~100 errcheck, staticcheck SA1012/SA1019/ST1005, unused, ineffassign fixes) so that `core go qa` passes with 0 issues. Closes #167, #168, #170, #250, #251, #252, #253, #254, #255, #256 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
144 lines
3.1 KiB
Go
144 lines
3.1 KiB
Go
package collect
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/host-uk/core/pkg/io"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestState_SetGet_Good(t *testing.T) {
|
|
m := io.NewMockMedium()
|
|
s := NewState(m, "/state.json")
|
|
|
|
entry := &StateEntry{
|
|
Source: "github:test",
|
|
LastRun: time.Now(),
|
|
Items: 42,
|
|
LastID: "abc123",
|
|
Cursor: "cursor-xyz",
|
|
}
|
|
|
|
s.Set("github:test", entry)
|
|
|
|
got, ok := s.Get("github:test")
|
|
assert.True(t, ok)
|
|
assert.Equal(t, entry.Source, got.Source)
|
|
assert.Equal(t, entry.Items, got.Items)
|
|
assert.Equal(t, entry.LastID, got.LastID)
|
|
assert.Equal(t, entry.Cursor, got.Cursor)
|
|
}
|
|
|
|
func TestState_Get_Bad(t *testing.T) {
|
|
m := io.NewMockMedium()
|
|
s := NewState(m, "/state.json")
|
|
|
|
got, ok := s.Get("nonexistent")
|
|
assert.False(t, ok)
|
|
assert.Nil(t, got)
|
|
}
|
|
|
|
func TestState_SaveLoad_Good(t *testing.T) {
|
|
m := io.NewMockMedium()
|
|
s := NewState(m, "/state.json")
|
|
|
|
now := time.Date(2025, 1, 15, 10, 30, 0, 0, time.UTC)
|
|
entry := &StateEntry{
|
|
Source: "market:bitcoin",
|
|
LastRun: now,
|
|
Items: 100,
|
|
LastID: "btc-100",
|
|
}
|
|
|
|
s.Set("market:bitcoin", entry)
|
|
|
|
// Save state
|
|
err := s.Save()
|
|
assert.NoError(t, err)
|
|
|
|
// Verify file was written
|
|
assert.True(t, m.IsFile("/state.json"))
|
|
|
|
// Load into a new state instance
|
|
s2 := NewState(m, "/state.json")
|
|
err = s2.Load()
|
|
assert.NoError(t, err)
|
|
|
|
got, ok := s2.Get("market:bitcoin")
|
|
assert.True(t, ok)
|
|
assert.Equal(t, "market:bitcoin", got.Source)
|
|
assert.Equal(t, 100, got.Items)
|
|
assert.Equal(t, "btc-100", got.LastID)
|
|
assert.True(t, now.Equal(got.LastRun))
|
|
}
|
|
|
|
func TestState_Load_Good_NoFile(t *testing.T) {
|
|
m := io.NewMockMedium()
|
|
s := NewState(m, "/nonexistent.json")
|
|
|
|
// Loading when no file exists should not error
|
|
err := s.Load()
|
|
assert.NoError(t, err)
|
|
|
|
// State should be empty
|
|
_, ok := s.Get("anything")
|
|
assert.False(t, ok)
|
|
}
|
|
|
|
func TestState_Load_Bad_InvalidJSON(t *testing.T) {
|
|
m := io.NewMockMedium()
|
|
m.Files["/state.json"] = "not valid json"
|
|
|
|
s := NewState(m, "/state.json")
|
|
err := s.Load()
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func TestState_SaveLoad_Good_MultipleEntries(t *testing.T) {
|
|
m := io.NewMockMedium()
|
|
s := NewState(m, "/state.json")
|
|
|
|
s.Set("source-a", &StateEntry{Source: "source-a", Items: 10})
|
|
s.Set("source-b", &StateEntry{Source: "source-b", Items: 20})
|
|
s.Set("source-c", &StateEntry{Source: "source-c", Items: 30})
|
|
|
|
err := s.Save()
|
|
assert.NoError(t, err)
|
|
|
|
s2 := NewState(m, "/state.json")
|
|
err = s2.Load()
|
|
assert.NoError(t, err)
|
|
|
|
a, ok := s2.Get("source-a")
|
|
assert.True(t, ok)
|
|
assert.Equal(t, 10, a.Items)
|
|
|
|
b, ok := s2.Get("source-b")
|
|
assert.True(t, ok)
|
|
assert.Equal(t, 20, b.Items)
|
|
|
|
c, ok := s2.Get("source-c")
|
|
assert.True(t, ok)
|
|
assert.Equal(t, 30, c.Items)
|
|
}
|
|
|
|
func TestState_Set_Good_Overwrite(t *testing.T) {
|
|
m := io.NewMockMedium()
|
|
s := NewState(m, "/state.json")
|
|
|
|
s.Set("source", &StateEntry{Source: "source", Items: 5})
|
|
s.Set("source", &StateEntry{Source: "source", Items: 15})
|
|
|
|
got, ok := s.Get("source")
|
|
assert.True(t, ok)
|
|
assert.Equal(t, 15, got.Items)
|
|
}
|
|
|
|
func TestNewState_Good(t *testing.T) {
|
|
m := io.NewMockMedium()
|
|
s := NewState(m, "/test/state.json")
|
|
|
|
assert.NotNil(t, s)
|
|
assert.NotNil(t, s.entries)
|
|
}
|