job-search no longer has a fetch command. Its subcommands are now in cmd/fetcher, which reads the same configuration: "fetcher service" runs every enabled source's fetcher on its interval until stopped, and "fetcher fts-once" (was "fetch once") fetches from Find a Tender once and prints the releases as JSON. The new namea say what the commands do, because service runs every source while fts-once fetches only from Find a Tender. The code stays in internal/cli/fetch, where NewCommands replaces the fetch parent command. once.go is now fts_once.go and commandOnce is commandFTSOnce. The README's usage, the config README and the find_a_tender api_root comment now give the new command names.
67 lines
1.6 KiB
Go
67 lines
1.6 KiB
Go
package fetch
|
|
|
|
import (
|
|
"io"
|
|
"slices"
|
|
"strings"
|
|
"testing"
|
|
|
|
"git.avsdev.uk/Go/job-search/internal/cli"
|
|
"git.avsdev.uk/Go/job-search/internal/types"
|
|
)
|
|
|
|
// opp makes an opportunity whose releases, oldest first, have these tags.
|
|
func opp(uuid string, tags ...string) *types.Opportunity {
|
|
o := &types.Opportunity{
|
|
UUID: uuid,
|
|
}
|
|
for _, tag := range tags {
|
|
o.Releases = append(o.Releases, types.OpportunityRelease{
|
|
Tags: []types.OpportunityReleaseTag{{
|
|
Tag: tag,
|
|
}},
|
|
})
|
|
}
|
|
return o
|
|
}
|
|
|
|
func TestFilter(t *testing.T) {
|
|
opps := []*types.Opportunity{
|
|
opp("planned", "planning"),
|
|
opp("open", "planning", "tender"),
|
|
opp("extended", "tender", "tenderUpdate"),
|
|
opp("awarded", "planning", "tender", "award"),
|
|
opp("cancelled", "tender", "tenderCancellation"),
|
|
opp("no releases"),
|
|
}
|
|
tests := map[string][]string{
|
|
"planning": {"planned"},
|
|
"opportunity": {"open", "extended"},
|
|
"award": {"awarded"},
|
|
}
|
|
for stage, want := range tests {
|
|
t.Run(stage, func(t *testing.T) {
|
|
var got []string
|
|
for _, o := range filter(opps, stage) {
|
|
got = append(got, o.UUID)
|
|
}
|
|
if !slices.Equal(got, want) {
|
|
t.Errorf("filter(%s) = %v; want %v", stage, got, want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// Conflicting filters are rejected by cobra before anything is fetched.
|
|
func TestOnceFiltersExclusive(t *testing.T) {
|
|
cmd := commandFTSOnce(&cli.Options{})
|
|
cmd.SetArgs([]string{"--planning", "--awards"})
|
|
cmd.SetOut(io.Discard)
|
|
cmd.SetErr(io.Discard)
|
|
|
|
err := cmd.Execute()
|
|
if err == nil || !strings.Contains(err.Error(), "none of the others can be") {
|
|
t.Fatalf("err = %v; want a mutually exclusive flags error", err)
|
|
}
|
|
}
|