diff --git a/lib/dist.js b/lib/dist.js index 6542401..212db76 100644 --- a/lib/dist.js +++ b/lib/dist.js @@ -85,14 +85,21 @@ module.exports = return new EventData(eventId, type, isJson, data, metadata); } + // Exporting classes module.exports.EventStoreConnection = __webpack_require__(6); - module.exports.UserCredentials = __webpack_require__(62); + module.exports.UserCredentials = __webpack_require__(65); module.exports.EventData = EventData; - module.exports.PersistentSubscriptionSettings = __webpack_require__(63); - module.exports.SystemConsumerStrategies = __webpack_require__(49); + module.exports.PersistentSubscriptionSettings = __webpack_require__(66); + module.exports.SystemConsumerStrategies = __webpack_require__(52); + // Exporting errors + module.exports.WrongExpectedVersionError = __webpack_require__(34); + module.exports.StreamDeletedError = __webpack_require__(35); + module.exports.AccessDeniedError = __webpack_require__(36); + // Exporting enums/constants module.exports.expectedVersion = expectedVersion; module.exports.positions = positions; - + module.exports.systemMetadata = __webpack_require__(67); + module.exports.eventReadStatus = results.EventReadStatus; // Helper functions module.exports.createConnection = module.exports.EventStoreConnection.create; module.exports.createEventData = eventDataFactory; @@ -529,13 +536,25 @@ module.exports = throw new Error(name + " is null."); }; + module.exports.isInteger = function(value, name) { + if (typeof value !== 'number' || value % 1 !== 0) + throw new TypeError(name + " is not an integer."); + }; + + module.exports.isArrayOf = function(expectedType, value, name) { + if (!Array.isArray(value)) + throw new TypeError(name + " is not an array."); + if (!value.every(function(x) { return x instanceof expectedType; })) + throw new TypeError([name, " is not an array of ", expectedType, "."].join("")); + }; + /***/ }, /* 6 */ /***/ function(module, exports, __webpack_require__) { var EventStoreNodeConnection = __webpack_require__(7); - var StaticEndpointDiscoverer = __webpack_require__(60); - var NoopLogger = __webpack_require__(61); + var StaticEndpointDiscoverer = __webpack_require__(63); + var NoopLogger = __webpack_require__(64); var defaultConnectionSettings = { log: new NoopLogger(), @@ -602,27 +621,27 @@ module.exports = var EventStoreConnectionLogicHandler = __webpack_require__(10); var DeleteStreamOperation = __webpack_require__(33); - var AppendToStreamOperation = __webpack_require__(35); - var StartTransactionOperation = __webpack_require__(36); - var TransactionalWriteOperation = __webpack_require__(38); - var CommitTransactionOperation = __webpack_require__(39); - var ReadEventOperation = __webpack_require__(40); - var ReadStreamEventsForwardOperation = __webpack_require__(41); - var ReadStreamEventsBackwardOperation = __webpack_require__(45); - var ReadAllEventsForwardOperation = __webpack_require__(46); - var ReadAllEventsBackwardOperation = __webpack_require__(47); - var CreatePersistentSubscriptionOperation = __webpack_require__(48); - var UpdatePersistentSubscriptionOperation = __webpack_require__(50); - var DeletePersistentSubscriptionOperation = __webpack_require__(51); + var AppendToStreamOperation = __webpack_require__(38); + var StartTransactionOperation = __webpack_require__(39); + var TransactionalWriteOperation = __webpack_require__(41); + var CommitTransactionOperation = __webpack_require__(42); + var ReadEventOperation = __webpack_require__(43); + var ReadStreamEventsForwardOperation = __webpack_require__(44); + var ReadStreamEventsBackwardOperation = __webpack_require__(48); + var ReadAllEventsForwardOperation = __webpack_require__(49); + var ReadAllEventsBackwardOperation = __webpack_require__(50); + var CreatePersistentSubscriptionOperation = __webpack_require__(51); + var UpdatePersistentSubscriptionOperation = __webpack_require__(53); + var DeletePersistentSubscriptionOperation = __webpack_require__(54); - var EventStoreTransaction = __webpack_require__(37); - var EventStoreStreamCatchUpSubscription = __webpack_require__(52); - var EventStoreAllCatchUpSubscription = __webpack_require__(54); - var EventStorePersistentSubscription = __webpack_require__(55); + var EventStoreTransaction = __webpack_require__(40); + var EventStoreStreamCatchUpSubscription = __webpack_require__(55); + var EventStoreAllCatchUpSubscription = __webpack_require__(57); + var EventStorePersistentSubscription = __webpack_require__(58); var results = __webpack_require__(3); - var systemStreams = __webpack_require__(58); - var systemEventTypes = __webpack_require__(59); + var systemStreams = __webpack_require__(61); + var systemEventTypes = __webpack_require__(62); var EventData = __webpack_require__(1); /** @@ -691,8 +710,10 @@ module.exports = * @returns {Promise.} */ EventStoreNodeConnection.prototype.deleteStream = function(stream, expectedVersion, hardDelete, userCredentials) { - if (typeof stream !== 'string' || stream === '') throw new TypeError("stream must be an non-empty string."); - if (typeof expectedVersion !== 'number' || expectedVersion % 1 !== 0) throw new TypeError("expectedVersion must be an integer."); + ensure.notNullOrEmpty(stream, "stream"); + ensure.isInteger(expectedVersion, "expectedVersion"); + hardDelete = !!hardDelete; + userCredentials = userCredentials || null; var self = this; return new Promise(function(resolve, reject) { @@ -702,8 +723,7 @@ module.exports = } var deleteStreamOperation = new DeleteStreamOperation( - self._settings.log, cb, self._settings.requireMaster, stream, expectedVersion, - !!hardDelete, userCredentials || null); + self._settings.log, cb, self._settings.requireMaster, stream, expectedVersion, hardDelete, userCredentials); self._enqueueOperation(deleteStreamOperation); }); }; @@ -712,14 +732,17 @@ module.exports = * Append events to a stream (async) * @param {string} stream The name of the stream to which to append. * @param {number} expectedVersion The version at which we currently expect the stream to be in order that an optimistic concurrency check can be performed. - * @param {Array.} events The events to append. + * @param {EventData[]|EventData} events The event(s) to append. * @param {UserCredentials} [userCredentials] User credentials * @returns {Promise.} */ EventStoreNodeConnection.prototype.appendToStream = function(stream, expectedVersion, events, userCredentials) { - if (typeof stream !== 'string' || stream === '') throw new TypeError("stream must be an non-empty string."); - if (typeof expectedVersion !== 'number' || expectedVersion % 1 !== 0) throw new TypeError("expectedVersion must be an integer."); - if (!Array.isArray(events)) throw new TypeError("events must be an array."); + ensure.notNullOrEmpty(stream, "stream"); + ensure.isInteger(expectedVersion, "expectedVersion"); + if (!Array.isArray(events)) + events = [events]; + ensure.isArrayOf(EventData, events, "events"); + userCredentials = userCredentials || null; var self = this; return new Promise(function(resolve, reject) { @@ -728,7 +751,7 @@ module.exports = resolve(result); } var operation = new AppendToStreamOperation(self._settings.log, cb, self._settings.requireMaster, stream, - expectedVersion, events, userCredentials || null); + expectedVersion, events, userCredentials); self._enqueueOperation(operation); }); }; @@ -1185,7 +1208,7 @@ module.exports = case results.EventReadStatus.NoStream: return new results.RawStreamMetadataResult(stream, false, -1, null); case results.EventReadStatus.StreamDeleted: - return new results.RawStreamMetadataResult(stream, true, Number.MAX_VALUE, null); + return new results.RawStreamMetadataResult(stream, true, 0x7fffffff, null); default: throw new Error(util.format("Unexpected ReadEventResult: %s.", res.status)); } @@ -1454,15 +1477,15 @@ module.exports = EventStoreConnectionLogicHandler.prototype._discoverEndpoint = function(cb) { this._logDebug('DiscoverEndpoint'); - if (this._state != ConnectionState.Connecting) return; - if (this._connectingPhase != ConnectingPhase.Reconnecting) return; + if (this._state !== ConnectionState.Connecting) return; + if (this._connectingPhase !== ConnectingPhase.Reconnecting) return; this._connectingPhase = ConnectingPhase.EndPointDiscovery; cb = cb || function() {}; var self = this; - this._endpointDiscoverer.discover(this._connection != null ? this._connection.remoteEndPoint : null) + this._endpointDiscoverer.discover(this._connection !== null ? this._connection.remoteEndPoint : null) .then(function(nodeEndpoints){ self.enqueueMessage(new messages.EstablishTcpConnectionMessage(nodeEndpoints)); cb(); @@ -1920,7 +1943,6 @@ module.exports = { case ConnectionState.Init: break; case ConnectionState.Connecting: - { if (this._connectingPhase == ConnectingPhase.Reconnecting && Date.now() - this._reconnInfo.timeStamp >= this._settings.reconnectionDelay) { this._logDebug("TimerTick checking reconnection..."); @@ -1934,17 +1956,15 @@ module.exports = this._discoverEndpoint(null); } } - if (this._connectingPhase == ConnectingPhase.Authentication && Date.now() - this._authInfo.timeStamp >= this._settings.operationTimeout) + else if (this._connectingPhase == ConnectingPhase.Authentication && Date.now() - this._authInfo.timeStamp >= this._settings.operationTimeout) { this.emit('authenticationFailed', "Authentication timed out."); this._goToConnectedState(); } - if (this._connectingPhase > ConnectingPhase.ConnectionEstablishing) + else if (this._connectingPhase > ConnectingPhase.ConnectionEstablishing) this._manageHeartbeats(); break; - } case ConnectionState.Connected: - { // operations timeouts are checked only if connection is established and check period time passed if (Date.now() - this._lastTimeoutsTimeStamp >= this._settings.operationTimeoutCheckPeriod) { @@ -1958,7 +1978,6 @@ module.exports = } this._manageHeartbeats(); break; - } case ConnectionState.Closed: break; default: @@ -2137,21 +2156,25 @@ module.exports = }); } Object.defineProperty(TcpPackageConnection.prototype, 'connectionId', { + enumerable: true, get: function() { return this._connectionId; } }); Object.defineProperty(TcpPackageConnection.prototype, 'isClosed', { + enumerable: true, get: function() { return this._connection.isClosed; } }); Object.defineProperty(TcpPackageConnection.prototype, 'remoteEndPoint', { + enumerable: true, get: function() { return this._connection.remoteEndPoint; } }); Object.defineProperty(TcpPackageConnection.prototype, 'localEndPoint', { + enumerable: true, get: function() { return this._connection.localEndPoint; } @@ -2355,11 +2378,13 @@ module.exports = this._receiveQueue = []; Object.defineProperty(this, 'remoteEndPoint', { + enumerable: true, get: function() { return this._remoteEndPoint; } }); Object.defineProperty(this, 'localEndPoint', { + enumerable: true, get: function() { return this._localEndPoint; } @@ -3731,8 +3756,11 @@ module.exports = var InspectionResult = __webpack_require__(27); var ClientMessage = __webpack_require__(28); var results = __webpack_require__(3); + var WrongExpectedVersionError = __webpack_require__(34); + var StreamDeletedError = __webpack_require__(35); + var AccessDeniedError = __webpack_require__(36); - var OperationBase = __webpack_require__(34); + var OperationBase = __webpack_require__(37); function DeleteStreamOperation(log, cb, requireMaster, stream, expectedVersion, hardDelete, userCredentials) { @@ -3763,17 +3791,16 @@ module.exports = case ClientMessage.OperationResult.ForwardTimeout: return new InspectionResult(InspectionDecision.Retry, "ForwardTimeout"); case ClientMessage.OperationResult.WrongExpectedVersion: - var err = util.format("Delete stream failed due to WrongExpectedVersion. Stream: %s, Expected version: %d.", this._stream, this._expectedVersion); - this.fail(new Error("Wrong expected version: " + err)); + this.fail(new WrongExpectedVersionError("Delete", this._stream, this._expectedVersion)); return new InspectionResult(InspectionDecision.EndOperation, "WrongExpectedVersion"); case ClientMessage.OperationResult.StreamDeleted: - this.fail(new Error("Stream deleted: " + this._stream)); + this.fail(new StreamDeletedError(this._stream)); return new InspectionResult(InspectionDecision.EndOperation, "StreamDeleted"); case ClientMessage.OperationResult.InvalidTransaction: this.fail(new Error("Invalid transaction.")); return new InspectionResult(InspectionDecision.EndOperation, "InvalidTransaction"); case ClientMessage.OperationResult.AccessDenied: - this.fail(new Error(util.format("Write access denied for stream '%s'.", this._stream))); + this.fail(new AccessDeniedError("Delete", this._stream)); return new InspectionResult(InspectionDecision.EndOperation, "AccessDenied"); default: throw new Error(util.format("Unexpected OperationResult: %d.", response.result)); @@ -3796,12 +3823,63 @@ module.exports = var util = __webpack_require__(4); + function WrongExpectedVersionError(action, stream, expectedVersion) { + Error.captureStackTrace(this, this.constructor); + this.name = this.constructor.name; + this.message = util.format("%s failed due to WrongExpectedVersion. Stream: %s Expected version: %d.", action, stream, expectedVersion); + this.action = action; + this.stream = stream; + this.expectedVersion = expectedVersion; + } + util.inherits(WrongExpectedVersionError, Error); + + module.exports = WrongExpectedVersionError; + +/***/ }, +/* 35 */ +/***/ function(module, exports, __webpack_require__) { + + var util = __webpack_require__(4); + + function StreamDeletedError(stream) { + Error.captureStackTrace(this, this.constructor); + this.name = this.constructor.name; + this.message = util.format("Event stream '%s' is deleted.", stream); + this.stream = stream; + } + util.inherits(StreamDeletedError, Error); + + module.exports = StreamDeletedError; + +/***/ }, +/* 36 */ +/***/ function(module, exports, __webpack_require__) { + + var util = __webpack_require__(4); + + function AccessDeniedError(action, stream) { + Error.captureStackTrace(this, this.constructor); + this.name = this.constructor.name; + this.message = util.format("%s access denied for stream '%s'.", action, stream); + this.action = action; + this.stream = stream; + } + util.inherits(AccessDeniedError, Error); + + module.exports = AccessDeniedError; + +/***/ }, +/* 37 */ +/***/ function(module, exports, __webpack_require__) { + + var util = __webpack_require__(4); + var TcpPackage = __webpack_require__(17); var TcpCommand = __webpack_require__(19); var TcpFlags = __webpack_require__(18); var InspectionDecision = __webpack_require__(26); var ClientMessage = __webpack_require__(28); - var createInspectionResult = __webpack_require__(27); + var InspectionResult = __webpack_require__(27); var createBufferSegment = __webpack_require__(14); function OperationBase(log, cb, requestCommand, responseCommand, userCredentials) { @@ -3875,7 +3953,7 @@ module.exports = } } catch(e) { this.fail(e); - return createInspectionResult(InspectionDecision.EndOperation, "Error - " + e.message); + return new InspectionResult(InspectionDecision.EndOperation, "Error - " + e.message); } }; @@ -3887,7 +3965,7 @@ module.exports = } catch(e) {} //TODO typed error this.fail(new Error("Authentication error: " + message)); - return createInspectionResult(InspectionDecision.EndOperation, "NotAuthenticated"); + return new InspectionResult(InspectionDecision.EndOperation, "NotAuthenticated"); }; OperationBase.prototype._inspectBadRequest = function(pkg) @@ -3898,7 +3976,7 @@ module.exports = } catch(e) {} //TODO typed error this.fail(new Error("Bad request: " + message)); - return createInspectionResult(InspectionDecision.EndOperation, "BadRequest - " + message); + return new InspectionResult(InspectionDecision.EndOperation, "BadRequest - " + message); }; OperationBase.prototype._inspectNotHandled = function(pkg) @@ -3907,20 +3985,20 @@ module.exports = switch (message.reason) { case ClientMessage.NotHandled.NotHandledReason.NotReady: - return createInspectionResult(InspectionDecision.Retry, "NotHandled - NotReady"); + return new InspectionResult(InspectionDecision.Retry, "NotHandled - NotReady"); case ClientMessage.NotHandled.NotHandledReason.TooBusy: - return createInspectionResult(InspectionDecision.Retry, "NotHandled - TooBusy"); + return new InspectionResult(InspectionDecision.Retry, "NotHandled - TooBusy"); case ClientMessage.NotHandled.NotHandledReason.NotMaster: var masterInfo = ClientMessage.NotHandled.MasterInfo.decode(message.additional_info); - return new InspectionResult(InspectionDecision.Reconnect, "NotHandled - NotMaster", + return new new InspectionResult(InspectionDecision.Reconnect, "NotHandled - NotMaster", {host: masterInfo.external_tcp_address, port: masterInfo.external_tcp_port}, {host: masterInfo.external_secure_tcp_address, port: masterInfo.external_secure_tcp_port}); default: this.log.error("Unknown NotHandledReason: %s.", message.reason); - return createInspectionResult(InspectionDecision.Retry, "NotHandled - "); + return new InspectionResult(InspectionDecision.Retry, "NotHandled - "); } }; @@ -3937,7 +4015,7 @@ module.exports = this.constructor.name, this, pkg.data); this.fail(new Error(util.format("Unexpected command. Expecting %s got %s.", TcpCommand.getName(expectedCommand), TcpCommand.getName(pkg.command)))); - return createInspectionResult(InspectionDecision.EndOperation, "Unexpected command - " + TcpCommand.getName(pkg.command)); + return new InspectionResult(InspectionDecision.EndOperation, "Unexpected command - " + TcpCommand.getName(pkg.command)); }; @@ -3945,7 +4023,7 @@ module.exports = /***/ }, -/* 35 */ +/* 38 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(4); @@ -3957,8 +4035,11 @@ module.exports = var ClientMessage = __webpack_require__(28); var WriteResult = __webpack_require__(3).WriteResult; var Position = __webpack_require__(3).Position; + var WrongExpectedVersionError = __webpack_require__(34); + var StreamDeletedError = __webpack_require__(35); + var AccessDeniedError = __webpack_require__(36); - var OperationBase = __webpack_require__(34); + var OperationBase = __webpack_require__(37); function AppendToStreamOperation(log, cb, requireMaster, stream, expectedVersion, events, userCredentials) { OperationBase.call(this, log, cb, TcpCommand.WriteEvents, TcpCommand.WriteEventsCompleted, userCredentials); @@ -4002,17 +4083,16 @@ module.exports = this._wasCommitTimeout = true; return new InspectionResult(InspectionDecision.Retry, "CommitTimeout"); case ClientMessage.OperationResult.WrongExpectedVersion: - var err = ["Append failed due to WrongExpectedVersion. Stream: ", this._stream,", Expected version: ", this._expectedVersion].join(''); - this.fail(new Error(err)); + this.fail(new WrongExpectedVersionError("Append", this._stream, this._expectedVersion)); return new InspectionResult(InspectionDecision.EndOperation, "WrongExpectedVersion"); case ClientMessage.OperationResult.StreamDeleted: - this.fail(new Error("Stream deleted. Stream: " + this._stream)); + this.fail(new StreamDeletedError(this._stream)); return new InspectionResult(InspectionDecision.EndOperation, "StreamDeleted"); case ClientMessage.OperationResult.InvalidTransaction: this.fail(new Error("Invalid transaction.")); return new InspectionResult(InspectionDecision.EndOperation, "InvalidTransaction"); case ClientMessage.OperationResult.AccessDenied: - this.fail(new Error(["Write access denied for stream '", this._stream, "'."].join(''))); + this.fail(new AccessDeniedError("Write", this._stream)); return new InspectionResult(InspectionDecision.EndOperation, "AccessDenied"); default: throw new Error("Unexpected OperationResult: " + response.result); @@ -4031,7 +4111,7 @@ module.exports = /***/ }, -/* 36 */ +/* 39 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(4); @@ -4041,10 +4121,10 @@ module.exports = var InspectionDecision = __webpack_require__(26); var InspectionResult = __webpack_require__(27); var ClientMessage = __webpack_require__(28); - var EventStoreTransaction = __webpack_require__(37); + var EventStoreTransaction = __webpack_require__(40); var results = __webpack_require__(3); - var OperationBase = __webpack_require__(34); + var OperationBase = __webpack_require__(37); function StartTransactionOperation(log, cb, requireMaster, stream, expectedVersion, parentConnection, userCredentials) { OperationBase.call(this, log, cb, TcpCommand.TransactionStart, TcpCommand.TransactionStartCompleted, userCredentials); @@ -4103,7 +4183,7 @@ module.exports = /***/ }, -/* 37 */ +/* 40 */ /***/ function(module, exports) { /** @@ -4161,7 +4241,7 @@ module.exports = module.exports = EventStoreTransaction; /***/ }, -/* 38 */ +/* 41 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(4); @@ -4172,7 +4252,7 @@ module.exports = var InspectionResult = __webpack_require__(27); var ClientMessage = __webpack_require__(28); - var OperationBase = __webpack_require__(34); + var OperationBase = __webpack_require__(37); function TransactionalWriteOperation(log, cb, requireMaster, transactionId, events, userCredentials) { @@ -4229,7 +4309,7 @@ module.exports = /***/ }, -/* 39 */ +/* 42 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(4); @@ -4241,7 +4321,7 @@ module.exports = var ClientMessage = __webpack_require__(28); var results = __webpack_require__(3); - var OperationBase = __webpack_require__(34); + var OperationBase = __webpack_require__(37); function CommitTransactionOperation(log, cb, requireMaster, transactionId, userCredentials) { @@ -4299,7 +4379,7 @@ module.exports = module.exports = CommitTransactionOperation; /***/ }, -/* 40 */ +/* 43 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(4); @@ -4309,8 +4389,9 @@ module.exports = var InspectionResult = __webpack_require__(27); var InspectionDecision = __webpack_require__(26); var results = __webpack_require__(3); + var AccessDeniedError = __webpack_require__(36); - var OperationBase = __webpack_require__(34); + var OperationBase = __webpack_require__(37); function ReadEventOperation(log, cb, stream, eventNumber, resolveLinkTos, requireMaster, userCredentials) { OperationBase.call(this, log, cb, TcpCommand.ReadEvent, TcpCommand.ReadEventCompleted, userCredentials); @@ -4346,7 +4427,7 @@ module.exports = this.fail(new Error("Server error: " + response.error)); return new InspectionResult(InspectionDecision.EndOperation, "Error"); case ClientMessage.ReadEventCompleted.ReadEventResult.AccessDenied: - this.fail(new Error(util.format("Read access denied for stream '%s'.", this._stream))); + this.fail(new AccessDeniedError("Read", this._stream)); return new InspectionResult(InspectionDecision.EndOperation, "AccessDenied"); default: throw new Error(util.format("Unexpected ReadEventResult: %s.", response.result)); @@ -4384,7 +4465,7 @@ module.exports = /***/ }, -/* 41 */ +/* 44 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(4); @@ -4392,13 +4473,13 @@ module.exports = var TcpCommand = __webpack_require__(19); var ClientMessage = __webpack_require__(28); - var ReadDirection = __webpack_require__(42); - var StatusCode = __webpack_require__(43); + var ReadDirection = __webpack_require__(45); + var StatusCode = __webpack_require__(46); var InspectionResult = __webpack_require__(27); var InspectionDecision = __webpack_require__(26); var results = __webpack_require__(3); - var OperationBase = __webpack_require__(34); + var OperationBase = __webpack_require__(37); function ReadStreamEventsForwardOperation( log, cb, stream, fromEventNumber, maxCount, resolveLinkTos, requireMaster, userCredentials @@ -4463,7 +4544,7 @@ module.exports = /***/ }, -/* 42 */ +/* 45 */ /***/ function(module, exports) { const ReadDirection = { @@ -4475,11 +4556,11 @@ module.exports = /***/ }, -/* 43 */ +/* 46 */ /***/ function(module, exports, __webpack_require__) { var ClientMessage = __webpack_require__(28); - var SliceReadStatus = __webpack_require__(44); + var SliceReadStatus = __webpack_require__(47); module.exports = {}; @@ -4497,7 +4578,7 @@ module.exports = }; /***/ }, -/* 44 */ +/* 47 */ /***/ function(module, exports) { const SliceReadStatus = { @@ -4510,7 +4591,7 @@ module.exports = /***/ }, -/* 45 */ +/* 48 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(4); @@ -4518,13 +4599,13 @@ module.exports = var TcpCommand = __webpack_require__(19); var ClientMessage = __webpack_require__(28); - var ReadDirection = __webpack_require__(42); - var StatusCode = __webpack_require__(43); + var ReadDirection = __webpack_require__(45); + var StatusCode = __webpack_require__(46); var InspectionResult = __webpack_require__(27); var InspectionDecision = __webpack_require__(26); var results = __webpack_require__(3); - var OperationBase = __webpack_require__(34); + var OperationBase = __webpack_require__(37); function ReadStreamEventsBackwardOperation( log, cb, stream, fromEventNumber, maxCount, resolveLinkTos, requireMaster, userCredentials @@ -4589,7 +4670,7 @@ module.exports = /***/ }, -/* 46 */ +/* 49 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(4); @@ -4597,12 +4678,12 @@ module.exports = var TcpCommand = __webpack_require__(19); var ClientMessage = __webpack_require__(28); - var ReadDirection = __webpack_require__(42); + var ReadDirection = __webpack_require__(45); var InspectionResult = __webpack_require__(27); var InspectionDecision = __webpack_require__(26); var results = __webpack_require__(3); - var OperationBase = __webpack_require__(34); + var OperationBase = __webpack_require__(37); function ReadAllEventsForwardOperation( log, cb, position, maxCount, resolveLinkTos, requireMaster, userCredentials @@ -4656,7 +4737,7 @@ module.exports = /***/ }, -/* 47 */ +/* 50 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(4); @@ -4664,12 +4745,12 @@ module.exports = var TcpCommand = __webpack_require__(19); var ClientMessage = __webpack_require__(28); - var ReadDirection = __webpack_require__(42); + var ReadDirection = __webpack_require__(45); var InspectionResult = __webpack_require__(27); var InspectionDecision = __webpack_require__(26); var results = __webpack_require__(3); - var OperationBase = __webpack_require__(34); + var OperationBase = __webpack_require__(37); function ReadAllEventsBackwardOperation( log, cb, position, maxCount, resolveLinkTos, requireMaster, userCredentials @@ -4723,17 +4804,17 @@ module.exports = /***/ }, -/* 48 */ +/* 51 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(4); var uuid = __webpack_require__(2); var ensure = __webpack_require__(5); - var OperationBase = __webpack_require__(34); + var OperationBase = __webpack_require__(37); var TcpCommand = __webpack_require__(19); var ClientMessage = __webpack_require__(28); - var SystemConsumerStrategies = __webpack_require__(49); + var SystemConsumerStrategies = __webpack_require__(52); var InspectionDecision = __webpack_require__(26); var InspectionResult = __webpack_require__(27); var results = __webpack_require__(3); @@ -4803,7 +4884,7 @@ module.exports = /***/ }, -/* 49 */ +/* 52 */ /***/ function(module, exports) { const SystemConsumerStrategies = { @@ -4816,17 +4897,17 @@ module.exports = /***/ }, -/* 50 */ +/* 53 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(4); var uuid = __webpack_require__(2); var ensure = __webpack_require__(5); - var OperationBase = __webpack_require__(34); + var OperationBase = __webpack_require__(37); var TcpCommand = __webpack_require__(19); var ClientMessage = __webpack_require__(28); - var SystemConsumerStrategies = __webpack_require__(49); + var SystemConsumerStrategies = __webpack_require__(52); var InspectionDecision = __webpack_require__(26); var InspectionResult = __webpack_require__(27); var results = __webpack_require__(3); @@ -4896,14 +4977,14 @@ module.exports = /***/ }, -/* 51 */ +/* 54 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(4); var uuid = __webpack_require__(2); var ensure = __webpack_require__(5); - var OperationBase = __webpack_require__(34); + var OperationBase = __webpack_require__(37); var TcpCommand = __webpack_require__(19); var ClientMessage = __webpack_require__(28); var InspectionDecision = __webpack_require__(26); @@ -4957,13 +5038,13 @@ module.exports = /***/ }, -/* 52 */ +/* 55 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(4); - var EventStoreCatchUpSubscription = __webpack_require__(53); - var SliceReadStatus = __webpack_require__(44); + var EventStoreCatchUpSubscription = __webpack_require__(56); + var SliceReadStatus = __webpack_require__(47); function EventStoreStreamCatchUpSubscription( connection, log, streamId, fromEventNumberExclusive, resolveLinkTos, userCredentials, @@ -5055,7 +5136,7 @@ module.exports = /***/ }, -/* 53 */ +/* 56 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(4); @@ -5313,12 +5394,12 @@ module.exports = module.exports = EventStoreCatchUpSubscription; /***/ }, -/* 54 */ +/* 57 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(4); - var EventStoreCatchUpSubscription = __webpack_require__(53); + var EventStoreCatchUpSubscription = __webpack_require__(56); var results = __webpack_require__(3); @@ -5403,12 +5484,12 @@ module.exports = /***/ }, -/* 55 */ +/* 58 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(4); - var EventStorePersistentSubscriptionBase = __webpack_require__(56); + var EventStorePersistentSubscriptionBase = __webpack_require__(59); var messages = __webpack_require__(9); function EventStorePersistentSubscription( @@ -5443,12 +5524,12 @@ module.exports = module.exports = EventStorePersistentSubscription; /***/ }, -/* 56 */ +/* 59 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(4); var ensure = __webpack_require__(5); - var PersistentSubscriptionNakEventAction = __webpack_require__(57); + var PersistentSubscriptionNakEventAction = __webpack_require__(60); var SubscriptionDropReason = __webpack_require__(23); function DropSubscriptionEvent() {} @@ -5616,7 +5697,7 @@ module.exports = /***/ }, -/* 57 */ +/* 60 */ /***/ function(module, exports) { const PersistentSubscriptionNakEventAction = { @@ -5636,7 +5717,7 @@ module.exports = /***/ }, -/* 58 */ +/* 61 */ /***/ function(module, exports) { module.exports.metastreamOf = function(stream) { @@ -5647,7 +5728,7 @@ module.exports = }; /***/ }, -/* 59 */ +/* 62 */ /***/ function(module, exports) { const SystemEventTypes = { @@ -5658,7 +5739,7 @@ module.exports = /***/ }, -/* 60 */ +/* 63 */ /***/ function(module, exports) { function StaticEndpointDiscoverer(tcpEndPoint, useSsl) { @@ -5675,7 +5756,7 @@ module.exports = module.exports = StaticEndpointDiscoverer; /***/ }, -/* 61 */ +/* 64 */ /***/ function(module, exports) { function NoopLogger() { @@ -5687,7 +5768,7 @@ module.exports = module.exports = NoopLogger; /***/ }, -/* 62 */ +/* 65 */ /***/ function(module, exports, __webpack_require__) { var ensure = __webpack_require__(5); @@ -5712,10 +5793,10 @@ module.exports = module.exports = UserCredentials; /***/ }, -/* 63 */ +/* 66 */ /***/ function(module, exports, __webpack_require__) { - var SystemConsumerStrategies = __webpack_require__(49); + var SystemConsumerStrategies = __webpack_require__(52); function PersistentSubscriptionSettings( resolveLinkTos, startFrom, extraStatistics, messageTimeout, @@ -5742,5 +5823,26 @@ module.exports = return new PersistentSubscriptionSettings(false, -1, false, 30000, 500, 500, 10, 20, 2000, 10, 1000, 0, SystemConsumerStrategies.RoundRobin); }; +/***/ }, +/* 67 */ +/***/ function(module, exports) { + + const SystemMetadata = { + maxAge: '$maxAge', + maxCount: '$maxCount', + truncateBefore: '$tb', + cacheControl: '$cacheControl', + acl: '$acl', + aclRead: '$r', + aclWrite: '$w', + aclDelete: '$d', + aclMetaRead: '$mr', + aclMetaWrite: '$mw', + userStreamAcl: '$userStreamAcl', + systemStreamAcl: '$systemStreamAcl' + }; + + module.exports = SystemMetadata; + /***/ } /******/ ]); \ No newline at end of file diff --git a/src/client.js b/src/client.js index 5f2391d..ace2292 100644 --- a/src/client.js +++ b/src/client.js @@ -38,18 +38,21 @@ function eventDataFactory(eventId, type, isJson, data, metadata) { return new EventData(eventId, type, isJson, data, metadata); } +// Exporting classes module.exports.EventStoreConnection = require('./eventStoreConnection'); module.exports.UserCredentials = require('./systemData/userCredentials'); module.exports.EventData = EventData; module.exports.PersistentSubscriptionSettings = require('./persistentSubscriptionSettings'); module.exports.SystemConsumerStrategies = require('./systemConsumerStrategies'); +// Exporting errors module.exports.WrongExpectedVersionError = require('./errors/wrongExpectedVersionError'); module.exports.StreamDeletedError = require('./errors/streamDeletedError'); module.exports.AccessDeniedError = require('./errors/accessDeniedError'); +// Exporting enums/constants module.exports.expectedVersion = expectedVersion; module.exports.positions = positions; module.exports.systemMetadata = require('./common/systemMetadata'); - +module.exports.eventReadStatus = results.EventReadStatus; // Helper functions module.exports.createConnection = module.exports.EventStoreConnection.create; module.exports.createEventData = eventDataFactory; diff --git a/src/clientOperations/deleteStreamOperation.js b/src/clientOperations/deleteStreamOperation.js index bb77805..d2f10ea 100644 --- a/src/clientOperations/deleteStreamOperation.js +++ b/src/clientOperations/deleteStreamOperation.js @@ -6,6 +6,9 @@ var InspectionDecision = require('../systemData/inspectionDecision'); var InspectionResult = require('./../systemData/inspectionResult'); var ClientMessage = require('../messages/clientMessage'); var results = require('../results'); +var WrongExpectedVersionError = require('../errors/wrongExpectedVersionError'); +var StreamDeletedError = require('../errors/streamDeletedError'); +var AccessDeniedError = require('../errors/accessDeniedError'); var OperationBase = require('../clientOperations/operationBase'); @@ -38,17 +41,16 @@ DeleteStreamOperation.prototype._inspectResponse = function(response) { case ClientMessage.OperationResult.ForwardTimeout: return new InspectionResult(InspectionDecision.Retry, "ForwardTimeout"); case ClientMessage.OperationResult.WrongExpectedVersion: - var err = util.format("Delete stream failed due to WrongExpectedVersion. Stream: %s, Expected version: %d.", this._stream, this._expectedVersion); - this.fail(new Error("Wrong expected version: " + err)); + this.fail(new WrongExpectedVersionError("Delete", this._stream, this._expectedVersion)); return new InspectionResult(InspectionDecision.EndOperation, "WrongExpectedVersion"); case ClientMessage.OperationResult.StreamDeleted: - this.fail(new Error("Stream deleted: " + this._stream)); + this.fail(new StreamDeletedError(this._stream)); return new InspectionResult(InspectionDecision.EndOperation, "StreamDeleted"); case ClientMessage.OperationResult.InvalidTransaction: this.fail(new Error("Invalid transaction.")); return new InspectionResult(InspectionDecision.EndOperation, "InvalidTransaction"); case ClientMessage.OperationResult.AccessDenied: - this.fail(new Error(util.format("Write access denied for stream '%s'.", this._stream))); + this.fail(new AccessDeniedError("Delete", this._stream)); return new InspectionResult(InspectionDecision.EndOperation, "AccessDenied"); default: throw new Error(util.format("Unexpected OperationResult: %d.", response.result)); diff --git a/src/clientOperations/readEventOperation.js b/src/clientOperations/readEventOperation.js index af3bd39..4540543 100644 --- a/src/clientOperations/readEventOperation.js +++ b/src/clientOperations/readEventOperation.js @@ -5,6 +5,7 @@ var ClientMessage = require('../messages/clientMessage'); var InspectionResult = require('./../systemData/inspectionResult'); var InspectionDecision = require('../systemData/inspectionDecision'); var results = require('../results'); +var AccessDeniedError = require('../errors/accessDeniedError'); var OperationBase = require('./operationBase'); @@ -42,7 +43,7 @@ ReadEventOperation.prototype._inspectResponse = function(response) { this.fail(new Error("Server error: " + response.error)); return new InspectionResult(InspectionDecision.EndOperation, "Error"); case ClientMessage.ReadEventCompleted.ReadEventResult.AccessDenied: - this.fail(new Error(util.format("Read access denied for stream '%s'.", this._stream))); + this.fail(new AccessDeniedError("Read", this._stream)); return new InspectionResult(InspectionDecision.EndOperation, "AccessDenied"); default: throw new Error(util.format("Unexpected ReadEventResult: %s.", response.result)); diff --git a/src/common/log/fileLogger.js b/src/common/log/fileLogger.js index dfcbdc0..4e2486c 100644 --- a/src/common/log/fileLogger.js +++ b/src/common/log/fileLogger.js @@ -13,7 +13,7 @@ function FileLogger(filePath, append) { function createLine(level, args, argsStartIndex) { var msg = util.format.apply(util, Array.prototype.slice.call(args, argsStartIndex)); - return util.format('%s %s - %s%s', new Date().toISOString(), level, msg, os.EOL); + return util.format('%s %s - %s%s', new Date().toISOString().substr(11,12), level, msg, os.EOL); } FileLogger.prototype.debug = function() { diff --git a/src/messages/messages.js b/src/messages/messages.js index b3d9f32..42132b0 100644 --- a/src/messages/messages.js +++ b/src/messages/messages.js @@ -111,7 +111,12 @@ module.exports = require("protobufjs").newBuilder({})['import']({ "name": "ResolvedIndexedEvent", "fields": [ { - "rule": "required", + /* + rule changed from required to optional + because protobufjs doesn't allow null value for required object + and in the case of a non-success result, event will be null + */ + "rule": "optional", "type": "EventRecord", "name": "event", "id": 1 diff --git a/test/appendToStream_test.js b/test/appendToStream_test.js index af1a5ca..94b69ac 100644 --- a/test/appendToStream_test.js +++ b/test/appendToStream_test.js @@ -1,46 +1,12 @@ var uuid = require('uuid'); var client = require('../src/client'); -var settings = {}; -if (process.env.TESTS_VERBOSE_LOGGING === '1') { - settings.verboseLogging = true; - var FileLogger = require('../src/common/log/fileLogger'); - settings.log = new FileLogger('appendToStream_test.log'); -} - module.exports = { - setUp: function(cb) { - this.testStreamName = 'test-' + uuid.v4(); - var connected = false; - this.conn = client.EventStoreConnection.create(settings, {host: 'localhost', port: 1113}); - this.conn.connect() - .then(function() { - //Doesn't mean anything, connection is just initiated - }) - .catch(function(err) { - cb(err); - }); - this.conn.on('closed', function(reason){ - if (connected) return; - cb(new Error("Connection failed: " + reason)); - }); - this.conn.on('connected', function() { - connected = true; - cb(); - }); - }, - tearDown: function(cb) { - this.conn.close(); - this.conn.on('closed', function() { - cb(); - }); - this.conn = null; - }, 'Append One Event To Stream Happy Path': function(test) { var event = client.createJsonEventData(uuid.v4(), {a: Math.random(), b: uuid.v4()}, null, 'testEvent'); this.conn.appendToStream(this.testStreamName, client.expectedVersion.any, event) .then(function(result) { - test.ok(result.nextExpectedVersion === 0, "Expected nextExpectedVersion === 0, but was " + result.nextExpectedVersion); + test.areEqual("nextExpectedVersion", result.nextExpectedVersion, 0); test.ok(result.logPosition, "No log position in result."); test.done(); }) @@ -55,7 +21,7 @@ module.exports = { ]; this.conn.appendToStream(this.testStreamName, client.expectedVersion.any, events) .then(function(result) { - test.ok(result.nextExpectedVersion === 1, "Expected nextExpectedVersion === 1, but was " + result.nextExpectedVersion); + test.areEqual("result.nextExpectedVersion", result.nextExpectedVersion, 1); test.ok(result.logPosition, "No log position in result."); test.done(); }) @@ -67,17 +33,14 @@ module.exports = { var event = client.createJsonEventData(uuid.v4(), {a: Math.random(), b: uuid.v4()}, null, 'testEvent'); this.conn.appendToStream(this.testStreamName, 10, event) .then(function(result) { - test.ok(false, "Append succeeded but should have failed."); + test.fail("Append succeeded but should have failed."); test.done(); }) .catch(function(err) { var isWrongExpectedVersion = err instanceof client.WrongExpectedVersionError; test.ok(isWrongExpectedVersion, "Expected WrongExpectedVersionError, got " + err.constructor.name); - if (!isWrongExpectedVersion) { - test.done(err); - return; - } - test.done(); + if (isWrongExpectedVersion) return test.done(); + test.done(err); }); }, 'Append To Stream Deleted': function(test) { @@ -88,17 +51,14 @@ module.exports = { return self.conn.appendToStream(self.testStreamName, client.expectedVersion.any, event) }) .then(function(result) { - test.ok(false, "Append succeeded but should have failed."); + test.fail("Append succeeded but should have failed."); test.done(); }) .catch(function(err) { var isStreamDeleted = err instanceof client.StreamDeletedError; test.ok(isStreamDeleted, "Expected StreamDeletedError, got " + err.constructor.name); - if (!isStreamDeleted) { - test.done(err); - return; - } - test.done(); + if (isStreamDeleted) return test.done(); + test.done(err); }); }, 'Append To Stream Access Denied': function(test) { @@ -110,17 +70,16 @@ module.exports = { return self.conn.appendToStream(self.testStreamName, client.expectedVersion.any, event) }) .then(function(result) { - test.ok(false, "Append succeeded but should have failed."); + test.fail("Append succeeded but should have failed."); test.done(); }) .catch(function(err) { var isStreamDeleted = err instanceof client.AccessDeniedError; test.ok(isStreamDeleted, "Expected AccessDeniedError, got " + err.constructor.name); - if (!isStreamDeleted) { - test.done(err); - return; - } - test.done(); + if (isStreamDeleted) return test.done(); + test.done(err); }); } }; + +require('./common/base_test').init(module.exports); diff --git a/test/common/base_test.js b/test/common/base_test.js new file mode 100644 index 0000000..a9db065 --- /dev/null +++ b/test/common/base_test.js @@ -0,0 +1,109 @@ +var util = require('util'); +var uuid = require('uuid'); +var client = require('../../src/client'); +var FileLogger = require('../../src/common/log/fileLogger'); +var NoopLogger = require('../../src/common/log/noopLogger'); + +var settings = { + log: new NoopLogger() +}; +if (process.env.TESTS_VERBOSE_LOGGING === '1') { + settings.verboseLogging = true; + settings.log = new FileLogger('test-verbose.log'); +} + +var tcpEndPoint = {host: 'localhost', port: 1113}; + +function setUp(cb) { + this.log = settings.log; + this.testStreamName = 'test-' + uuid.v4(); + var connected = false; + this.conn = client.EventStoreConnection.create(settings, tcpEndPoint); + this.conn.connect() + .then(function () { + //Doesn't mean anything, connection is just initiated + settings.log.debug("Connection to %j initialized.", tcpEndPoint); + }) + .catch(function (err) { + settings.log.error(err, "Initializing connection to %j failed.", tcpEndPoint); + cb(err); + }); + this.conn.on('closed', function (reason) { + if (connected) return; + var error = new Error("Connection failed: " + reason); + settings.log.error(error, "Connection to %j failed.", tcpEndPoint); + cb(error); + }); + this.conn.on('connected', function () { + settings.log.debug("Connected to %j.", tcpEndPoint); + connected = true; + cb(); + }); +} + +function tearDown(cb) { + this.conn.close(); + this.conn.on('closed', function() { + cb(); + }); + this.conn = null; +} + +var areEqual = function(name, actual, expected) { + if (typeof expected !== 'object' || expected === null) + this.strictEqual(actual, expected, util.format("Failed %s === %s, got %s.", name, expected, actual)); + else + this.deepEqual(actual, expected, util.format("Failed %s deepEqual %j, got %j.", name, expected, actual)); +}; + +var fail = function(reason) { + this.ok(false, reason); +}; + +var _ = { + 'setUp': setUp, + 'tearDown': tearDown +}; + +function wrap(name, testFunc) { + var base = _[name]; + if (base === undefined) { + return function(test) { + settings.log.debug('--- %s ---', name); + test.areEqual = areEqual.bind(test); + test.fail = fail.bind(test); + return testFunc.call(this, test); + } + } + return function(cb) { + var self = this; + base.call(this, function(err) { + if (err) return cb(err); + return testFunc.call(self, cb); + }); + } +} + +module.exports.init = function(testSuite, addSetUpTearDownIfNotPresent) { + var thisObj = {}; + if (addSetUpTearDownIfNotPresent === undefined) addSetUpTearDownIfNotPresent = true; + for(var k in testSuite) { + if (testSuite.hasOwnProperty(k)) { + testSuite[k] = wrap(k, testSuite[k]).bind(thisObj); + } + } + if (!addSetUpTearDownIfNotPresent) return; + if (!testSuite.hasOwnProperty('setUp')) testSuite['setUp'] = setUp.bind(thisObj); + if (!testSuite.hasOwnProperty('tearDown')) testSuite['tearDown'] = tearDown.bind(thisObj); +}; +module.exports.settings = function(settingsOverride) { + var obj = {}; + for(var prop in settings) { + obj[prop] = settings[prop]; + } + if (!settingsOverride) return obj; + for(var prop in settingsOverride) { + obj[prop] = settingsOverride[prop]; + } + return obj; +}; diff --git a/test/connection_test.js b/test/connection_test.js index f5ab48b..953960f 100644 --- a/test/connection_test.js +++ b/test/connection_test.js @@ -1,53 +1,40 @@ -var util = require('util'); var client = require('../src/client.js'); -var consoleLogger = { - debug: function() { - var msg = util.format.apply(util, Array.prototype.slice.call(arguments)); - util.log(msg); - }, - info: function() {}, - error: function() {} -}; - -var settings = {};//verboseLogging: true, log: consoleLogger}; +var testBase = require('./common/base_test'); module.exports = { 'Connect To Endpoint Happy Path': function(test) { var tcpEndpoint = {hostname: 'localhost', port: 1113}; - var conn = client.EventStoreConnection.create({}, tcpEndpoint); + var conn = client.EventStoreConnection.create(testBase.settings(), tcpEndpoint); conn.connect() - .catch(function(e) { - test.done(e); + .catch(function(err) { + test.done(err); }); conn.on('connected', function(endPoint){ - test.deepEqual(endPoint, tcpEndpoint); + test.areEqual("connected endPoint", endPoint, tcpEndpoint); done(); }); conn.on('error', done); - function done(e) { + function done(err) { conn.close(); - if (e) { - test.done(e); - return; - } + if (err) return test.done(err); test.done(); } }, 'Connect To Endpoint That Don\'t Exist': function(test) { var tcpEndpoint = {hostname: 'localhost', port: 1114}; - var conn = client.EventStoreConnection.create({maxReconnections: 1}, tcpEndpoint); + var conn = client.EventStoreConnection.create(testBase.settings({maxReconnections:1}), tcpEndpoint); conn.connect() - .catch(function (e) { - test.done(e); + .catch(function (err) { + test.done(err); }); conn.on('connected', function () { - test.ok(false, "Should not be able to connect."); + test.fail("Should not be able to connect."); test.done(); }); - conn.on('error', function (e) { - test.done(e); + conn.on('error', function (err) { + test.done(err); }); conn.on('closed', function(reason) { test.ok(reason.indexOf("Reconnection limit reached") === 0, "Wrong expected reason."); @@ -55,3 +42,5 @@ module.exports = { }); } }; + +testBase.init(module.exports, false); \ No newline at end of file diff --git a/test/deleteStream_test.js b/test/deleteStream_test.js index 72860bb..a31fc30 100644 --- a/test/deleteStream_test.js +++ b/test/deleteStream_test.js @@ -1,49 +1,17 @@ var uuid = require('uuid'); var client = require('../src/client'); -var settings = {}; -if (process.env.TESTS_VERBOSE_LOGGING === '1') { - settings.verboseLogging = true; - var FileLogger = require('../src/common/log/fileLogger'); - settings.log = new FileLogger('deleteStream_test.log'); -} - module.exports = { setUp: function(cb) { - this.testStreamName = 'test-' + uuid.v4(); - var connected = false; - this.conn = client.EventStoreConnection.create(settings, {host: 'localhost', port: 1113}); - this.conn.connect() + var events = [ + client.createJsonEventData(uuid.v4(), {a: Math.random(), b: uuid.v4()}, null, 'testEvent'), + client.createJsonEventData(uuid.v4(), {a: Math.random(), b: uuid.v4()}, null, 'testEvent') + ]; + this.conn.appendToStream(this.testStreamName, client.expectedVersion.noStream, events) .then(function() { - //Doesn't mean anything, connection is just initiated + cb(); }) - .catch(function(err) { - cb(err); - }); - this.conn.on('closed', function(reason){ - if (connected) return; - cb(new Error("Connection failed: " + reason)); - }); - var self = this; - this.conn.on('connected', function() { - connected = true; - var events = [ - client.createJsonEventData(uuid.v4(), {a: Math.random(), b: uuid.v4()}, null, 'testEvent'), - client.createJsonEventData(uuid.v4(), {a: Math.random(), b: uuid.v4()}, null, 'testEvent') - ]; - self.conn.appendToStream(self.testStreamName, client.expectedVersion.noStream, events) - .then(function() { - cb(); - }) - .catch(cb); - }); - }, - tearDown: function(cb) { - this.conn.close(); - this.conn.on('closed', function() { - cb(); - }); - this.conn = null; + .catch(cb); }, 'Test Delete Stream Soft Happy Path': function(test) { var self = this; @@ -53,8 +21,8 @@ module.exports = { return self.conn.getStreamMetadataRaw(self.testStreamName); }) .then(function(metadata) { - test.ok(metadata.stream === self.testStreamName, "Metadata stream doesn't match."); - test.ok(metadata.isStreamDeleted === false, "Metadata says stream is deleted."); + test.areEqual("metadata.stream", metadata.stream, self.testStreamName); + test.areEqual("metadata.isStreamDeleted", metadata.isStreamDeleted, false); test.ok(metadata.streamMetadata.$tb, "Expected Truncate Before to be set"); test.done(); }) @@ -62,12 +30,6 @@ module.exports = { test.done(err); }); }, - /* - This test fails because of a protobufjs error. - Client.ReadEventCompleted fails to decode because ResolvedIndexedEvent.event is null and it's marked as required. - Test will pass if messages.proto is modified so that ResolvedIndexedEvent.event is optional. - Unsure if it's a protobufjs issue or a GES issue. Need to duplicate this test with .Net Client. - 'Test Delete Stream Hard Happy Path': function(test) { var self = this; this.conn.deleteStream(this.testStreamName, 1, true) @@ -76,15 +38,62 @@ module.exports = { return self.conn.getStreamMetadataRaw(self.testStreamName); }) .then(function(metadata) { - test.ok(metadata.stream === self.testStreamName, "Metadata stream doesn't match."); - test.ok(metadata.isStreamDeleted === true, "Metadata says stream is deleted."); - test.ok(metadata.streamMetadata === null, "Expected streamMetadata to be null."); + test.areEqual("metadata.stream", metadata.stream, self.testStreamName); + test.areEqual("metadata.isStreamDeleted", metadata.isStreamDeleted, true); + test.areEqual("metadata.streamMetadata", metadata.streamMetadata, null); test.done(); }) .catch(function(err) { test.done(err); }); + }, + 'Test Delete Stream With Wrong Expected Version': function(test) { + this.conn.deleteStream(this.testStreamName, 10) + .then(function(result) { + test.fail("Delete succeeded but should have failed."); + test.done(); + }) + .catch(function(err) { + var isWrongExpectedVersion = err instanceof client.WrongExpectedVersionError; + test.ok(isWrongExpectedVersion, "Expected WrongExpectedVersionError, but got " + err.constructor.name); + if (isWrongExpectedVersion) return test.done(); + test.done(err); + }); + }, + 'Test Delete Stream With No Access': function(test) { + var self = this; + this.conn.setStreamMetadataRaw(this.testStreamName, client.expectedVersion.any, {$acl: {$d: "$admins"}}) + .then(function() { + return self.conn.deleteStream(self.testStreamName, 10); + }) + .then(function(result) { + test.fail("Delete succeeded but should have failed."); + test.done(); + }) + .catch(function(err) { + var isAccessDenied = err instanceof client.AccessDeniedError; + test.ok(isAccessDenied, "Expected AccessDeniedError, but got " + err.constructor.name); + if (isAccessDenied) return test.done(); + test.done(err); + }); + }, + 'Test Delete Stream Hard When Already Deleted': function(test) { + var self = this; + this.conn.deleteStream(this.testStreamName, 1, true) + .then(function() { + return self.conn.deleteStream(self.testStreamName, 1, true); + }) + .then(function(result) { + test.fail("Delete succeeded but should have failed."); + test.done(); + }) + .catch(function(err) { + var isStreamDeleted = err instanceof client.StreamDeletedError; + test.ok(isStreamDeleted, "Expected StreamDeletedError, but got " + err.constructor.name); + if (isStreamDeleted) return test.done(); + test.done(err); + }); } - */ - }; + +require('./common/base_test').init(module.exports); \ No newline at end of file diff --git a/test/readEvent_test.js b/test/readEvent_test.js new file mode 100644 index 0000000..7690c38 --- /dev/null +++ b/test/readEvent_test.js @@ -0,0 +1,102 @@ +var util = require('util'); +var uuid = require('uuid'); +var client = require('../src/client'); + + +module.exports = { + setUp: function(cb) { + this.expectedEvent = {a: uuid.v4(), b: Math.random()}; + this.expectedEventType = 'anEvent'; + this.expectedEventId = uuid.v4(); + var event = client.createJsonEventData(this.expectedEventId, this.expectedEvent, null, this.expectedEventType); + this.conn.appendToStream(this.testStreamName, client.expectedVersion.noStream, event) + .then(function() { + cb(); + }) + .catch(cb); + }, + 'Read Event Happy Path': function(test) { + var self = this; + this.conn.readEvent(this.testStreamName, 0) + .then(function(result) { + test.areEqual('status', result.status, client.eventReadStatus.Success); + test.areEqual('stream', result.stream, self.testStreamName); + test.areEqual('eventNumber', result.eventNumber, 0); + test.ok(result.event !== null, "event is null."); + test.ok(result.event.originalEvent !== null, "event.originalEvent is null."); + var event = JSON.parse(result.event.originalEvent.data.toString()); + test.areEqual('event.eventId', result.event.originalEvent.eventId, self.expectedEventId); + test.areEqual('event.eventType', result.event.originalEvent.eventType, self.expectedEventType); + test.areEqual('decoded event.data', event, self.expectedEvent); + test.done(); + }) + .catch(function(err) { + test.done(err); + }) + }, + 'Read Event From Non-Existing Stream': function(test) { + var anotherStream = 'test' + uuid.v4(); + this.conn.readEvent(anotherStream, 0) + .then(function(result) { + test.areEqual('status', result.status, client.eventReadStatus.NoStream); + test.areEqual('stream', result.stream, anotherStream); + test.areEqual('eventNumber', result.eventNumber, 0); + test.areEqual('event', result.event, null); + test.done(); + }) + .catch(function(err) { + test.done(err); + }); + }, + 'Read Event From Deleted Stream': function(test) { + var self = this; + this.conn.deleteStream(this.testStreamName, 0, true) + .then(function() { + return self.conn.readEvent(self.testStreamName, 0) + }) + .then(function(result) { + test.areEqual('status', result.status, client.eventReadStatus.StreamDeleted); + test.areEqual('stream', result.stream, self.testStreamName); + test.areEqual('eventNumber', result.eventNumber, 0); + test.areEqual('event', result.event, null); + test.done(); + }) + .catch(function(err) { + test.done(err); + }); + }, + 'Read Event With Inexisting Version': function(test) { + var self = this; + return self.conn.readEvent(self.testStreamName, 1) + .then(function(result) { + test.areEqual('status', result.status, client.eventReadStatus.NotFound); + test.areEqual('stream', result.stream, self.testStreamName); + test.areEqual('eventNumber', result.eventNumber, 1); + test.areEqual('event', result.event, null); + test.done(); + }) + .catch(function(err) { + test.done(err); + }); + }, + 'Read Event With No Access': function(test) { + var self = this; + var metadata = {$acl: {$r: '$admins'}}; + this.conn.setStreamMetadataRaw(self.testStreamName, client.expectedVersion.noStream, metadata) + .then(function(){ + return self.conn.readEvent(self.testStreamName, 0); + }) + .then(function(result) { + test.fail("readEvent succeeded but should have failed."); + test.done(); + }) + .catch(function(err) { + var isAccessDenied = err instanceof client.AccessDeniedError; + test.ok(isAccessDenied, "readEvent should have failed with AccessDeniedError, got " + err.constructor.name); + if (isAccessDenied) return test.done(); + test.done(err); + }); + } +}; + +require('./common/base_test').init(module.exports); \ No newline at end of file