~bigbes/sr-ht-spec

ref: e756d504ebc789e9e88f9bdd175d57afd4c87439 sr-ht-spec/service/service_test.go -rw-r--r-- 3.8 KiB
e756d504 — Eugene Blikh web: draw the whole web tier from sr-ht-ecore 9 days ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package service

import (
	"errors"
	"strings"
	"testing"
	"time"
)

func TestLoadConfigAcceptsACompleteConfig(t *testing.T) {
	cfg, err := LoadConfig(testIni(t, "/var/lib/spec"))
	if err != nil {
		t.Fatalf("LoadConfig: %v", err)
	}
	if cfg.Repos != "/var/lib/spec" || cfg.Cache != "/var/cache/spec" {
		t.Errorf("paths = %q, %q", cfg.Repos, cfg.Cache)
	}
	if cfg.Origin != "https://spec.srht.bigb.es" {
		t.Errorf("origin = %q", cfg.Origin)
	}
	if cfg.Instance.AgentEmail != "agent@spec.srht.bigb.es" {
		t.Errorf("agent email = %q, want it derived from our own origin", cfg.Instance.AgentEmail)
	}
	if cfg.Instance.OwnerName != "bigbes" {
		t.Errorf("owner = %q", cfg.Instance.OwnerName)
	}
}

func TestLoadConfigTrimsTheOriginsTrailingSlash(t *testing.T) {
	conf := testIni(t, "/var/lib/spec", "origin")
	conf["spec.sr.ht"]["origin"] = "https://spec.srht.bigb.es/"
	cfg, err := LoadConfig(conf)
	if err != nil {
		t.Fatalf("LoadConfig: %v", err)
	}
	if cfg.Origin != "https://spec.srht.bigb.es" {
		t.Errorf("origin = %q, want the trailing slash gone", cfg.Origin)
	}
}

// Every missing key must be named in one message: an operator fixes the config
// in one pass instead of discovering each gap on a separate restart.
func TestLoadConfigNamesEveryMissingKeyAtOnce(t *testing.T) {
	conf := testIni(t, "/var/lib/spec", "repos", "cache", "owner-email")
	_, err := LoadConfig(conf)
	if !errors.Is(err, ErrIncompleteConfig) {
		t.Fatalf("err = %v, want ErrIncompleteConfig", err)
	}
	for _, want := range []string{"[spec.sr.ht] repos", "[spec.sr.ht] cache", "[sr.ht] owner-email"} {
		if !strings.Contains(err.Error(), want) {
			t.Errorf("message does not name %q:\n%s", want, err)
		}
	}
	if strings.Contains(err.Error(), "connection-string") {
		t.Errorf("message names a key that was present:\n%s", err)
	}
}

func TestLoadConfigRejectsUnusableValues(t *testing.T) {
	tests := []struct {
		name    string
		section string
		key     string
		value   string
		want    string
	}{
		{"relative repos", ConfigSection, "repos", "spec", "absolute path"},
		{"relative cache", ConfigSection, "cache", "./cache", "absolute path"},
		{"origin with no host", ConfigSection, "origin", "spec.srht.bigb.es", "no host"},
		{"origin with a bad scheme", ConfigSection, "origin", "ftp://spec.srht.bigb.es", "http or https"},
		{"blank owner", "sr.ht", "owner-name", "   ", "[sr.ht] owner-name"},
	}
	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			conf := testIni(t, "/var/lib/spec", tc.key)
			conf[tc.section][tc.key] = tc.value
			_, err := LoadConfig(conf)
			if !errors.Is(err, ErrIncompleteConfig) {
				t.Fatalf("err = %v, want ErrIncompleteConfig", err)
			}
			if !strings.Contains(err.Error(), tc.want) {
				t.Errorf("message does not mention %q:\n%s", tc.want, err)
			}
		})
	}
}

// A nil handle would make every agent token resolve as unknown, which looks
// exactly like a mass revocation.
func TestNewRefusesANilDatabaseHandle(t *testing.T) {
	if _, err := New(testConfig(t, t.TempDir()), nil); err == nil {
		t.Fatal("New with a nil handle succeeded")
	}
}

func TestNewValidatesTheConfig(t *testing.T) {
	cfg := testConfig(t, "relative/path")
	if _, err := New(cfg, deadDB(t)); !errors.Is(err, ErrIncompleteConfig) {
		t.Fatalf("err = %v, want ErrIncompleteConfig", err)
	}
}

func TestServiceExposesItsWiring(t *testing.T) {
	svc, root := newService(t)
	if svc.ReposRoot() != root {
		t.Errorf("ReposRoot = %q, want %q", svc.ReposRoot(), root)
	}
	if svc.Origin() != "https://spec.srht.bigb.es" {
		t.Errorf("Origin = %q", svc.Origin())
	}
	if svc.Resolver() == nil || svc.Resolver().Owner() != "bigbes" {
		t.Errorf("resolver = %v", svc.Resolver())
	}
	if svc.Store() == nil {
		t.Error("store is nil")
	}
	if svc.grace != DefaultReconcileGrace || svc.now == nil {
		t.Errorf("reconciler defaults not wired: grace=%v", svc.grace)
	}
	var _ time.Duration = DefaultReconcileInterval
}