2022-02-26 19:38:52 +00:00
package main
import (
2023-12-19 11:15:30 +00:00
"context"
2022-02-26 19:38:52 +00:00
"net/http"
"net/http/httptest"
2023-12-19 11:15:30 +00:00
"net/url"
"strings"
2022-02-26 19:38:52 +00:00
"testing"
2023-12-19 11:15:30 +00:00
"github.com/carlmjohnson/requests"
2022-02-26 19:38:52 +00:00
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
2023-12-19 11:15:30 +00:00
"go.goblog.app/app/pkgs/contenttype"
"go.hacdias.com/indielib/micropub"
2022-02-26 19:38:52 +00:00
)
2023-12-25 12:44:35 +00:00
func createMicropubTestEnv ( t * testing . T ) * goBlog {
2022-02-26 19:38:52 +00:00
app := & goBlog {
cfg : createDefaultTestConfig ( t ) ,
}
2022-07-16 19:09:43 +00:00
_ = app . initConfig ( false )
2023-12-25 12:44:35 +00:00
return app
}
func Test_micropubQuery ( t * testing . T ) {
app := createMicropubTestEnv ( t )
2022-02-26 19:38:52 +00:00
// Create a test post with tags
err := app . createPost ( & post {
Path : "/test/post" ,
Content : "Test post" ,
Parameters : map [ string ] [ ] string {
"tags" : { "test" , "test2" } ,
} ,
} )
require . NoError ( t , err )
type testCase struct {
query string
want string
wantStatus int
}
testCases := [ ] testCase {
{
query : "config" ,
2023-12-19 11:15:30 +00:00
want : "{\"categories\":[\"test\",\"test2\"],\"channels\":[{\"uid\":\"default\",\"name\":\"default: My Blog\"},{\"uid\":\"default/posts\",\"name\":\"default/posts: posts\"}],\"media-endpoint\":\"http://localhost:8080/micropub/media\",\"visibility\":[\"private\",\"unlisted\",\"public\"]}\n" ,
2022-02-26 19:38:52 +00:00
wantStatus : http . StatusOK ,
} ,
{
query : "source&url=http://localhost:8080/test/post" ,
2023-12-19 11:15:30 +00:00
want : "{\"properties\":{\"category\":[\"test\",\"test2\"],\"content\":[\"---\\nblog: default\\npath: /test/post\\npriority: 0\\npublished: \\\"\\\"\\nsection: \\\"\\\"\\nstatus: published\\ntags:\\n - test\\n - test2\\nupdated: \\\"\\\"\\nvisibility: public\\n---\\nTest post\"],\"mp-channel\":[\"default\"],\"mp-slug\":[\"\"],\"post-status\":[\"published\"],\"published\":[\"\"],\"updated\":[\"\"],\"url\":[\"http://localhost:8080/test/post\"],\"visibility\":[\"public\"]},\"type\":[\"h-entry\"]}\n" ,
2022-02-26 19:38:52 +00:00
wantStatus : http . StatusOK ,
} ,
{
query : "source" ,
2023-12-19 11:15:30 +00:00
want : "{\"items\":[{\"properties\":{\"category\":[\"test\",\"test2\"],\"content\":[\"---\\nblog: default\\npath: /test/post\\npriority: 0\\npublished: \\\"\\\"\\nsection: \\\"\\\"\\nstatus: published\\ntags:\\n - test\\n - test2\\nupdated: \\\"\\\"\\nvisibility: public\\n---\\nTest post\"],\"mp-channel\":[\"default\"],\"mp-slug\":[\"\"],\"post-status\":[\"published\"],\"published\":[\"\"],\"updated\":[\"\"],\"url\":[\"http://localhost:8080/test/post\"],\"visibility\":[\"public\"]},\"type\":[\"h-entry\"]}]}\n" ,
2022-02-26 19:38:52 +00:00
wantStatus : http . StatusOK ,
} ,
{
query : "category" ,
2023-12-19 11:15:30 +00:00
want : "{\"categories\":[\"test\",\"test2\"]}\n" ,
2022-02-26 19:38:52 +00:00
wantStatus : http . StatusOK ,
} ,
2022-09-23 12:15:29 +00:00
{
query : "channel" ,
2023-12-19 11:15:30 +00:00
want : "{\"channels\":[{\"uid\":\"default\",\"name\":\"default: My Blog\"},{\"uid\":\"default/posts\",\"name\":\"default/posts: posts\"}]}\n" ,
2022-09-23 12:15:29 +00:00
wantStatus : http . StatusOK ,
} ,
2022-02-26 19:38:52 +00:00
{
query : "somethingelse" ,
wantStatus : http . StatusNotFound ,
} ,
}
for _ , tc := range testCases {
req := httptest . NewRequest ( http . MethodGet , "http://localhost:8080/micropub?q=" + tc . query , nil )
rec := httptest . NewRecorder ( )
2023-12-19 11:15:30 +00:00
app . getMicropubImplementation ( ) . getHandler ( ) . ServeHTTP ( rec , req )
2022-02-26 19:38:52 +00:00
rec . Flush ( )
assert . Equal ( t , tc . wantStatus , rec . Code )
if tc . want != "" {
assert . Equal ( t , tc . want , rec . Body . String ( ) )
}
}
}
2023-12-19 11:15:30 +00:00
func Test_micropubCreate ( t * testing . T ) {
2023-12-25 12:44:35 +00:00
app := createMicropubTestEnv ( t )
2023-12-19 11:15:30 +00:00
// Modify settings for easier testing
bc := app . cfg . Blogs [ app . cfg . DefaultBlog ]
sc := bc . Sections [ bc . DefaultSection ]
sc . PathTemplate = ` {{ printf "/%v" .Slug }} `
handler := addAllScopes ( app . getMicropubImplementation ( ) . getHandler ( ) )
2023-12-25 12:44:35 +00:00
t . Run ( "JSON" , func ( t * testing . T ) {
testCases := [ ] struct {
name , postPath , reqBody string
assertions func ( t * testing . T , p * post )
} {
{
"Normal" ,
"/create1" ,
` { "type":["h-entry"],"properties": { "content":["Test post"],"mp-slug":["create1"],"category":["Cool"]}} ` ,
func ( t * testing . T , p * post ) {
assert . Equal ( t , "Test post" , p . Content )
assert . Equal ( t , [ ] string { "Cool" } , p . Parameters [ "tags" ] )
} ,
} ,
{
"Photo" ,
"/create2" ,
` { "type":["h-entry"],"properties": { "mp-slug":["create2"],"photo":["https://photos.example.com/123.jpg"]}} ` ,
func ( t * testing . T , p * post ) {
assert . Equal ( t , "\n![](https://photos.example.com/123.jpg)" , p . Content )
assert . Equal ( t , [ ] string { "https://photos.example.com/123.jpg" } , p . Parameters [ "images" ] )
} ,
} ,
{
"Photo with alternative text" ,
"/create3" ,
` { "type" : [ "h-entry" ] , "properties" : { "mp-slug" : [ "create3" ] , "photo" : [ {
"value" : "https://photos.example.com/123.jpg" ,
"alt" : "This is a photo"
} ] } } ` ,
func ( t * testing . T , p * post ) {
assert . Equal ( t , "\n![This is a photo](https://photos.example.com/123.jpg \"This is a photo\")" , p . Content )
assert . Equal ( t , [ ] string { "https://photos.example.com/123.jpg" } , p . Parameters [ "images" ] )
assert . Equal ( t , [ ] string { "This is a photo" } , p . Parameters [ "imagealts" ] )
} ,
} ,
}
2023-12-19 11:15:30 +00:00
2023-12-25 12:44:35 +00:00
for _ , tc := range testCases {
tc := tc
t . Run ( tc . name , func ( t * testing . T ) {
t . Parallel ( )
2023-12-19 11:15:30 +00:00
2023-12-25 12:44:35 +00:00
recorder := httptest . NewRecorder ( )
req , _ := requests . New ( ) . Post ( ) . BodyReader ( strings . NewReader ( tc . reqBody ) ) . ContentType ( contenttype . JSONUTF8 ) . Request ( context . Background ( ) )
handler . ServeHTTP ( recorder , req )
2023-12-19 11:15:30 +00:00
2023-12-25 12:44:35 +00:00
result := recorder . Result ( )
require . Equal ( t , http . StatusAccepted , result . StatusCode )
require . Equal ( t , "http://localhost:8080" + tc . postPath , result . Header . Get ( "Location" ) )
_ = result . Body . Close ( )
2023-12-19 11:15:30 +00:00
2023-12-25 12:44:35 +00:00
p , err := app . getPost ( tc . postPath )
require . NoError ( t , err )
2023-12-19 11:15:30 +00:00
2023-12-25 12:44:35 +00:00
tc . assertions ( t , p )
} )
}
2023-12-19 11:15:30 +00:00
} )
2023-12-25 12:44:35 +00:00
t . Run ( "Form" , func ( t * testing . T ) {
testCases := [ ] struct {
name , postPath string
bodyForm url . Values
assertions func ( t * testing . T , p * post )
} {
{
"Photo with alternative text" ,
"/create4" ,
url . Values {
"h" : [ ] string { "entry" } ,
"mp-slug" : [ ] string { "create4" } ,
"photo" : [ ] string { "https://photos.example.com/123.jpg" } ,
"mp-photo-alt" : [ ] string { "This is a photo" } ,
} ,
func ( t * testing . T , p * post ) {
assert . Equal ( t , "\n![This is a photo](https://photos.example.com/123.jpg \"This is a photo\")" , p . Content )
assert . Equal ( t , [ ] string { "https://photos.example.com/123.jpg" } , p . Parameters [ "images" ] )
assert . Equal ( t , [ ] string { "This is a photo" } , p . Parameters [ "imagealts" ] )
} ,
} ,
{
"Custom parameter" ,
"/create5" ,
url . Values {
"h" : [ ] string { "entry" } ,
"mp-slug" : [ ] string { "create5" } ,
"random" : [ ] string { "Abc" , "Def" } ,
} ,
func ( t * testing . T , p * post ) {
assert . Equal ( t , [ ] string { "Abc" , "Def" } , p . Parameters [ "random" ] )
} ,
} ,
}
2023-12-19 11:15:30 +00:00
2023-12-25 12:44:35 +00:00
for _ , tc := range testCases {
tc := tc
t . Run ( tc . name , func ( t * testing . T ) {
t . Parallel ( )
2023-12-19 11:15:30 +00:00
2023-12-25 12:44:35 +00:00
recorder := httptest . NewRecorder ( )
req , _ := requests . New ( ) . Post ( ) . BodyForm ( tc . bodyForm ) . Request ( context . Background ( ) )
handler . ServeHTTP ( recorder , req )
2023-12-19 11:15:30 +00:00
2023-12-25 12:44:35 +00:00
result := recorder . Result ( )
require . Equal ( t , http . StatusAccepted , result . StatusCode )
require . Equal ( t , "http://localhost:8080" + tc . postPath , result . Header . Get ( "Location" ) )
_ = result . Body . Close ( )
2023-12-19 11:15:30 +00:00
2023-12-25 12:44:35 +00:00
p , err := app . getPost ( tc . postPath )
require . NoError ( t , err )
2023-12-19 11:15:30 +00:00
2023-12-25 12:44:35 +00:00
tc . assertions ( t , p )
} )
}
2023-12-19 11:15:30 +00:00
} )
}
func Test_micropubUpdate ( t * testing . T ) {
2023-12-25 12:44:35 +00:00
app := createMicropubTestEnv ( t )
2023-12-19 11:15:30 +00:00
t . Run ( "Delete" , func ( t * testing . T ) {
postPath := "/delete1"
err := app . createPost ( & post {
Path : postPath ,
Content : "Test post" ,
Parameters : map [ string ] [ ] string {
"tags" : { "test" , "test2" } ,
"random" : { "abc" , "def" } ,
} ,
} )
require . NoError ( t , err )
_ , err = app . getMicropubImplementation ( ) . Update ( & micropub . Request {
URL : app . cfg . Server . PublicAddress + postPath ,
Updates : micropub . RequestUpdate {
Delete : map [ string ] any {
// Should filter the parameters
"category" : [ ] any { "test" } ,
// Should do nothing, because it's a custom parameter and thus ignored
"random" : [ ] any { "def" } ,
// Should do nothing
"content" : [ ] any { } ,
} ,
} ,
} )
require . NoError ( t , err )
p , err := app . getPost ( postPath )
require . NoError ( t , err )
assert . Equal ( t , [ ] string { "test2" } , p . Parameters [ "tags" ] )
assert . Equal ( t , [ ] string { "abc" , "def" } , p . Parameters [ "random" ] )
assert . Equal ( t , "Test post" , p . Content )
} )
t . Run ( "Replace" , func ( t * testing . T ) {
postPath := "/replace1"
err := app . createPost ( & post {
Path : postPath ,
Content : "Test post" ,
Status : statusPublished ,
Visibility : visibilityPublic ,
Parameters : map [ string ] [ ] string {
"tags" : { "test" , "test2" } ,
"random" : { "abc" , "def" } ,
} ,
} )
require . NoError ( t , err )
_ , err = app . getMicropubImplementation ( ) . Update ( & micropub . Request {
URL : app . cfg . Server . PublicAddress + postPath ,
Updates : micropub . RequestUpdate {
Replace : map [ string ] [ ] any {
"category" : { "test" } ,
"random" : { "def" } ,
"content" : { "New test" } ,
2024-01-23 07:25:21 +00:00
"post-status" : { "draft" } ,
2023-12-19 11:15:30 +00:00
"visibility" : { "unlisted" } ,
} ,
} ,
} )
require . NoError ( t , err )
p , err := app . getPost ( postPath )
require . NoError ( t , err )
assert . Equal ( t , [ ] string { "test" } , p . Parameters [ "tags" ] )
assert . Equal ( t , [ ] string { "def" } , p . Parameters [ "random" ] )
assert . Equal ( t , "New test" , p . Content )
2024-01-23 07:25:21 +00:00
assert . Equal ( t , statusDraft , p . Status )
2023-12-19 11:15:30 +00:00
assert . Nil ( t , p . Parameters [ "post-status" ] )
assert . Equal ( t , visibilityUnlisted , p . Visibility )
} )
2024-01-23 07:25:21 +00:00
t . Run ( "Replace wrong status" , func ( t * testing . T ) {
postPath := "/replace2"
err := app . createPost ( & post {
Path : postPath ,
Content : "" ,
Status : statusPublished ,
Visibility : visibilityPublic ,
Parameters : map [ string ] [ ] string { } ,
} )
require . NoError ( t , err )
_ , err = app . getMicropubImplementation ( ) . Update ( & micropub . Request {
URL : app . cfg . Server . PublicAddress + postPath ,
Updates : micropub . RequestUpdate {
Replace : map [ string ] [ ] any {
"post-status" : { "published-deleted" } ,
} ,
} ,
} )
require . NoError ( t , err )
p , err := app . getPost ( postPath )
require . NoError ( t , err )
assert . Equal ( t , statusPublished , p . Status )
assert . Nil ( t , p . Parameters [ "post-status" ] )
} )
2023-12-19 11:15:30 +00:00
t . Run ( "Add" , func ( t * testing . T ) {
postPath := "/add1"
err := app . createPost ( & post {
Path : postPath ,
Content : "Test post" ,
Parameters : map [ string ] [ ] string {
"tags" : { "test" } ,
} ,
} )
require . NoError ( t , err )
_ , err = app . getMicropubImplementation ( ) . Update ( & micropub . Request {
URL : app . cfg . Server . PublicAddress + postPath ,
Updates : micropub . RequestUpdate {
Add : map [ string ] [ ] any {
"category" : { "test2" } ,
"random" : { "abc" } ,
"content" : { "Add" , "Bbb" } ,
"post-status" : { "published" } ,
} ,
} ,
} )
require . NoError ( t , err )
p , err := app . getPost ( postPath )
require . NoError ( t , err )
assert . Equal ( t , [ ] string { "test" , "test2" } , p . Parameters [ "tags" ] )
assert . Equal ( t , [ ] string { "abc" } , p . Parameters [ "random" ] )
assert . Equal ( t , "Test post" , p . Content )
assert . Nil ( t , p . Parameters [ "post-status" ] )
} )
}