Browse Source

api tests added

master
Christian Müller 8 years ago
parent
commit
f0b588d081
  1. 2
      .gitignore
  2. 1
      .jshintrc
  3. 10
      .tern-project
  4. 2
      Gopkg.lock
  5. 5
      Makefile
  6. 201
      api_spec.js
  7. 11
      package.json
  8. 6
      server.go
  9. 21
      storage.go

2
.gitignore vendored

@ -1,5 +1,3 @@ @@ -1,5 +1,3 @@
dump.rdb
bin/
node_modules/
npm-debug.log
database.sqlite-journal

1
.jshintrc

@ -1 +0,0 @@ @@ -1 +0,0 @@
{ "esnext": true }

10
.tern-project

@ -1,10 +0,0 @@ @@ -1,10 +0,0 @@
{
"plugins": {
"node": {}
},
"libs": [
"ecma5",
"ecma6"
],
"ecmaVersion": 6
}

2
Gopkg.lock generated

@ -76,6 +76,6 @@ @@ -76,6 +76,6 @@
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "82edf4a4585c9ad3318ead49e58d8bca7efed18e2f727be8e8fc6498972fc039"
inputs-digest = "441429b4f331d40009b166378491cbd1b7e797135151d16d79394725cfbe16a2"
solver-name = "gps-cdcl"
solver-version = 1

5
Makefile

@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
run:
go run *.go
test:
jasmine-node .

201
api_spec.js

@ -0,0 +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();

11
package.json

@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
{
"name": "NoteHub",
"version": "3.0.0",
"main": "server.js",
"scripts": {
"test": "jasmine-node ."
},
"devDependencies": {
"frisby": "^0.8.5"
}
}

6
server.go

@ -142,7 +142,7 @@ func main() { @@ -142,7 +142,7 @@ func main() {
code = http.StatusBadRequest
}
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)
return c.Redirect(http.StatusMovedPermanently, "/"+n.ID)
@ -160,7 +160,7 @@ func get(vals url.Values, key string) string { @@ -160,7 +160,7 @@ func get(vals url.Values, key string) string {
return ""
}
func md2html(c echo.Context, name string) (Note, int) {
func md2html(c echo.Context, name string) (*Note, int) {
path := "assets/markdown/" + name + ".md"
mdContent, err := ioutil.ReadFile(path)
if err != nil {
@ -169,5 +169,5 @@ func md2html(c echo.Context, name string) (Note, int) { @@ -169,5 +169,5 @@ func md2html(c echo.Context, name string) (Note, int) {
return errPage(code), code
}
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
}

21
storage.go

@ -54,15 +54,18 @@ type Note struct { @@ -54,15 +54,18 @@ type Note struct {
Content, Ads template.HTML
}
func errPage(code int, details ...string) Note {
func errPage(code int, details ...string) *Note {
text := errorCodes[code]
body := text
if len(details) > 0 {
text += ": " + strings.Join(details, ";")
body += ": " + strings.Join(details, ";")
}
return Note{
n := &Note{
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() {
@ -88,13 +91,11 @@ func persistStats(logger echo.Logger, db *sql.DB, stats *sync.Map) { @@ -88,13 +91,11 @@ func persistStats(logger echo.Logger, db *sql.DB, stats *sync.Map) {
stats.Range(func(id, views interface{}) bool {
stmt, _ := tx.Prepare("update notes set views = ? where id = ?")
_, err := stmt.Exec(views, id)
if err != nil {
tx.Rollback()
return false
if err == nil {
c++
}
stmt.Close()
defer stats.Delete(id)
c++
return true
})
tx.Commit()
@ -174,7 +175,7 @@ func randId() string { @@ -174,7 +175,7 @@ func randId() 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")
c.Logger().Debugf("loading note %q", q)
stmt, _ := db.Prepare("select * from notes where id = ?")
@ -198,7 +199,7 @@ func load(c echo.Context, db *sql.DB) (Note, int) { @@ -198,7 +199,7 @@ func load(c echo.Context, db *sql.DB) (Note, int) {
if editedVal != nil {
n.Edited = editedVal.(time.Time)
}
return *n, http.StatusOK
return n, http.StatusOK
}
var mdRenderer = markdown.New(markdown.HTML(true))

Loading…
Cancel
Save