Skip to content
quarry Artifact [12fcc8280d]
Login

Artifact [12fcc8280d]

Artifact 12fcc8280d2dce560221561bcd9cd592a322b108383eeb84c8335bdcb1cf48ec:


package web

import (
	"net/http"
	"net/http/httptest"
	"net/url"
	"strings"
	"testing"

	"craftdesign.group/quarry/internal/api"
	"craftdesign.group/quarry/internal/oltp"
	"craftdesign.group/quarry/internal/ops"
	"craftdesign.group/quarry/internal/xfer"
)

type webFossilUsers struct {
	users   []oltp.FossilUser
	links   map[string]string
	fetched int
}

func (m *webFossilUsers) ReplaceFossilUsers(_ string, u []oltp.FossilUser) (int, int, error) {
	m.users = u
	return len(u), 0, nil
}
func (m *webFossilUsers) FossilUsers(string) ([]oltp.FossilUser, error) { return m.users, nil }
func (m *webFossilUsers) LinkFossilUser(_, _, login, account string) (string, error) {
	m.links[login] = account
	for i := range m.users {
		if m.users[i].Login == login {
			m.users[i].Linked, m.users[i].Suggest = account, false
		}
	}
	return "", nil
}

func fossilUsersServer(t *testing.T, plane *memCaps, store *webFossilUsers) *httptest.Server {
	t.Helper()
	r := ops.NewRegistry()
	if err := api.RegisterAll(r, api.Deps{Version: "v",
		Repos:       api.NewRepos(map[string]*api.Repo{"alpha": {Index: landingIndex(t, false)}}),
		Roster:      capsRoster{plane},
		FossilUsers: store,
		ProjectCode: func(string) (string, error) { return "code", nil },
		FetchUsers: func(string, string, string, string) ([]xfer.RemoteUser, error) {
			store.fetched++
			return nil, nil
		}}); err != nil {
		t.Fatal(err)
	}
	srv := httptest.NewServer(HandlerWith(r, nil, nil, []Option{
		WithSessions(fakeSessions{user: "dan", roles: map[string]ops.Auth{"alpha": ops.Admin}}),
		WithCaps(plane)}))
	t.Cleanup(srv.Close)
	return srv
}

// Advanced lists the synced users; a matching name is suggested, a
// linked account shows on People as coming from fossil.
func TestSettingsListFossilUsersAndMarkLinkedPeople(t *testing.T) {
	plane := &memCaps{stored: map[string]string{"dan": "a", "al": "i"}}
	store := &webFossilUsers{links: map[string]string{}, users: []oltp.FossilUser{
		{Login: "alice", Caps: "i", Linked: "al"},
		{Login: "bob", Caps: "k", Suggest: true},
	}}
	body := asDan(t, fossilUsersServer(t, plane, store), "/r/alpha/settings")
	for _, hook := range []string{`data-hook="fossil-users"`, `data-login="alice"`, `data-hook="fossil-suggest"`, `data-hook="from-fossil"`} {
		if !strings.Contains(body, hook) {
			t.Errorf("settings lack %s", hook)
		}
	}
	if strings.Contains(body, `name="password" value=`) {
		t.Error("the password field is prefilled")
	}
}

// A repository admin cannot aim the server at another host; the refusal
// comes back to the block, and nothing is fetched.
func TestFossilUserSyncFormCarriesTheRefusal(t *testing.T) {
	plane := &memCaps{stored: map[string]string{"dan": "a"}}
	store := &webFossilUsers{links: map[string]string{}}
	srv := fossilUsersServer(t, plane, store)
	resp := postAsDan(t, srv, "/r/alpha/settings/fossil-users", url.Values{
		"url": {"http://127.0.0.1:4222/"}, "login": {"root"}, "password": {"pw"}})
	if resp.StatusCode != http.StatusSeeOther || !strings.Contains(resp.Header.Get("Location"), "fe=") {
		t.Fatalf("status %d, location %q", resp.StatusCode, resp.Header.Get("Location"))
	}
	if strings.Contains(resp.Header.Get("Location"), "pw") {
		t.Fatal("the password travelled into the redirect")
	}
	if store.fetched != 0 {
		t.Fatal("a refused sync fetched")
	}
	resp = postAsDan(t, srv, "/r/alpha/settings/fossil-users/link", url.Values{"login": {"bob"}, "account": {"bob"}})
	if resp.StatusCode != http.StatusSeeOther || store.links["bob"] != "bob" {
		t.Fatalf("link: status %d, links %v", resp.StatusCode, store.links)
	}
}