2021-04-09 18:04:04 +02:00
package recv
2021-04-08 12:16:33 +02:00
import (
2021-04-09 21:00:54 +02:00
"brainbaking.com/go-jamming/app/mf"
2021-04-18 15:39:29 +02:00
"brainbaking.com/go-jamming/db"
"encoding/json"
2021-04-08 12:16:33 +02:00
"errors"
2021-04-23 09:39:49 +02:00
"github.com/rs/zerolog"
2021-04-09 10:12:14 +02:00
"github.com/stretchr/testify/assert"
2021-04-23 09:39:49 +02:00
"io/ioutil"
2021-04-11 09:50:27 +02:00
"net/http"
2021-04-08 16:37:04 +02:00
"testing"
2021-04-09 10:12:14 +02:00
"time"
2021-04-08 12:16:33 +02:00
2021-04-09 18:04:04 +02:00
"brainbaking.com/go-jamming/common"
"brainbaking.com/go-jamming/mocks"
2021-04-08 12:16:33 +02:00
)
var conf = & common . Config {
2021-04-09 21:00:54 +02:00
AllowedWebmentionSources : [ ] string {
2021-04-08 12:16:33 +02:00
"jefklakscodex.com" ,
2021-04-16 16:17:09 +02:00
"brainbaking.com" ,
2021-04-08 12:16:33 +02:00
} ,
2021-05-02 11:40:45 +02:00
Blacklist : [ ] string {
"blacklisted.com" ,
} ,
2022-04-23 11:35:53 +02:00
Whitelist : [ ] string {
"brainbaking.com" ,
"jefklakscodex.com" ,
} ,
2021-04-08 12:16:33 +02:00
}
2021-04-19 21:38:53 +02:00
func TestSaveAuthorPictureLocally ( t * testing . T ) {
cases := [ ] struct {
label string
pictureUrl string
expectedPictureUrl string
2021-04-22 16:02:59 +02:00
expectedError error
2021-04-19 21:38:53 +02:00
} {
{
"Absolute URL gets 'downloaded' and replaced by relative" ,
"https://brainbaking.com/picture.jpg" ,
"/pictures/brainbaking.com" ,
2021-04-22 16:02:59 +02:00
nil ,
2021-04-19 21:38:53 +02:00
} ,
2021-05-01 20:22:56 +02:00
{
"Refuses to download if it's from a silo domain and possibly involves GDPR privacy issues" ,
"https://brid.gy/picture.jpg" ,
"https://brid.gy/picture.jpg" ,
errWontDownloadBecauseOfPrivacy ,
} ,
2021-04-19 21:38:53 +02:00
{
2021-04-22 16:02:59 +02:00
"Absolute URL does not get replaced but error if no valid image" ,
"https://brainbaking.com/index.xml" ,
"https://brainbaking.com/index.xml" ,
errPicNoRealImage ,
} ,
{
"Absolute URL does not get replaced but error if download fails" ,
"https://brainbaking.com/thedogatemypic-nowitsmissing-shiii.png" ,
2021-04-19 21:38:53 +02:00
"https://brainbaking.com/thedogatemypic-nowitsmissing-shiii.png" ,
2021-04-22 16:02:59 +02:00
errPicUnableToDownload ,
2021-04-19 21:38:53 +02:00
} ,
}
2022-04-23 10:00:00 +02:00
t . Cleanup ( db . Purge )
2021-04-19 21:38:53 +02:00
for _ , tc := range cases {
t . Run ( tc . label , func ( t * testing . T ) {
repo := db . NewMentionRepo ( conf )
recv := & Receiver {
Conf : conf ,
Repo : repo ,
RestClient : & mocks . RestClientMock {
2021-04-23 09:39:49 +02:00
GetBodyFunc : mocks . RelPathGetBodyFunc ( "../../../mocks/" ) ,
2021-04-19 21:38:53 +02:00
} ,
}
indieweb := & mf . IndiewebData {
2021-05-01 20:22:56 +02:00
Source : tc . pictureUrl ,
2021-04-19 21:38:53 +02:00
Author : mf . IndiewebAuthor {
Picture : tc . pictureUrl ,
} ,
}
2021-04-22 16:02:59 +02:00
err := recv . saveAuthorPictureLocally ( indieweb )
2021-04-19 21:38:53 +02:00
assert . Equal ( t , tc . expectedPictureUrl , indieweb . Author . Picture )
2021-04-22 16:02:59 +02:00
assert . Equal ( t , tc . expectedError , err )
2021-04-19 21:38:53 +02:00
} )
}
}
2021-04-23 11:27:43 +02:00
func BenchmarkReceiveWithoutRestCalls ( b * testing . B ) {
2021-04-23 09:39:49 +02:00
origLog := zerolog . GlobalLevel ( )
zerolog . SetGlobalLevel ( zerolog . Disabled )
defer zerolog . SetGlobalLevel ( origLog )
wm := mf . Mention {
Source : "https://brainbaking.com/valid-indieweb-source.html" ,
Target : "https://jefklakscodex.com/articles" ,
}
data , err := ioutil . ReadFile ( "../../../mocks/valid-indieweb-source.html" )
assert . NoError ( b , err )
html := string ( data )
repo := db . NewMentionRepo ( conf )
recv := & Receiver {
Conf : conf ,
Repo : repo ,
RestClient : & mocks . RestClientMock {
GetBodyFunc : func ( s string ) ( http . Header , string , error ) {
return http . Header { } , html , nil
} ,
} ,
}
b . ReportAllocs ( )
for i := 0 ; i < b . N ; i ++ {
recv . Receive ( wm )
}
}
2021-04-09 10:12:14 +02:00
func TestReceive ( t * testing . T ) {
cases := [ ] struct {
label string
2021-04-09 14:21:25 +02:00
wm mf . Mention
2021-04-09 12:40:37 +02:00
json string
2021-04-09 21:00:54 +02:00
} {
2021-04-25 15:11:16 +02:00
{
label : "bugfix interface conversion panic unusual author part in mf" ,
wm : mf . Mention {
Source : "https://brainbaking.com/bugfix-interface-conversion-panic.html" ,
Target : "https://brainbaking.com/" ,
} ,
json : ` { "author": { "name":"Ton Zijlstra","picture":"/pictures/brainbaking.com"},"name":"","content":"De allereerste Nederlandstalige meet-up van Obsidian.md gebruikers was interessant en leuk! We waren met z’ n vieren, Sebastiaan, Wouter, Frank en ik, en spraken bijna 2 uur met elkaar. Leuk om te vergelijken waarom en hoe we notities maken in Obsid...", "name":"Nabeschouwing: de eerste Nederlandstalige Obsidian meet-up", "published":"2021-04-25T11:24:48+02:00", "source":"https://brainbaking.com/bugfix-interface-conversion-panic.html", "target":"https://brainbaking.com/", "type":"mention", "url":"https://www.zylstra.org/blog/2021/04/nabeschouwing-de-eerste-nederlandstalige-obsidian-meet-up/"} ` ,
} ,
2021-04-09 10:12:14 +02:00
{
2021-04-09 12:40:37 +02:00
label : "receive a Webmention bookmark via twitter" ,
2021-04-09 14:21:25 +02:00
wm : mf . Mention {
2021-04-09 12:40:37 +02:00
Source : "https://brainbaking.com/valid-bridgy-twitter-source.html" ,
Target : "https://brainbaking.com/post/2021/03/the-indieweb-mixed-bag" ,
2021-04-09 10:12:14 +02:00
} ,
2021-04-26 11:15:11 +02:00
json : ` { "author": { "name":"Jamie Tanna","picture":"/pictures/brainbaking.com"},"name":"","content":"Recommended read:\nThe IndieWeb Mixed Bag - Thoughts about the (d)evolution of blog interactions\nhttps://brainbaking.com/post/2021/03/the-indieweb-mixed-bag/","published":"2021-03-15T12:42:00+00:00","url":"https://brainbaking.com/mf2/2021/03/1bkre/","type":"bookmark","source":"https://brainbaking.com/valid-bridgy-twitter-source.html","target":"https://brainbaking.com/post/2021/03/the-indieweb-mixed-bag"} ` ,
2021-04-09 10:12:14 +02:00
} ,
{
2021-04-09 12:40:37 +02:00
label : "receive a brid.gy Webmention like" ,
2021-04-09 14:21:25 +02:00
wm : mf . Mention {
2021-04-09 12:40:37 +02:00
Source : "https://brainbaking.com/valid-bridgy-like.html" ,
2021-04-09 10:12:14 +02:00
// wrapped in a a class="u-like-of" tag
2021-04-09 12:40:37 +02:00
Target : "https://brainbaking.com/valid-indieweb-target.html" ,
2021-04-09 10:12:14 +02:00
} ,
// no dates in bridgy-to-mastodon likes...
2021-04-26 11:15:11 +02:00
json : ` { "author": { "name":"Stampeding Longhorn","picture":"/pictures/brainbaking.com"},"name":"","content":"","published":"2020-01-01T12:30:00+00:00","url":"https://chat.brainbaking.com/notice/A4nx1rFwKUJYSe4TqK#favorited-by-A4nwg4LYyh4WgrJOXg","type":"like","source":"https://brainbaking.com/valid-bridgy-like.html","target":"https://brainbaking.com/valid-indieweb-target.html"} ` ,
2021-04-09 10:12:14 +02:00
} ,
{
2021-04-09 12:40:37 +02:00
label : "receive a brid.gy Webmention that has a url and photo without value" ,
2021-04-09 14:21:25 +02:00
wm : mf . Mention {
2021-04-09 12:40:37 +02:00
Source : "https://brainbaking.com/valid-bridgy-source.html" ,
Target : "https://brainbaking.com/valid-indieweb-target.html" ,
2021-04-09 10:12:14 +02:00
} ,
2021-04-26 11:15:11 +02:00
json : ` { "author": { "name":"Stampeding Longhorn", "picture":"/pictures/brainbaking.com"}, "content":"@wouter The cat pictures are awesome. for jest tests!", "name":"@wouter The cat pictures are awesome. for jest tests!", "published":"2021-03-02T16:17:18+00:00", "source":"https://brainbaking.com/valid-bridgy-source.html", "target":"https://brainbaking.com/valid-indieweb-target.html", "type":"mention", "url":"https://social.linux.pizza/@StampedingLonghorn/105821099684887793"} ` ,
2021-04-09 10:12:14 +02:00
} ,
{
label : "receive saves a JSON file of indieweb-metadata if all is valid" ,
2021-04-09 14:21:25 +02:00
wm : mf . Mention {
2021-04-09 12:40:37 +02:00
Source : "https://brainbaking.com/valid-indieweb-source.html" ,
Target : "https://jefklakscodex.com/articles" ,
2021-04-09 10:12:14 +02:00
} ,
2021-04-26 11:15:11 +02:00
json : ` { "author": { "name":"Wouter Groeneveld","picture":"/pictures/brainbaking.com"},"name":"I just learned about https://www.inklestudios.com/...","content":"This is cool, I just found out about valid indieweb target - so cool","published":"2021-03-06T12:41:00+00:00","url":"https://brainbaking.com/notes/2021/03/06h12m41s48/","type":"mention","source":"https://brainbaking.com/valid-indieweb-source.html","target":"https://jefklakscodex.com/articles"} ` ,
2021-04-09 10:12:14 +02:00
} ,
{
label : "receive saves a JSON file of indieweb-metadata with summary as content if present" ,
2021-04-09 14:21:25 +02:00
wm : mf . Mention {
2021-04-09 12:40:37 +02:00
Source : "https://brainbaking.com/valid-indieweb-source-with-summary.html" ,
Target : "https://brainbaking.com/valid-indieweb-target.html" ,
2021-04-09 10:12:14 +02:00
} ,
2021-04-26 11:15:11 +02:00
json : ` { "author": { "name":"Wouter Groeneveld", "picture":"/pictures/brainbaking.com"}, "content":"This is cool, this is a summary!", "name":"I just learned about https://www.inklestudios.com/...", "published":"2021-03-06T12:41:00+00:00", "source":"https://brainbaking.com/valid-indieweb-source-with-summary.html", "target":"https://brainbaking.com/valid-indieweb-target.html", "type":"mention", "url":"https://brainbaking.com/notes/2021/03/06h12m41s48/"} ` ,
2021-04-09 10:12:14 +02:00
} ,
{
label : "receive saves a JSON file of non-indieweb-data such as title if all is valid" ,
2021-04-09 14:21:25 +02:00
wm : mf . Mention {
2021-04-09 12:40:37 +02:00
Source : "https://brainbaking.com/valid-nonindieweb-source.html" ,
Target : "https://brainbaking.com/valid-indieweb-target.html" ,
2021-04-09 10:12:14 +02:00
} ,
2021-05-01 20:37:52 +02:00
json : ` { "author": { "name":"https://brainbaking.com/valid-nonindieweb-source.html", "picture":"/pictures/anonymous"}, "content":"Diablo 2 Twenty Years Later: A Retrospective | Jefklaks Codex", "name":"Diablo 2 Twenty Years Later: A Retrospective | Jefklaks Codex", "published":"2020-01-01T12:30:00+00:00", "source":"https://brainbaking.com/valid-nonindieweb-source.html", "target":"https://brainbaking.com/valid-indieweb-target.html", "type":"mention", "url":"https://brainbaking.com/valid-nonindieweb-source.html"} ` ,
2021-04-08 16:37:04 +02:00
} ,
}
2021-04-09 10:12:14 +02:00
for _ , tc := range cases {
t . Run ( tc . label , func ( t * testing . T ) {
2021-04-09 14:21:25 +02:00
common . Now = func ( ) time . Time {
2021-04-09 10:12:14 +02:00
return time . Date ( 2020 , time . January , 1 , 12 , 30 , 0 , 0 , time . UTC )
}
2021-04-18 15:39:29 +02:00
repo := db . NewMentionRepo ( conf )
2021-04-09 12:40:37 +02:00
receiver := & Receiver {
2021-04-18 15:39:29 +02:00
Conf : conf ,
Repo : repo ,
2021-04-09 12:40:37 +02:00
RestClient : & mocks . RestClientMock {
2021-04-23 09:39:49 +02:00
GetBodyFunc : mocks . RelPathGetBodyFunc ( "../../../mocks/" ) ,
2021-04-09 10:12:14 +02:00
} ,
}
2021-04-09 12:40:37 +02:00
receiver . Receive ( tc . wm )
2021-04-09 10:12:14 +02:00
2021-04-18 15:39:29 +02:00
actual := repo . Get ( tc . wm )
actualJson , _ := json . Marshal ( actual )
2021-04-09 10:12:14 +02:00
assert . JSONEq ( t , tc . json , string ( actualJson ) )
} )
}
2021-04-08 16:37:04 +02:00
}
2021-04-08 12:16:33 +02:00
func TestReceiveTargetDoesNotExistAnymoreDeletesPossiblyOlderWebmention ( t * testing . T ) {
2021-04-18 15:39:29 +02:00
repo := db . NewMentionRepo ( conf )
2022-04-23 10:00:00 +02:00
t . Cleanup ( db . Purge )
2021-04-08 12:16:33 +02:00
2021-04-09 14:21:25 +02:00
wm := mf . Mention {
2021-04-09 12:40:37 +02:00
Source : "https://brainbaking.com" ,
Target : "https://jefklakscodex.com/articles" ,
2021-04-08 12:16:33 +02:00
}
2021-04-18 15:39:29 +02:00
repo . Save ( wm , & mf . IndiewebData {
Name : "something something" ,
} )
2021-04-08 12:16:33 +02:00
client := & mocks . RestClientMock {
2021-04-11 09:50:27 +02:00
GetBodyFunc : func ( url string ) ( http . Header , string , error ) {
return nil , "" , errors . New ( "whoops" )
2021-04-08 12:16:33 +02:00
} ,
2021-04-09 21:00:54 +02:00
}
2021-04-09 12:40:37 +02:00
receiver := & Receiver {
2021-04-18 15:39:29 +02:00
Conf : conf ,
2021-04-09 12:40:37 +02:00
RestClient : client ,
2021-04-18 15:39:29 +02:00
Repo : repo ,
2021-04-08 12:16:33 +02:00
}
2021-04-09 12:40:37 +02:00
receiver . Receive ( wm )
2021-04-18 15:39:29 +02:00
indb := repo . Get ( wm )
assert . Empty ( t , indb )
2021-04-09 10:12:14 +02:00
}
2022-04-23 21:27:43 +02:00
func TestReceiveFromNotInWhitelistSavesInModerationAndNotifies ( t * testing . T ) {
2022-04-23 11:35:53 +02:00
wm := mf . Mention {
Source : "https://brainbaking.com/valid-indieweb-source.html" ,
Target : "https://brainbaking.com/valid-indieweb-target.html" ,
}
cnf := & common . Config {
AllowedWebmentionSources : [ ] string {
"brainbaking.com" ,
} ,
2022-04-23 21:27:43 +02:00
BaseURL : "https://jam.brainbaking.com/" ,
Token : "mytoken" ,
2022-04-23 11:35:53 +02:00
Blacklist : [ ] string { } ,
Whitelist : [ ] string { } ,
}
repo := db . NewMentionRepo ( cnf )
t . Cleanup ( db . Purge )
2022-04-23 21:27:43 +02:00
notifierMock := & mocks . StringNotifier {
Conf : cnf ,
Output : "" ,
}
2022-04-23 11:35:53 +02:00
receiver := & Receiver {
Conf : cnf ,
Repo : repo ,
RestClient : & mocks . RestClientMock {
GetBodyFunc : mocks . RelPathGetBodyFunc ( "../../../mocks/" ) ,
} ,
2022-04-23 21:27:43 +02:00
Notifier : notifierMock ,
2022-04-23 11:35:53 +02:00
}
receiver . Receive ( wm )
assert . Empty ( t , repo . GetAll ( "brainbaking.com" ) . Data )
assert . Equal ( t , 1 , len ( repo . GetAllToModerate ( "brainbaking.com" ) . Data ) )
2022-04-24 16:10:59 +02:00
assert . Contains ( t , notifierMock . Output , "✅ Accept!" )
2022-04-23 11:35:53 +02:00
}
2021-05-02 11:40:45 +02:00
func TestReceiveFromBlacklistedDomainDoesNothing ( t * testing . T ) {
wm := mf . Mention {
Source : "https://blacklisted.com/whoops" ,
Target : "https://brainbaking.com/valid-indieweb-source.html" ,
}
repo := db . NewMentionRepo ( conf )
2022-04-23 10:00:00 +02:00
t . Cleanup ( db . Purge )
2021-05-02 11:40:45 +02:00
receiver := & Receiver {
Conf : conf ,
Repo : repo ,
}
receiver . Receive ( wm )
assert . Empty ( t , repo . GetAll ( "brainbaking.com" ) . Data )
2022-04-23 11:35:53 +02:00
assert . Empty ( t , repo . GetAllToModerate ( "brainbaking.com" ) . Data )
2021-05-02 11:40:45 +02:00
}
2021-04-09 10:12:14 +02:00
func TestReceiveTargetThatDoesNotPointToTheSourceDoesNothing ( t * testing . T ) {
2021-04-09 14:21:25 +02:00
wm := mf . Mention {
2021-04-09 12:40:37 +02:00
Source : "https://brainbaking.com/valid-indieweb-source.html" ,
Target : "https://brainbaking.com/valid-indieweb-source.html" ,
2021-04-09 10:12:14 +02:00
}
2021-04-18 15:39:29 +02:00
repo := db . NewMentionRepo ( conf )
2022-04-23 10:00:00 +02:00
t . Cleanup ( db . Purge )
2021-04-09 12:40:37 +02:00
receiver := & Receiver {
2021-04-18 15:39:29 +02:00
Conf : conf ,
Repo : repo ,
2021-04-09 12:40:37 +02:00
RestClient : & mocks . RestClientMock {
2021-04-23 09:39:49 +02:00
GetBodyFunc : mocks . RelPathGetBodyFunc ( "../../../mocks/" ) ,
2021-04-09 10:12:14 +02:00
} ,
}
2021-04-09 12:40:37 +02:00
receiver . Receive ( wm )
2021-04-18 15:39:29 +02:00
assert . Empty ( t , repo . GetAll ( "brainbaking.com" ) . Data )
2022-04-23 11:35:53 +02:00
assert . Empty ( t , repo . GetAllToModerate ( "brainbaking.com" ) . Data )
2021-04-08 12:50:15 +02:00
}
2021-05-01 20:22:56 +02:00
func TestProcessSourceBodyAnonymizesBothAuthorPictureAndNameIfComingFromSilo ( t * testing . T ) {
wm := mf . Mention {
Source : "https://brid.gy/post/twitter/ChrisAldrich/1387130900962443264" ,
Target : "https://brainbaking.com/" ,
}
2022-04-23 11:35:53 +02:00
cnf := & common . Config {
AllowedWebmentionSources : [ ] string {
"brainbaking.com" ,
} ,
Whitelist : [ ] string {
"brid.gy" ,
} ,
}
repo := db . NewMentionRepo ( cnf )
2022-04-23 10:00:00 +02:00
t . Cleanup ( db . Purge )
2021-05-01 20:37:52 +02:00
recv := & Receiver {
2022-04-23 11:35:53 +02:00
Conf : cnf ,
2021-05-01 20:22:56 +02:00
Repo : repo ,
}
src , err := ioutil . ReadFile ( "../../../mocks/valid-bridgy-source.html" )
assert . NoError ( t , err )
2021-05-01 20:37:52 +02:00
recv . processSourceBody ( string ( src ) , wm )
2021-05-01 20:22:56 +02:00
savedMention := repo . Get ( wm )
assert . Equal ( t , "Anonymous" , savedMention . Author . Name )
assert . Equal ( t , "/pictures/anonymous" , savedMention . Author . Picture )
}
2021-04-08 12:50:15 +02:00
func TestProcessSourceBodyAbortsIfNoMentionOfTargetFoundInSourceHtml ( t * testing . T ) {
2021-04-09 14:21:25 +02:00
wm := mf . Mention {
2021-04-09 12:40:37 +02:00
Source : "https://brainbaking.com" ,
Target : "https://jefklakscodex.com/articles" ,
2021-04-08 12:50:15 +02:00
}
2021-04-18 15:39:29 +02:00
repo := db . NewMentionRepo ( conf )
2022-04-23 10:00:00 +02:00
t . Cleanup ( db . Purge )
2021-05-01 20:37:52 +02:00
recv := & Receiver {
2021-04-18 15:39:29 +02:00
Conf : conf ,
Repo : repo ,
2021-04-08 12:50:15 +02:00
}
2021-05-01 20:37:52 +02:00
recv . processSourceBody ( "<html>my nice body</html>" , wm )
2021-04-18 15:39:29 +02:00
assert . Empty ( t , repo . Get ( wm ) )
2021-04-08 12:50:15 +02:00
}
2021-05-01 20:37:52 +02:00
func TestProcessAuthorPictureAnonymizesIfEmpty ( t * testing . T ) {
recv := & Receiver { }
indieweb := & mf . IndiewebData {
Author : mf . IndiewebAuthor {
Picture : "" ,
} ,
}
recv . processAuthorPicture ( indieweb )
assert . Equal ( t , "/pictures/anonymous" , indieweb . Author . Picture )
}