api tests added
This commit is contained in:
@@ -1,5 +1,3 @@
|
|||||||
dump.rdb
|
|
||||||
bin/
|
|
||||||
node_modules/
|
node_modules/
|
||||||
npm-debug.log
|
npm-debug.log
|
||||||
database.sqlite-journal
|
database.sqlite-journal
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
{
|
|
||||||
"plugins": {
|
|
||||||
"node": {}
|
|
||||||
},
|
|
||||||
"libs": [
|
|
||||||
"ecma5",
|
|
||||||
"ecma6"
|
|
||||||
],
|
|
||||||
"ecmaVersion": 6
|
|
||||||
}
|
|
||||||
Generated
+1
-1
@@ -76,6 +76,6 @@
|
|||||||
[solve-meta]
|
[solve-meta]
|
||||||
analyzer-name = "dep"
|
analyzer-name = "dep"
|
||||||
analyzer-version = 1
|
analyzer-version = 1
|
||||||
inputs-digest = "82edf4a4585c9ad3318ead49e58d8bca7efed18e2f727be8e8fc6498972fc039"
|
inputs-digest = "441429b4f331d40009b166378491cbd1b7e797135151d16d79394725cfbe16a2"
|
||||||
solver-name = "gps-cdcl"
|
solver-name = "gps-cdcl"
|
||||||
solver-version = 1
|
solver-version = 1
|
||||||
|
|||||||
+201
@@ -0,0 +1,201 @@
|
|||||||
|
var frisby = require('frisby');
|
||||||
|
|
||||||
|
frisby.create('Landing page')
|
||||||
|
.get('http://localhost:3000/')
|
||||||
|
.expectStatus(200)
|
||||||
|
.expectHeaderContains('content-type', 'text/html; charset=utf-8')
|
||||||
|
.expectBodyContains('Markdown Publishing')
|
||||||
|
.toss();
|
||||||
|
|
||||||
|
frisby.create('Open note page')
|
||||||
|
.get('http://localhost:3000/new')
|
||||||
|
.expectStatus(200)
|
||||||
|
.expectHeaderContains('content-type', 'text/html; charset=utf-8')
|
||||||
|
.expectBodyContains('Terms of Service')
|
||||||
|
.toss();
|
||||||
|
|
||||||
|
frisby.create('Open TOS')
|
||||||
|
.get('http://localhost:3000/TOS.md')
|
||||||
|
.expectStatus(200)
|
||||||
|
.expectHeaderContains('content-type', 'text/html; charset=utf-8')
|
||||||
|
.expectBodyContains('Site Terms of Use Modifications')
|
||||||
|
.toss();
|
||||||
|
|
||||||
|
frisby.create('Incurrect URL')
|
||||||
|
.get('http://localhost:3000/abcdef')
|
||||||
|
.expectStatus(404)
|
||||||
|
.expectBodyContains('Not found')
|
||||||
|
.toss();
|
||||||
|
|
||||||
|
frisby.create('Invalid posting 1')
|
||||||
|
.post('http://localhost:3000/note')
|
||||||
|
.expectStatus(412)
|
||||||
|
.expectHeaderContains('content-type', 'text/html; charset=utf-8')
|
||||||
|
.expectBodyContains('Precondition failed')
|
||||||
|
.toss();
|
||||||
|
|
||||||
|
frisby.create('Invalid posting 2')
|
||||||
|
.post('http://localhost:3000/note', { tos: "on" })
|
||||||
|
.expectStatus(400)
|
||||||
|
.expectHeaderContains('content-type', 'text/html; charset=utf-8')
|
||||||
|
.expectBodyContains('Bad request')
|
||||||
|
.toss();
|
||||||
|
|
||||||
|
frisby.create('Invalid posting 3')
|
||||||
|
.post('http://localhost:3000/note', {
|
||||||
|
text: "too short",
|
||||||
|
password: '',
|
||||||
|
tos: 'on',
|
||||||
|
})
|
||||||
|
.expectStatus(400)
|
||||||
|
.expectHeaderContains('content-type', 'text/html; charset=utf-8')
|
||||||
|
.expectBodyContains('length not accepted')
|
||||||
|
.toss();
|
||||||
|
|
||||||
|
let testNote = 'This is a test note';
|
||||||
|
|
||||||
|
frisby.create('Invalid posting 4')
|
||||||
|
.post('http://localhost:3000/note', {
|
||||||
|
note: testNote
|
||||||
|
})
|
||||||
|
.expectStatus(412)
|
||||||
|
.expectHeaderContains('content-type', 'text/html; charset=utf-8')
|
||||||
|
.expectBodyContains('Precondition failed')
|
||||||
|
.toss();
|
||||||
|
|
||||||
|
frisby.create('Valid posting')
|
||||||
|
.post('http://localhost:3000/note', {
|
||||||
|
password: '',
|
||||||
|
tos: 'on',
|
||||||
|
text: testNote
|
||||||
|
})
|
||||||
|
.expectStatus(301)
|
||||||
|
.expectHeaderContains('content-type', 'text/plain; charset=utf-8')
|
||||||
|
.expectHeaderContains('Location', '/')
|
||||||
|
.after(function(err, res, body) {
|
||||||
|
let noteId = res.headers.location.replace('/', '');
|
||||||
|
frisby.create('Read posted note')
|
||||||
|
.get('http://localhost:3000/' + noteId)
|
||||||
|
.expectStatus(200)
|
||||||
|
.expectBodyContains(testNote)
|
||||||
|
.after((err, res, body) => {
|
||||||
|
frisby.create('Illegal note editing attempt with empty password')
|
||||||
|
.post('http://localhost:3000/note', {
|
||||||
|
id: noteId,
|
||||||
|
tos: 'on',
|
||||||
|
action: 'UPDATE',
|
||||||
|
text: testNote + '!!!',
|
||||||
|
password: ''
|
||||||
|
})
|
||||||
|
.expectStatus(400)
|
||||||
|
.expectBodyContains('password is empty')
|
||||||
|
.toss();
|
||||||
|
})
|
||||||
|
.after((err, res, body) => {
|
||||||
|
frisby.create('Illegal note editing attempt')
|
||||||
|
.post('http://localhost:3000/note', {
|
||||||
|
id: noteId,
|
||||||
|
tos: 'on',
|
||||||
|
action: 'UPDATE',
|
||||||
|
text: testNote + '!!!',
|
||||||
|
password: 'aaabbb'
|
||||||
|
})
|
||||||
|
.expectStatus(401)
|
||||||
|
.expectBodyContains('id or password is wrong')
|
||||||
|
.toss();
|
||||||
|
|
||||||
|
})
|
||||||
|
.toss();
|
||||||
|
})
|
||||||
|
.toss();
|
||||||
|
|
||||||
|
frisby.create('Valid posting, editing and more')
|
||||||
|
.post('http://localhost:3000/note', {
|
||||||
|
password: 'aabbcc',
|
||||||
|
tos: 'on',
|
||||||
|
text: testNote
|
||||||
|
})
|
||||||
|
.expectStatus(301)
|
||||||
|
.expectHeaderContains('Location', '/')
|
||||||
|
.expectHeaderContains('content-type', 'text/plain; charset=utf-8')
|
||||||
|
.after(function(err, res, body) {
|
||||||
|
let noteId = res.headers.location.replace('/', '');
|
||||||
|
frisby.create('Export posted note')
|
||||||
|
.get('http://localhost:3000/' + noteId + '/export')
|
||||||
|
.expectStatus(200)
|
||||||
|
.expectHeaderContains('content-type', 'text/plain; charset=utf-8')
|
||||||
|
.expectBodyContains(testNote)
|
||||||
|
.toss();
|
||||||
|
frisby.create('Read posted note')
|
||||||
|
.get('http://localhost:3000/' + noteId)
|
||||||
|
.expectStatus(200)
|
||||||
|
.expectBodyContains(testNote)
|
||||||
|
.expectHeaderContains('content-type', 'text/html; charset=utf-8')
|
||||||
|
.after((err, res, body) => {
|
||||||
|
frisby.create('Unauthorized note editing attempt')
|
||||||
|
.post('http://localhost:3000/note', {
|
||||||
|
id: noteId,
|
||||||
|
tos: 'on',
|
||||||
|
text: testNote + '!!!',
|
||||||
|
password: 'abbcc'
|
||||||
|
})
|
||||||
|
.expectStatus(401)
|
||||||
|
.expectBodyContains('password is wrong')
|
||||||
|
.toss();
|
||||||
|
})
|
||||||
|
.after((err, res, body) => {
|
||||||
|
frisby.create('Valid note editing attempt')
|
||||||
|
.post('http://localhost:3000/note', {
|
||||||
|
id: noteId,
|
||||||
|
tos: 'on',
|
||||||
|
text: 'Changed text!',
|
||||||
|
password: 'aabbcc'
|
||||||
|
})
|
||||||
|
.expectStatus(301)
|
||||||
|
.after((err, res, body) => {
|
||||||
|
frisby.create('Read changed note')
|
||||||
|
.get('http://localhost:3000/' + noteId)
|
||||||
|
.expectStatus(200)
|
||||||
|
.expectBodyContains('Changed text!')
|
||||||
|
.toss();
|
||||||
|
})
|
||||||
|
.toss();
|
||||||
|
})
|
||||||
|
.toss();
|
||||||
|
frisby.create('Read export of posted note')
|
||||||
|
.expectStatus(200)
|
||||||
|
.get('http://localhost:3000/' + noteId + '/export')
|
||||||
|
.expectHeaderContains('content-type', 'text/plain; charset=utf-8')
|
||||||
|
.expectBodyContains(testNote)
|
||||||
|
.toss();
|
||||||
|
frisby.create('Open /edit on posted note')
|
||||||
|
.expectStatus(200)
|
||||||
|
.expectBodyContains('<textarea autofocus name="text">' + testNote + '</textarea>')
|
||||||
|
.get('http://localhost:3000/' + noteId + '/edit')
|
||||||
|
.toss();
|
||||||
|
frisby.create('Read stats of posted note')
|
||||||
|
.get('http://localhost:3000/' + noteId + '/stats')
|
||||||
|
.expectHeaderContains('content-type', 'text/html; charset=utf-8')
|
||||||
|
.expectStatus(200)
|
||||||
|
.expectBodyContains('Statistics')
|
||||||
|
.expectBodyContains('<tr><td>Views</td><td>0</td></tr>')
|
||||||
|
.toss();
|
||||||
|
})
|
||||||
|
.toss();
|
||||||
|
|
||||||
|
var tooLongNote = 'ABCD';
|
||||||
|
|
||||||
|
while (tooLongNote.length < 1024*200) tooLongNote += tooLongNote;
|
||||||
|
|
||||||
|
frisby.create('Invalid posting of too long note')
|
||||||
|
.post('http://localhost:3000/note', {
|
||||||
|
action: 'POST',
|
||||||
|
tos: 'on',
|
||||||
|
password: 'aabbcc',
|
||||||
|
text: tooLongNote
|
||||||
|
})
|
||||||
|
.expectStatus(400)
|
||||||
|
.expectHeaderContains('content-type', 'text/html; charset=utf-8')
|
||||||
|
.expectBodyContains('length not accepted')
|
||||||
|
.toss();
|
||||||
|
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"name": "NoteHub",
|
||||||
|
"version": "3.0.0",
|
||||||
|
"main": "server.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "jasmine-node ."
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"frisby": "^0.8.5"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -142,7 +142,7 @@ func main() {
|
|||||||
code = http.StatusBadRequest
|
code = http.StatusBadRequest
|
||||||
}
|
}
|
||||||
c.Logger().Errorf("POST /note error: %d", code)
|
c.Logger().Errorf("POST /note error: %d", code)
|
||||||
return c.Render(code, "Note", errPage(code))
|
return c.Render(code, "Note", errPage(code, err.Error()))
|
||||||
}
|
}
|
||||||
c.Logger().Debugf("note %q saved", n.ID)
|
c.Logger().Debugf("note %q saved", n.ID)
|
||||||
return c.Redirect(http.StatusMovedPermanently, "/"+n.ID)
|
return c.Redirect(http.StatusMovedPermanently, "/"+n.ID)
|
||||||
@@ -160,7 +160,7 @@ func get(vals url.Values, key string) string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func md2html(c echo.Context, name string) (Note, int) {
|
func md2html(c echo.Context, name string) (*Note, int) {
|
||||||
path := "assets/markdown/" + name + ".md"
|
path := "assets/markdown/" + name + ".md"
|
||||||
mdContent, err := ioutil.ReadFile(path)
|
mdContent, err := ioutil.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -169,5 +169,5 @@ func md2html(c echo.Context, name string) (Note, int) {
|
|||||||
return errPage(code), code
|
return errPage(code), code
|
||||||
}
|
}
|
||||||
c.Logger().Debugf("rendering markdown page %q", name)
|
c.Logger().Debugf("rendering markdown page %q", name)
|
||||||
return Note{Title: name, Content: mdTmplHTML(mdContent)}, http.StatusOK
|
return &Note{Title: name, Content: mdTmplHTML(mdContent)}, http.StatusOK
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-11
@@ -54,15 +54,18 @@ type Note struct {
|
|||||||
Content, Ads template.HTML
|
Content, Ads template.HTML
|
||||||
}
|
}
|
||||||
|
|
||||||
func errPage(code int, details ...string) Note {
|
func errPage(code int, details ...string) *Note {
|
||||||
text := errorCodes[code]
|
text := errorCodes[code]
|
||||||
|
body := text
|
||||||
if len(details) > 0 {
|
if len(details) > 0 {
|
||||||
text += ": " + strings.Join(details, ";")
|
body += ": " + strings.Join(details, ";")
|
||||||
}
|
}
|
||||||
return Note{
|
n := &Note{
|
||||||
Title: text,
|
Title: text,
|
||||||
Content: mdTmplHTML([]byte(fmt.Sprintf("# %d %s", code, text))),
|
Text: fmt.Sprintf("# %d %s", code, body),
|
||||||
}
|
}
|
||||||
|
n.prepare()
|
||||||
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Note) prepare() {
|
func (n *Note) prepare() {
|
||||||
@@ -88,13 +91,11 @@ func persistStats(logger echo.Logger, db *sql.DB, stats *sync.Map) {
|
|||||||
stats.Range(func(id, views interface{}) bool {
|
stats.Range(func(id, views interface{}) bool {
|
||||||
stmt, _ := tx.Prepare("update notes set views = ? where id = ?")
|
stmt, _ := tx.Prepare("update notes set views = ? where id = ?")
|
||||||
_, err := stmt.Exec(views, id)
|
_, err := stmt.Exec(views, id)
|
||||||
if err != nil {
|
if err == nil {
|
||||||
tx.Rollback()
|
c++
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
stmt.Close()
|
stmt.Close()
|
||||||
defer stats.Delete(id)
|
defer stats.Delete(id)
|
||||||
c++
|
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
tx.Commit()
|
tx.Commit()
|
||||||
@@ -174,7 +175,7 @@ func randId() string {
|
|||||||
return buf.String()
|
return buf.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func load(c echo.Context, db *sql.DB) (Note, int) {
|
func load(c echo.Context, db *sql.DB) (*Note, int) {
|
||||||
q := c.Param("id")
|
q := c.Param("id")
|
||||||
c.Logger().Debugf("loading note %q", q)
|
c.Logger().Debugf("loading note %q", q)
|
||||||
stmt, _ := db.Prepare("select * from notes where id = ?")
|
stmt, _ := db.Prepare("select * from notes where id = ?")
|
||||||
@@ -198,7 +199,7 @@ func load(c echo.Context, db *sql.DB) (Note, int) {
|
|||||||
if editedVal != nil {
|
if editedVal != nil {
|
||||||
n.Edited = editedVal.(time.Time)
|
n.Edited = editedVal.(time.Time)
|
||||||
}
|
}
|
||||||
return *n, http.StatusOK
|
return n, http.StatusOK
|
||||||
}
|
}
|
||||||
|
|
||||||
var mdRenderer = markdown.New(markdown.HTML(true))
|
var mdRenderer = markdown.New(markdown.HTML(true))
|
||||||
|
|||||||
Reference in New Issue
Block a user