Просмотр исходного кода

splice state management into ResourceStateManager

Brian Gough 9 лет назад
Родитель
Сommit
a84c884fc9

+ 46 - 0
services/clsi/app/coffee/ResourceStateManager.coffee

@@ -0,0 +1,46 @@
+Path = require "path"
+fs = require "fs"
+mkdirp = require "mkdirp"
+logger = require "logger-sharelatex"
+settings = require("settings-sharelatex")
+Errors = require "./Errors"
+
+module.exports = ResourceStateManager =
+
+	# The sync state is an identifier which must match for an
+	# incremental update to be allowed.
+	#
+	# The initial value is passed in and stored on a full
+	# compile.
+	#
+	# Subsequent incremental compiles must come with the same value - if
+	# not they will be rejected with a 409 Conflict response.
+	#
+	# An incremental compile can only update existing files with new
+	# content.  The sync state identifier must change if any docs or
+	# files are moved, added, deleted or renamed.
+
+	SYNC_STATE_FILE: ".project-sync-state"
+
+	saveProjectStateHash: (state, basePath, callback) ->
+		stateFile = Path.join(basePath, @SYNC_STATE_FILE)
+		if not state? # remove the file if no state passed in
+			logger.log state:state, basePath:basePath, "clearing sync state"
+			fs.unlink stateFile, (err) ->
+				if err? and err.code isnt 'ENOENT'
+					return callback(err)
+				else
+					return callback()
+		else
+			logger.log state:state, basePath:basePath, "writing sync state"
+			fs.writeFile stateFile, state, {encoding: 'ascii'}, callback
+
+	checkProjectStateHashMatches: (state, basePath, callback) ->
+		stateFile = Path.join(basePath, @SYNC_STATE_FILE)
+		fs.readFile stateFile, {encoding:'ascii'}, (err, oldState) ->
+			if err? and err.code isnt 'ENOENT'
+				return callback(err)
+			else if state isnt oldState
+				return callback new Errors.FilesOutOfSyncError("invalid state for incremental update")
+			else if state is oldState
+				callback(null)

+ 4 - 43
services/clsi/app/coffee/ResourceWriter.coffee

@@ -4,9 +4,9 @@ fs = require "fs"
 async = require "async"
 mkdirp = require "mkdirp"
 OutputFileFinder = require "./OutputFileFinder"
+ResourceStateManager = require "./ResourceStateManager"
 ResourceListManager = require "./ResourceListManager"
 Metrics = require "./Metrics"
-Errors = require "./Errors"
 logger = require "logger-sharelatex"
 settings = require("settings-sharelatex")
 
@@ -16,9 +16,8 @@ module.exports = ResourceWriter =
 
 	syncResourcesToDisk: (request, basePath, callback = (error, resourceList) ->) ->
 		if request.syncType is "incremental"
-			ResourceWriter.checkSyncState request.syncState, basePath, (error, syncStateOk) ->
-				logger.log syncState: request.syncState, result:syncStateOk, "checked state on incremental request"
-				return callback new Errors.FilesOutOfSyncError("invalid state for incremental update") if not syncStateOk
+			ResourceStateManager.checkProjectStateHashMatches request.syncState, basePath, (error) ->
+				return callback(error) if error?
 				ResourceListManager.loadResourceList basePath, (error, resourceList) ->
 					return callback(error) if error?
 					ResourceWriter._removeExtraneousFiles resourceList, basePath, (error) =>
@@ -26,53 +25,15 @@ module.exports = ResourceWriter =
 						ResourceWriter.saveIncrementalResourcesToDisk request.project_id, request.resources, basePath, (error) ->
 							return callback(error) if error?
 							callback(null, resourceList)
-
 		else
 			@saveAllResourcesToDisk request.project_id, request.resources, basePath, (error) ->
 				return callback(error) if error?
-				ResourceWriter.storeSyncState request.syncState, basePath, (error) ->
+				ResourceStateManager.saveProjectStateHash request.syncState, basePath, (error) ->
 					return callback(error) if error?
 					ResourceListManager.saveResourceList request.resources, basePath, (error) =>
 						return callback(error) if error?
 						callback(null, request.resources)
 
-	# The sync state is an identifier which must match for an
-	# incremental update to be allowed.
-	#
-	# The initial value is passed in and stored on a full
-	# compile.
-	#
-	# Subsequent incremental compiles must come with the same value - if
-	# not they will be rejected with a 409 Conflict response.
-	#
-	# An incremental compile can only update existing files with new
-	# content.  The sync state identifier must change if any docs or
-	# files are moved, added, deleted or renamed.
-
-	SYNC_STATE_FILE: ".project-sync-state"
-
-	storeSyncState: (state, basePath, callback) ->
-		stateFile = Path.join(basePath, @SYNC_STATE_FILE)
-		if not state? # remove the file if no state passed in
-			logger.log state:state, basePath:basePath, "clearing sync state"
-			fs.unlink stateFile, (err) ->
-				if err? and err.code isnt 'ENOENT'
-					return callback(err)
-				else
-					return callback()
-		else
-			logger.log state:state, basePath:basePath, "writing sync state"
-			fs.writeFile stateFile, state, {encoding: 'ascii'}, callback
-
-	checkSyncState: (state, basePath, callback) ->
-		stateFile = Path.join(basePath, @SYNC_STATE_FILE)
-		fs.readFile stateFile, {encoding:'ascii'}, (err, oldState) ->
-			if err? and err.code isnt 'ENOENT'
-				return callback(err)
-			else
-				# return true if state matches, false otherwise (including file not existing)
-				callback(null, if state is oldState then true else false)
-
 	saveIncrementalResourcesToDisk: (project_id, resources, basePath, callback = (error) ->) ->
 		@_createDirectory basePath, (error) =>
 			return callback(error) if error?

+ 29 - 6
services/clsi/test/unit/coffee/ResourceWriterTests.coffee

@@ -11,6 +11,7 @@ describe "ResourceWriter", ->
 				mkdir: sinon.stub().callsArg(1)
 				unlink: sinon.stub().callsArg(1)
 			"./ResourceListManager": @ResourceListManager = {}
+			"./ResourceStateManager": @ResourceStateManager = {}
 			"wrench": @wrench = {}
 			"./UrlCache" : @UrlCache = {}
 			"mkdirp" : @mkdirp = sinon.stub().callsArg(1)
@@ -32,8 +33,8 @@ describe "ResourceWriter", ->
 			]
 			@ResourceWriter._writeResourceToDisk = sinon.stub().callsArg(3)
 			@ResourceWriter._removeExtraneousFiles = sinon.stub().callsArg(2)
-			@ResourceWriter.checkSyncState = sinon.stub().callsArg(2)
-			@ResourceWriter.storeSyncState = sinon.stub().callsArg(2)
+			@ResourceStateManager.checkProjectStateHashMatches = sinon.stub().callsArg(2)
+			@ResourceStateManager.saveProjectStateHash = sinon.stub().callsArg(2)
 			@ResourceListManager.saveResourceList = sinon.stub().callsArg(2)
 			@ResourceListManager.loadResourceList = sinon.stub().callsArg(1)
 			@ResourceWriter.syncResourcesToDisk({
@@ -54,7 +55,7 @@ describe "ResourceWriter", ->
 					.should.equal true
 
 		it "should store the sync state", ->
-			@ResourceWriter.storeSyncState
+			@ResourceStateManager.saveProjectStateHash
 				.calledWith(@syncState, @basePath)
 				.should.equal true
 
@@ -73,8 +74,8 @@ describe "ResourceWriter", ->
 			]
 			@ResourceWriter._writeResourceToDisk = sinon.stub().callsArg(3)
 			@ResourceWriter._removeExtraneousFiles = sinon.stub().callsArg(2)
-			@ResourceWriter.checkSyncState = sinon.stub().callsArgWith(2, null, true)
-			@ResourceWriter.storeSyncState = sinon.stub().callsArg(2)
+			@ResourceStateManager.checkProjectStateHashMatches = sinon.stub().callsArg(2)
+			@ResourceStateManager.saveProjectStateHash = sinon.stub().callsArg(2)
 			@ResourceListManager.saveResourceList = sinon.stub().callsArg(2)
 			@ResourceListManager.loadResourceList = sinon.stub().callsArgWith(1, null, @resources)
 			@ResourceWriter.syncResourcesToDisk({
@@ -85,7 +86,7 @@ describe "ResourceWriter", ->
 			}, @basePath, @callback)
 
 		it "should check the sync state matches", ->
-			@ResourceWriter.checkSyncState
+			@ResourceStateManager.checkProjectStateHashMatches
 				.calledWith(@syncState, @basePath)
 				.should.equal true
 
@@ -103,6 +104,28 @@ describe "ResourceWriter", ->
 		it "should call the callback", ->
 			@callback.called.should.equal true
 
+	describe "syncResourcesToDisk on an incremental update when the state does not match", ->
+		beforeEach ->
+			@resources = [
+				"resource-1-mock"
+			]
+			@ResourceStateManager.checkProjectStateHashMatches = sinon.stub().callsArgWith(2, @error = new Error())
+			@ResourceWriter.syncResourcesToDisk({
+				project_id: @project_id,
+				syncType: "incremental",
+				syncState: @syncState = "1234567890abcdef",
+				resources: @resources
+			}, @basePath, @callback)
+
+		it "should check whether the sync state matches", ->
+			@ResourceStateManager.checkProjectStateHashMatches
+				.calledWith(@syncState, @basePath)
+				.should.equal true
+
+		it "should call the callback with an error", ->
+			@callback.calledWith(@error).should.equal true
+
+
 	describe "_removeExtraneousFiles", ->
 		beforeEach ->
 			@output_files = [{