go-finger/internal/webfinger/webfinger_test.go

445 lines
10 KiB
Go
Raw Normal View History

2023-09-20 01:26:38 -03:00
package webfinger_test
import (
"context"
"encoding/json"
"os"
"reflect"
"sort"
"strings"
"testing"
"git.maronato.dev/maronato/finger/internal/config"
"git.maronato.dev/maronato/finger/internal/log"
"git.maronato.dev/maronato/finger/internal/webfinger"
)
func newTempFile(t *testing.T, content string) (name string, remove func()) {
t.Helper()
f, err := os.CreateTemp("", "finger-test")
if err != nil {
t.Fatalf("error creating temp file: %v", err)
}
_, err = f.WriteString(content)
if err != nil {
t.Fatalf("error writing to temp file: %v", err)
}
return f.Name(), func() {
err = os.Remove(f.Name())
if err != nil {
t.Fatalf("error removing temp file: %v", err)
}
}
}
func TestNewFingerReader(t *testing.T) {
t.Parallel()
f := webfinger.NewFingerReader()
if f == nil {
t.Errorf("NewFingerReader() = %v, want: %v", f, nil)
}
}
func TestFingerReader_ReadFiles(t *testing.T) {
t.Parallel()
tests := []struct {
name string
urnsContent string
fingersContent string
useURNFile bool
useFingerFile bool
wantErr bool
}{
{
name: "reads files",
urnsContent: "name: https://schema/name\nprofile: https://schema/profile",
fingersContent: "user@example.com:\n name: John Doe",
useURNFile: true,
useFingerFile: true,
wantErr: false,
},
{
name: "errors on missing URNs file",
urnsContent: "invalid",
fingersContent: "user@example.com:\n name: John Doe",
useURNFile: false,
useFingerFile: true,
wantErr: true,
},
{
name: "errors on missing fingers file",
urnsContent: "name: https://schema/name\nprofile: https://schema/profile",
fingersContent: "invalid",
useFingerFile: false,
useURNFile: true,
wantErr: true,
},
}
for _, tt := range tests {
tc := tt
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
cfg := config.NewConfig()
urnsFileName, urnsCleanup := newTempFile(t, tc.urnsContent)
defer urnsCleanup()
fingersFileName, fingersCleanup := newTempFile(t, tc.fingersContent)
defer fingersCleanup()
if !tc.useURNFile {
cfg.URNPath = "invalid"
} else {
cfg.URNPath = urnsFileName
}
if !tc.useFingerFile {
cfg.FingerPath = "invalid"
} else {
cfg.FingerPath = fingersFileName
}
f := webfinger.NewFingerReader()
err := f.ReadFiles(cfg)
if err != nil {
if !tc.wantErr {
t.Errorf("ReadFiles() error = %v", err)
}
return
} else if tc.wantErr {
t.Errorf("ReadFiles() error = %v, wantErr %v", err, tc.wantErr)
}
if !reflect.DeepEqual(f.URNSFile, []byte(tc.urnsContent)) {
t.Errorf("ReadFiles() URNsFile = %v, want: %v", f.URNSFile, tc.urnsContent)
}
if !reflect.DeepEqual(f.FingersFile, []byte(tc.fingersContent)) {
t.Errorf("ReadFiles() FingersFile = %v, want: %v", f.FingersFile, tc.fingersContent)
}
})
}
}
func TestParseFingers(t *testing.T) {
t.Parallel()
tests := []struct {
name string
rawFingers webfinger.RawFingersMap
want webfinger.WebFingers
wantErr bool
}{
{
name: "parses links",
rawFingers: webfinger.RawFingersMap{
"user@example.com": {
"profile": "https://example.com/profile",
"invalidalias": "https://example.com/invalidalias",
"https://something": "https://somethingelse",
},
},
want: webfinger.WebFingers{
"acct:user@example.com": {
Subject: "acct:user@example.com",
Links: []webfinger.Link{
{
Rel: "https://schema/profile",
Href: "https://example.com/profile",
},
{
Rel: "invalidalias",
Href: "https://example.com/invalidalias",
},
{
Rel: "https://something",
Href: "https://somethingelse",
},
},
},
},
wantErr: false,
},
{
name: "parses properties",
rawFingers: webfinger.RawFingersMap{
"user@example.com": {
"name": "John Doe",
"invalidalias": "value1",
"https://mylink": "value2",
},
},
want: webfinger.WebFingers{
"acct:user@example.com": {
Subject: "acct:user@example.com",
Properties: map[string]string{
"https://schema/name": "John Doe",
"invalidalias": "value1",
"https://mylink": "value2",
},
},
},
wantErr: false,
},
{
name: "accepts acct: prefix",
rawFingers: webfinger.RawFingersMap{
"acct:user@example.com": {
"name": "John Doe",
},
},
want: webfinger.WebFingers{
"acct:user@example.com": {
Subject: "acct:user@example.com",
Properties: map[string]string{
"https://schema/name": "John Doe",
},
},
},
wantErr: false,
},
{
name: "accepts urls as resource",
rawFingers: webfinger.RawFingersMap{
"https://example.com": {
"name": "John Doe",
},
},
want: webfinger.WebFingers{
"https://example.com": {
Subject: "https://example.com",
Properties: map[string]string{
"https://schema/name": "John Doe",
},
},
},
wantErr: false,
},
{
name: "accepts multiple resources",
rawFingers: webfinger.RawFingersMap{
"user@example.com": {
"name": "John Doe",
},
"other@example.com": {
"name": "Jane Doe",
},
},
want: webfinger.WebFingers{
"acct:user@example.com": {
Subject: "acct:user@example.com",
Properties: map[string]string{
"https://schema/name": "John Doe",
},
},
"acct:other@example.com": {
Subject: "acct:other@example.com",
Properties: map[string]string{
"https://schema/name": "Jane Doe",
},
},
},
wantErr: false,
},
{
name: "errors on invalid resource",
rawFingers: webfinger.RawFingersMap{
"invalid": {
"name": "John Doe",
},
},
want: nil,
wantErr: true,
},
}
for _, tt := range tests {
tc := tt
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
// Create a urn map
urns := webfinger.URNMap{
"name": "https://schema/name",
"profile": "https://schema/profile",
}
ctx := context.Background()
cfg := config.NewConfig()
l := log.NewLogger(&strings.Builder{}, cfg)
ctx = log.WithLogger(ctx, l)
f := webfinger.NewFingerReader()
got, err := f.ParseFingers(ctx, urns, tc.rawFingers)
if (err != nil) != tc.wantErr {
t.Errorf("ParseFingers() error = %v, wantErr %v", err, tc.wantErr)
return
}
// Sort links to make it easier to compare
for _, v := range got {
for range v.Links {
sort.Slice(v.Links, func(i, j int) bool {
return v.Links[i].Rel < v.Links[j].Rel
})
}
}
for _, v := range tc.want {
for range v.Links {
sort.Slice(v.Links, func(i, j int) bool {
return v.Links[i].Rel < v.Links[j].Rel
})
}
}
if !reflect.DeepEqual(got, tc.want) {
// Unmarshal the structs to JSON to make it easier to print
gotstr := &strings.Builder{}
gotenc := json.NewEncoder(gotstr)
wantstr := &strings.Builder{}
wantenc := json.NewEncoder(wantstr)
_ = gotenc.Encode(got)
_ = wantenc.Encode(tc.want)
t.Errorf("ParseFingers() got = \n%s want: \n%s", gotstr.String(), wantstr.String())
}
})
}
}
func TestReadFingerFile(t *testing.T) {
t.Parallel()
tests := []struct {
name string
urnsContent string
fingersContent string
wantURN webfinger.URNMap
wantFinger webfinger.RawFingersMap
returns *webfinger.WebFingers
wantErr bool
}{
{
name: "reads files",
urnsContent: "name: https://schema/name\nprofile: https://schema/profile",
fingersContent: "user@example.com:\n name: John Doe",
wantURN: webfinger.URNMap{
"name": "https://schema/name",
"profile": "https://schema/profile",
},
wantFinger: webfinger.RawFingersMap{
"user@example.com": {
"name": "John Doe",
},
},
returns: &webfinger.WebFingers{
"acct:user@example.com": {
Subject: "acct:user@example.com",
Properties: map[string]string{
"https://schema/name": "John Doe",
},
},
},
wantErr: false,
},
{
name: "uses custom URNs",
urnsContent: "favorite_food: https://schema/favorite_food",
fingersContent: "user@example.com:\n favorite_food: Apple",
wantURN: webfinger.URNMap{
"favorite_food": "https://schema/favorite_food",
},
wantFinger: webfinger.RawFingersMap{
"user@example.com": {
"https://schema/favorite_food": "Apple",
},
},
wantErr: false,
},
{
name: "errors on invalid URNs file",
urnsContent: "invalid",
fingersContent: "user@example.com:\n name: John Doe",
wantURN: webfinger.URNMap{},
wantFinger: webfinger.RawFingersMap{},
wantErr: true,
},
{
name: "errors on invalid fingers file",
urnsContent: "name: https://schema/name\nprofile: https://schema/profile",
fingersContent: "invalid",
wantURN: webfinger.URNMap{},
wantFinger: webfinger.RawFingersMap{},
wantErr: true,
},
{
name: "errors on invalid URNs values",
urnsContent: "name: invalid",
fingersContent: "user@example.com:\n name: John Doe",
wantURN: webfinger.URNMap{},
wantFinger: webfinger.RawFingersMap{},
wantErr: true,
},
{
name: "errors on invalid fingers values",
urnsContent: "name: https://schema/name\nprofile: https://schema/profile",
fingersContent: "invalid:\n name: John Doe",
wantURN: webfinger.URNMap{},
wantFinger: webfinger.RawFingersMap{},
wantErr: true,
},
}
for _, tt := range tests {
tc := tt
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
ctx := context.Background()
cfg := config.NewConfig()
l := log.NewLogger(&strings.Builder{}, cfg)
ctx = log.WithLogger(ctx, l)
f := webfinger.NewFingerReader()
f.FingersFile = []byte(tc.fingersContent)
f.URNSFile = []byte(tc.urnsContent)
got, err := f.ReadFingerFile(ctx)
if err != nil {
if !tc.wantErr {
t.Errorf("ReadFingerFile() error = %v", err)
}
return
} else if tc.wantErr {
t.Errorf("ReadFingerFile() error = %v, wantErr %v", err, tc.wantErr)
}
if tc.returns != nil && !reflect.DeepEqual(got, *tc.returns) {
t.Errorf("ReadFingerFile() got = %v, want: %v", got, *tc.returns)
}
})
}
}