Initial open source commit

This commit is contained in:
James Allen
2014-02-12 17:27:43 +00:00
commit c83b03e93f
95 changed files with 16218 additions and 0 deletions

View File

@@ -0,0 +1,46 @@
Client = require "./helpers/Client"
request = require "request"
require("chai").should()
describe "Broken LaTeX file", ->
before ->
@broken_request =
resources: [
path: "main.tex"
content: '''
\\documentclass{articl % :(
\\begin{documen % :(
Broken
\\end{documen % :(
'''
]
@correct_request =
resources: [
path: "main.tex"
content: '''
\\documentclass{article}
\\begin{document}
Hello world
\\end{document}
'''
]
describe "on first run", ->
before (done) ->
@project_id = Client.randomId()
Client.compile @project_id, @broken_request, (@error, @res, @body) => done()
it "should return a failure status", ->
@body.compile.status.should.equal "failure"
describe "on second run", ->
before (done) ->
@project_id = Client.randomId()
Client.compile @project_id, @correct_request, () =>
Client.compile @project_id, @broken_request, (@error, @res, @body) =>
done()
it "should return a failure status", ->
@body.compile.status.should.equal "failure"

View File

@@ -0,0 +1,34 @@
Client = require "./helpers/Client"
request = require "request"
require("chai").should()
describe "Deleting Old Files", ->
before ->
@request =
resources: [
path: "main.tex"
content: '''
\\documentclass{article}
\\begin{document}
Hello world
\\end{document}
'''
]
describe "on first run", ->
before (done) ->
@project_id = Client.randomId()
Client.compile @project_id, @request, (@error, @res, @body) => done()
it "should return a success status", ->
@body.compile.status.should.equal "success"
describe "after file has been deleted", ->
before (done) ->
@request.resources = []
Client.compile @project_id, @request, (@error, @res, @body) =>
done()
it "should return a failure status", ->
@body.compile.status.should.equal "failure"

View File

@@ -0,0 +1,79 @@
Client = require "./helpers/Client"
request = require "request"
require("chai").should()
fs = require "fs"
ChildProcess = require "child_process"
fixturePath = (path) -> __dirname + "/../fixtures/" + path
convertToPng = (pdfPath, pngPath, callback = (error) ->) ->
convert = ChildProcess.exec "convert #{fixturePath(pdfPath)} #{fixturePath(pngPath)}"
convert.on "exit", () ->
callback()
compare = (originalPath, generatedPath, callback = (error, same) ->) ->
proc = ChildProcess.exec "compare -metric mae #{fixturePath(originalPath)} #{fixturePath(generatedPath)} #{fixturePath("tmp/diff.png")}"
stderr = ""
proc.stderr.on "data", (chunk) -> stderr += chunk
proc.on "exit", () ->
if stderr.trim() == "0 (0)"
callback null, true
else
console.log stderr
callback null, false
compareMultiplePages = (project_id, callback = (error) ->) ->
compareNext = (page_no, callback) ->
path = "tmp/#{project_id}-source-#{page_no}.png"
fs.stat fixturePath(path), (error, stat) ->
if error?
callback()
else
compare "tmp/#{project_id}-source-#{page_no}.png", "tmp/#{project_id}-generated-#{page_no}.png", (error, same) =>
throw error if error?
same.should.equal true
compareNext page_no + 1, callback
compareNext 0, callback
downloadAndComparePdf = (project_id, example_dir, url, callback = (error) ->) ->
writeStream = fs.createWriteStream(fixturePath("tmp/#{project_id}.pdf"))
request.get(url).pipe(writeStream)
writeStream.on "close", () =>
convertToPng "tmp/#{project_id}.pdf", "tmp/#{project_id}-generated.png", (error) =>
throw error if error?
convertToPng "examples/#{example_dir}/output.pdf", "tmp/#{project_id}-source.png", (error) =>
throw error if error?
fs.stat fixturePath("tmp/#{project_id}-source-0.png"), (error, stat) =>
if error?
compare "tmp/#{project_id}-source.png", "tmp/#{project_id}-generated.png", (error, same) =>
throw error if error?
same.should.equal true
callback()
else
compareMultiplePages project_id, (error) ->
throw error if error?
callback()
Client.runServer(4242, fixturePath("examples"))
describe "Example Documents", ->
before (done) ->
ChildProcess.exec("rm test/acceptance/fixtures/tmp/*").on "exit", () -> done()
for example_dir in fs.readdirSync fixturePath("examples")
do (example_dir) ->
describe example_dir, ->
before ->
@project_id = Client.randomId()
it "should generate the correct pdf", (done) ->
Client.compileDirectory @project_id, fixturePath("examples"), example_dir, 4242, (error, res, body) =>
pdf = Client.getOutputFile body, "pdf"
downloadAndComparePdf(@project_id, example_dir, pdf.url, done)
it "should generate the correct pdf on the second run as well", (done) ->
Client.compileDirectory @project_id, fixturePath("examples"), example_dir, 4242, (error, res, body) =>
pdf = Client.getOutputFile body, "pdf"
downloadAndComparePdf(@project_id, example_dir, pdf.url, done)

View File

@@ -0,0 +1,39 @@
Client = require "./helpers/Client"
request = require "request"
require("chai").should()
describe "Simple LaTeX file", ->
before (done) ->
@project_id = Client.randomId()
@request =
resources: [
path: "main.tex"
content: '''
\\documentclass{article}
\\begin{document}
Hello world
\\end{document}
'''
]
Client.compile @project_id, @request, (@error, @res, @body) => done()
it "should return the PDF", ->
pdf = Client.getOutputFile(@body, "pdf")
pdf.type.should.equal "pdf"
it "should return the log", ->
log = Client.getOutputFile(@body, "log")
log.type.should.equal "log"
it "should provide the pdf for download", (done) ->
pdf = Client.getOutputFile(@body, "pdf")
request.get pdf.url, (error, res, body) ->
res.statusCode.should.equal 200
done()
it "should provide the log for download", (done) ->
log = Client.getOutputFile(@body, "pdf")
request.get log.url, (error, res, body) ->
res.statusCode.should.equal 200
done()

View File

@@ -0,0 +1,27 @@
Client = require "./helpers/Client"
request = require "request"
require("chai").should()
describe "Timed out compile", ->
before (done) ->
@request =
options:
timeout: 0.01 #seconds
resources: [
path: "main.tex"
content: '''
\\documentclass{article}
\\begin{document}
Hello world
\\end{document}
'''
]
@project_id = Client.randomId()
Client.compile @project_id, @request, (@error, @res, @body) => done()
it "should return a timeout error", ->
@body.compile.error.should.equal "container timed out"
it "should return a failure status", ->
@body.compile.status.should.equal "failure"

View File

@@ -0,0 +1,220 @@
Client = require "./helpers/Client"
request = require "request"
require("chai").should()
sinon = require "sinon"
host = "localhost"
Server =
run: () ->
express = require "express"
app = express()
staticServer = express.static __dirname + "/../fixtures/"
app.get "/:random_id/*", (req, res, next) =>
@getFile(req.url)
req.url = "/" + req.params[0]
staticServer(req, res, next)
app.listen 31415, host
getFile: () ->
randomId: () ->
Math.random().toString(16).slice(2)
Server.run()
describe "Url Caching", ->
describe "Downloading an image for the first time", ->
before (done) ->
@project_id = Client.randomId()
@file = "#{Server.randomId()}/lion.png"
@request =
resources: [{
path: "main.tex"
content: '''
\\documentclass{article}
\\usepackage{graphicx}
\\begin{document}
\\includegraphics{lion.png}
\\end{document}
'''
}, {
path: "lion.png"
url: "http://#{host}:31415/#{@file}"
}]
sinon.spy Server, "getFile"
Client.compile @project_id, @request, (@error, @res, @body) => done()
afterEach ->
Server.getFile.restore()
it "should download the image", ->
Server.getFile
.calledWith("/" + @file)
.should.equal true
describe "When an image is in the cache and the last modified date is unchanged", ->
before (done) ->
@project_id = Client.randomId()
@file = "#{Server.randomId()}/lion.png"
@request =
resources: [{
path: "main.tex"
content: '''
\\documentclass{article}
\\usepackage{graphicx}
\\begin{document}
\\includegraphics{lion.png}
\\end{document}
'''
}, @image_resource = {
path: "lion.png"
url: "http://#{host}:31415/#{@file}"
modified: Date.now()
}]
Client.compile @project_id, @request, (@error, @res, @body) =>
sinon.spy Server, "getFile"
Client.compile @project_id, @request, (@error, @res, @body) =>
done()
after ->
Server.getFile.restore()
it "should not download the image again", ->
Server.getFile.called.should.equal false
describe "When an image is in the cache and the last modified date is advanced", ->
before (done) ->
@project_id = Client.randomId()
@file = "#{Server.randomId()}/lion.png"
@request =
resources: [{
path: "main.tex"
content: '''
\\documentclass{article}
\\usepackage{graphicx}
\\begin{document}
\\includegraphics{lion.png}
\\end{document}
'''
}, @image_resource = {
path: "lion.png"
url: "http://#{host}:31415/#{@file}"
modified: @last_modified = Date.now()
}]
Client.compile @project_id, @request, (@error, @res, @body) =>
sinon.spy Server, "getFile"
@image_resource.modified = new Date(@last_modified + 3000)
Client.compile @project_id, @request, (@error, @res, @body) =>
done()
afterEach ->
Server.getFile.restore()
it "should download the image again", ->
Server.getFile.called.should.equal true
describe "When an image is in the cache and the last modified date is further in the past", ->
before (done) ->
@project_id = Client.randomId()
@file = "#{Server.randomId()}/lion.png"
@request =
resources: [{
path: "main.tex"
content: '''
\\documentclass{article}
\\usepackage{graphicx}
\\begin{document}
\\includegraphics{lion.png}
\\end{document}
'''
}, @image_resource = {
path: "lion.png"
url: "http://#{host}:31415/#{@file}"
modified: @last_modified = Date.now()
}]
Client.compile @project_id, @request, (@error, @res, @body) =>
sinon.spy Server, "getFile"
@image_resource.modified = new Date(@last_modified - 3000)
Client.compile @project_id, @request, (@error, @res, @body) =>
done()
afterEach ->
Server.getFile.restore()
it "should not download the image again", ->
Server.getFile.called.should.equal false
describe "When an image is in the cache and the last modified date is not specified", ->
before (done) ->
@project_id = Client.randomId()
@file = "#{Server.randomId()}/lion.png"
@request =
resources: [{
path: "main.tex"
content: '''
\\documentclass{article}
\\usepackage{graphicx}
\\begin{document}
\\includegraphics{lion.png}
\\end{document}
'''
}, @image_resource = {
path: "lion.png"
url: "http://#{host}:31415/#{@file}"
modified: @last_modified = Date.now()
}]
Client.compile @project_id, @request, (@error, @res, @body) =>
sinon.spy Server, "getFile"
delete @image_resource.modified
Client.compile @project_id, @request, (@error, @res, @body) =>
done()
afterEach ->
Server.getFile.restore()
it "should download the image again", ->
Server.getFile.called.should.equal true
describe "After clearing the cache", ->
before (done) ->
@project_id = Client.randomId()
@file = "#{Server.randomId()}/lion.png"
@request =
resources: [{
path: "main.tex"
content: '''
\\documentclass{article}
\\usepackage{graphicx}
\\begin{document}
\\includegraphics{lion.png}
\\end{document}
'''
}, @image_resource = {
path: "lion.png"
url: "http://#{host}:31415/#{@file}"
modified: @last_modified = Date.now()
}]
Client.compile @project_id, @request, (error) =>
throw error if error?
Client.clearCache @project_id, (error, res, body) =>
throw error if error?
sinon.spy Server, "getFile"
Client.compile @project_id, @request, (@error, @res, @body) =>
done()
afterEach ->
Server.getFile.restore()
it "should download the image again", ->
Server.getFile.called.should.equal true

View File

@@ -0,0 +1,69 @@
request = require "request"
fs = require "fs"
Settings = require "../../../../app/js/Settings"
host = "localhost"
module.exports = Client =
host: Settings.externalUrl
randomId: () ->
Math.random().toString(16).slice(2)
compile: (project_id, data, callback = (error, res, body) ->) ->
request.post {
url: "#{@host}/project/#{project_id}/compile"
json:
compile: data
}, callback
clearCache: (project_id, callback = (error, res, body) ->) ->
request.del "#{@host}/project/#{project_id}", callback
getOutputFile: (response, type) ->
for file in response.compile.outputFiles
if file.type == type
return file
return null
runServer: (port, directory) ->
express = require("express")
app = express()
app.use express.static(directory)
app.listen(port, host)
compileDirectory: (project_id, baseDirectory, directory, serverPort, callback = (error, res, body) ->) ->
resources = []
entities = fs.readdirSync("#{baseDirectory}/#{directory}")
rootResourcePath = "main.tex"
while (entities.length > 0)
entity = entities.pop()
stat = fs.statSync("#{baseDirectory}/#{directory}/#{entity}")
if stat.isDirectory()
entities = entities.concat fs.readdirSync("#{baseDirectory}/#{directory}/#{entity}").map (subEntity) ->
if subEntity == "main.tex"
rootResourcePath = "#{entity}/#{subEntity}"
return "#{entity}/#{subEntity}"
else if stat.isFile() and entity != "output.pdf"
extension = entity.split(".").pop()
if ["tex", "bib", "cls", "sty", "pdf_tex", "Rtex"].indexOf(extension) > -1
resources.push
path: entity
content: fs.readFileSync("#{baseDirectory}/#{directory}/#{entity}").toString()
else if ["eps", "ttf", "png", "jpg", "pdf", "jpeg"].indexOf(extension) > -1
resources.push
path: entity
url: "http://#{host}:#{serverPort}/#{directory}/#{entity}"
modified: stat.mtime
fs.readFile "#{baseDirectory}/#{directory}/options.json", (error, body) =>
req =
resources: resources
rootResourcePath: rootResourcePath
if !error?
body = JSON.parse body
req.options = body
@compile project_id, req, callback