mirror of https://gitee.com/bigwinds/arangodb
Merge branch 'devel' of https://github.com/arangodb/arangodb into devel
This commit is contained in:
commit
cd377b0e0b
|
@ -2284,7 +2284,7 @@ ClusterMethods::persistCollectionInAgency(
|
|||
std::string distributeShardsLike = col->distributeShardsLike();
|
||||
std::vector<std::string> dbServers;
|
||||
std::vector<std::string> avoid = col->avoidServers();
|
||||
|
||||
|
||||
ClusterInfo* ci = ClusterInfo::instance();
|
||||
if (!distributeShardsLike.empty()) {
|
||||
CollectionNameResolver resolver(col->vocbase());
|
||||
|
@ -2320,7 +2320,6 @@ ClusterMethods::persistCollectionInAgency(
|
|||
}
|
||||
col->distributeShardsLike(otherCidString);
|
||||
} else {
|
||||
LOG_TOPIC(WARN, Logger::CLUSTER) << "WTF? " << ignoreDistributeShardsLikeErrors;
|
||||
if (ignoreDistributeShardsLikeErrors) {
|
||||
col->distributeShardsLike(std::string());
|
||||
} else {
|
||||
|
|
|
@ -258,8 +258,8 @@ class ClusterMethods {
|
|||
static std::unique_ptr<LogicalCollection> createCollectionOnCoordinator(
|
||||
TRI_col_type_e collectionType, TRI_vocbase_t* vocbase,
|
||||
arangodb::velocypack::Slice parameters,
|
||||
bool ignoreDistributeShardsLikeErrors,
|
||||
bool waitForSyncReplication);
|
||||
bool ignoreDistributeShardsLikeErrors = true,
|
||||
bool waitForSyncReplication = true);
|
||||
|
||||
private:
|
||||
|
||||
|
@ -268,7 +268,8 @@ class ClusterMethods {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static std::unique_ptr<LogicalCollection> persistCollectionInAgency(
|
||||
LogicalCollection* col, bool ignoreDistributeShardsLikeErrors, bool waitForSyncReplication);
|
||||
LogicalCollection* col, bool ignoreDistributeShardsLikeErrors = true,
|
||||
bool waitForSyncReplication = true);
|
||||
};
|
||||
|
||||
} // namespace arangodb
|
||||
|
|
|
@ -1265,8 +1265,7 @@ int InitialSyncer::handleSyncKeysRocksDB(arangodb::LogicalCollection* col,
|
|||
// smaller values than lowKey mean they don't exist remotely
|
||||
trx.remove(collectionName, key, options);
|
||||
return;
|
||||
}
|
||||
if (cmp1 >= 0 && cmp2 <= 0) {
|
||||
} else if (cmp1 >= 0 && cmp2 <= 0) {
|
||||
// we only need to hash we are in the range
|
||||
if (cmp1 == 0) {
|
||||
foundLowKey = true;
|
||||
|
@ -1294,21 +1293,23 @@ int InitialSyncer::handleSyncKeysRocksDB(arangodb::LogicalCollection* col,
|
|||
nextChunk = true;
|
||||
}
|
||||
|
||||
if (rangeUnequal) {
|
||||
int res = syncChunkRocksDB(&trx, keysId, currentChunkId, lowKey,
|
||||
highKey, markers, errorMsg);
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
THROW_ARANGO_EXCEPTION(res);
|
||||
}
|
||||
}
|
||||
|
||||
TRI_ASSERT(!rangeUnequal || nextChunk); // A => B
|
||||
if (nextChunk && currentChunkId + 1 < numChunks) {
|
||||
currentChunkId++; // we are out of range, see next chunk
|
||||
resetChunk();
|
||||
|
||||
// key is higher than upper bound, recheck the current document
|
||||
if (cmp2 > 0) {
|
||||
parseDoc(doc, key);
|
||||
if (nextChunk) {// we are out of range, see next chunk
|
||||
if (rangeUnequal && currentChunkId < numChunks) {
|
||||
int res = syncChunkRocksDB(&trx, keysId, currentChunkId, lowKey,
|
||||
highKey, markers, errorMsg);
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
THROW_ARANGO_EXCEPTION(res);
|
||||
}
|
||||
}
|
||||
currentChunkId++;
|
||||
if (currentChunkId < numChunks) {
|
||||
resetChunk();
|
||||
// key is higher than upper bound, recheck the current document
|
||||
if (cmp2 > 0) {
|
||||
parseDoc(doc, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -1325,6 +1326,19 @@ int InitialSyncer::handleSyncKeysRocksDB(arangodb::LogicalCollection* col,
|
|||
parseDoc(doc, key);
|
||||
},
|
||||
UINT64_MAX);
|
||||
|
||||
// we might have missed chunks, if the keys don't exist at all locally
|
||||
while (currentChunkId < numChunks) {
|
||||
int res = syncChunkRocksDB(&trx, keysId, currentChunkId, lowKey,
|
||||
highKey, markers, errorMsg);
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
THROW_ARANGO_EXCEPTION(res);
|
||||
}
|
||||
currentChunkId++;
|
||||
if (currentChunkId < numChunks) {
|
||||
resetChunk();
|
||||
}
|
||||
}
|
||||
|
||||
res = trx.commit();
|
||||
if (!res.ok()) {
|
||||
|
@ -1423,8 +1437,8 @@ int InitialSyncer::syncChunkRocksDB(
|
|||
size_t const numKeys = static_cast<size_t>(responseBody.length());
|
||||
if (numKeys == 0) {
|
||||
errorMsg = "got invalid response from master at " + _masterInfo._endpoint +
|
||||
": response contains an empty chunk. ChunkId: " +
|
||||
std::to_string(chunkId);
|
||||
": response contains an empty chunk. Collection: " + collectionName +
|
||||
" Chunk: " + std::to_string(chunkId);
|
||||
return TRI_ERROR_REPLICATION_INVALID_RESPONSE;
|
||||
}
|
||||
TRI_ASSERT(numKeys > 0);
|
||||
|
@ -1494,6 +1508,23 @@ int InitialSyncer::syncChunkRocksDB(
|
|||
|
||||
i++;
|
||||
}
|
||||
|
||||
// delete all keys at end of the range
|
||||
while (nextStart < markers.size()) {
|
||||
std::string const& localKey = markers[nextStart].first;
|
||||
|
||||
TRI_ASSERT(localKey.compare(highString) > 0);
|
||||
//if (localKey.compare(highString) > 0) {
|
||||
// we have a local key that is not present remotely
|
||||
keyBuilder->clear();
|
||||
keyBuilder->openObject();
|
||||
keyBuilder->add(StaticStrings::KeyString, VPackValue(localKey));
|
||||
keyBuilder->close();
|
||||
|
||||
trx->remove(collectionName, keyBuilder->slice(), options);
|
||||
//}
|
||||
++nextStart;
|
||||
}
|
||||
|
||||
if (!toFetch.empty()) {
|
||||
VPackBuilder keysBuilder;
|
||||
|
|
|
@ -71,7 +71,7 @@ static inline rocksdb::Transaction* rocksTransaction(
|
|||
return static_cast<RocksDBTransactionState*>(trx->state())
|
||||
->rocksTransaction();
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
RocksDBCollection::RocksDBCollection(LogicalCollection* collection,
|
||||
VPackSlice const& info)
|
||||
|
@ -196,8 +196,8 @@ void RocksDBCollection::open(bool ignoreErrors) {
|
|||
RocksDBEngine* engine =
|
||||
static_cast<RocksDBEngine*>(EngineSelectorFeature::ENGINE);
|
||||
auto counterValue = engine->counterManager()->loadCounter(this->objectId());
|
||||
LOG_TOPIC(ERR, Logger::DEVEL) << " number of documents: "
|
||||
<< counterValue.added();
|
||||
LOG_TOPIC(ERR, Logger::DEVEL)
|
||||
<< " number of documents: " << counterValue.added();
|
||||
_numberDocuments = counterValue.added() - counterValue.removed();
|
||||
_revisionId = counterValue.revisionId();
|
||||
//_numberDocuments = countKeyRange(db, readOptions,
|
||||
|
@ -443,19 +443,21 @@ void RocksDBCollection::truncate(transaction::Methods* trx,
|
|||
iter->Seek(documentBounds.start());
|
||||
|
||||
while (iter->Valid() && cmp->Compare(iter->key(), documentBounds.end()) < 0) {
|
||||
TRI_voc_rid_t revisionId = RocksDBKey::revisionId(iter->key());
|
||||
|
||||
// add possible log statement
|
||||
state->prepareOperation(cid, revisionId, TRI_VOC_DOCUMENT_OPERATION_REMOVE);
|
||||
rocksdb::Status s = rtrx->Delete(iter->key());
|
||||
if (!s.ok()) {
|
||||
auto converted = convertStatus(s);
|
||||
THROW_ARANGO_EXCEPTION(converted);
|
||||
}
|
||||
|
||||
// transaction size limit reached -- fail
|
||||
TRI_voc_rid_t revisionId = RocksDBKey::revisionId(iter->key());
|
||||
// report size of key
|
||||
RocksDBOperationResult result =
|
||||
state->addOperation(cid, revisionId, TRI_VOC_DOCUMENT_OPERATION_REMOVE,
|
||||
0, iter->key().size());
|
||||
|
||||
// transaction size limit reached -- fail
|
||||
if (result.fail()) {
|
||||
THROW_ARANGO_EXCEPTION(result);
|
||||
}
|
||||
|
@ -615,6 +617,11 @@ int RocksDBCollection::insert(arangodb::transaction::Methods* trx,
|
|||
RocksDBSavePoint guard(rocksTransaction(trx),
|
||||
trx->isSingleOperationTransaction());
|
||||
|
||||
RocksDBTransactionState* state =
|
||||
static_cast<RocksDBTransactionState*>(trx->state());
|
||||
state->prepareOperation(_logicalCollection->cid(), revisionId,
|
||||
TRI_VOC_DOCUMENT_OPERATION_INSERT);
|
||||
|
||||
res = insertDocument(trx, revisionId, newSlice, options.waitForSync);
|
||||
if (res.ok()) {
|
||||
Result lookupResult = lookupRevisionVPack(revisionId, trx, mdr);
|
||||
|
@ -624,11 +631,9 @@ int RocksDBCollection::insert(arangodb::transaction::Methods* trx,
|
|||
}
|
||||
|
||||
// report document and key size
|
||||
RocksDBOperationResult result =
|
||||
static_cast<RocksDBTransactionState*>(trx->state())
|
||||
->addOperation(_logicalCollection->cid(), revisionId,
|
||||
TRI_VOC_DOCUMENT_OPERATION_INSERT,
|
||||
newSlice.byteSize(), res.keySize());
|
||||
RocksDBOperationResult result = state->addOperation(
|
||||
_logicalCollection->cid(), revisionId,
|
||||
TRI_VOC_DOCUMENT_OPERATION_INSERT, newSlice.byteSize(), res.keySize());
|
||||
|
||||
// transaction size limit reached -- fail
|
||||
if (result.fail()) {
|
||||
|
@ -703,8 +708,9 @@ int RocksDBCollection::update(arangodb::transaction::Methods* trx,
|
|||
mergeObjectsForUpdate(trx, oldDoc, newSlice, isEdgeCollection,
|
||||
TRI_RidToString(revisionId), options.mergeObjects,
|
||||
options.keepNull, *builder.get());
|
||||
|
||||
if (trx->state()->isDBServer()) {
|
||||
RocksDBTransactionState* state =
|
||||
static_cast<RocksDBTransactionState*>(trx->state());
|
||||
if (state->isDBServer()) {
|
||||
// Need to check that no sharding keys have changed:
|
||||
if (arangodb::shardKeysChanged(_logicalCollection->dbName(),
|
||||
trx->resolver()->getCollectionNameCluster(
|
||||
|
@ -717,8 +723,10 @@ int RocksDBCollection::update(arangodb::transaction::Methods* trx,
|
|||
RocksDBSavePoint guard(rocksTransaction(trx),
|
||||
trx->isSingleOperationTransaction());
|
||||
|
||||
// add possible log statement under guard
|
||||
state->prepareOperation(_logicalCollection->cid(), revisionId,
|
||||
TRI_VOC_DOCUMENT_OPERATION_UPDATE);
|
||||
VPackSlice const newDoc(builder->slice());
|
||||
|
||||
res = updateDocument(trx, oldRevisionId, oldDoc, revisionId, newDoc,
|
||||
options.waitForSync);
|
||||
|
||||
|
@ -731,10 +739,9 @@ int RocksDBCollection::update(arangodb::transaction::Methods* trx,
|
|||
TRI_ASSERT(!mdr.empty());
|
||||
|
||||
// report document and key size
|
||||
result = static_cast<RocksDBTransactionState*>(trx->state())
|
||||
->addOperation(_logicalCollection->cid(), revisionId,
|
||||
TRI_VOC_DOCUMENT_OPERATION_UPDATE,
|
||||
newDoc.byteSize(), res.keySize());
|
||||
result = state->addOperation(_logicalCollection->cid(), revisionId,
|
||||
TRI_VOC_DOCUMENT_OPERATION_UPDATE,
|
||||
newDoc.byteSize(), res.keySize());
|
||||
|
||||
// transaction size limit reached -- fail
|
||||
if (result.fail()) {
|
||||
|
@ -803,7 +810,9 @@ int RocksDBCollection::replace(
|
|||
isEdgeCollection, TRI_RidToString(revisionId),
|
||||
*builder.get());
|
||||
|
||||
if (trx->state()->isDBServer()) {
|
||||
RocksDBTransactionState* state =
|
||||
static_cast<RocksDBTransactionState*>(trx->state());
|
||||
if (state->isDBServer()) {
|
||||
// Need to check that no sharding keys have changed:
|
||||
if (arangodb::shardKeysChanged(_logicalCollection->dbName(),
|
||||
trx->resolver()->getCollectionNameCluster(
|
||||
|
@ -816,6 +825,10 @@ int RocksDBCollection::replace(
|
|||
RocksDBSavePoint guard(rocksTransaction(trx),
|
||||
trx->isSingleOperationTransaction());
|
||||
|
||||
// add possible log statement under guard
|
||||
state->prepareOperation(_logicalCollection->cid(), revisionId,
|
||||
TRI_VOC_DOCUMENT_OPERATION_REPLACE);
|
||||
|
||||
RocksDBOperationResult opResult =
|
||||
updateDocument(trx, oldRevisionId, oldDoc, revisionId,
|
||||
VPackSlice(builder->slice()), options.waitForSync);
|
||||
|
@ -829,11 +842,10 @@ int RocksDBCollection::replace(
|
|||
TRI_ASSERT(!mdr.empty());
|
||||
|
||||
// report document and key size
|
||||
result = static_cast<RocksDBTransactionState*>(trx->state())
|
||||
->addOperation(_logicalCollection->cid(), revisionId,
|
||||
TRI_VOC_DOCUMENT_OPERATION_REPLACE,
|
||||
VPackSlice(builder->slice()).byteSize(),
|
||||
opResult.keySize());
|
||||
result = state->addOperation(_logicalCollection->cid(), revisionId,
|
||||
TRI_VOC_DOCUMENT_OPERATION_REPLACE,
|
||||
VPackSlice(builder->slice()).byteSize(),
|
||||
opResult.keySize());
|
||||
|
||||
// transaction size limit reached -- fail
|
||||
if (result.fail()) {
|
||||
|
@ -901,13 +913,19 @@ int RocksDBCollection::remove(arangodb::transaction::Methods* trx,
|
|||
RocksDBSavePoint guard(rocksTransaction(trx),
|
||||
trx->isSingleOperationTransaction());
|
||||
|
||||
// add possible log statement under guard
|
||||
RocksDBTransactionState* state =
|
||||
static_cast<RocksDBTransactionState*>(trx->state());
|
||||
state->prepareOperation(_logicalCollection->cid(), revisionId,
|
||||
TRI_VOC_DOCUMENT_OPERATION_REMOVE);
|
||||
// RocksDBLogValue val = RocksDBLogValue::DocumentRemove(StringRef(key));
|
||||
// state->rocksTransaction()->PutLogData(val.slice());
|
||||
res = removeDocument(trx, oldRevisionId, oldDoc, options.waitForSync);
|
||||
if (res.ok()) {
|
||||
// report key size
|
||||
res =
|
||||
static_cast<RocksDBTransactionState*>(trx->state())
|
||||
->addOperation(_logicalCollection->cid(), revisionId,
|
||||
TRI_VOC_DOCUMENT_OPERATION_REMOVE, 0, res.keySize());
|
||||
res = state->addOperation(_logicalCollection->cid(), revisionId,
|
||||
TRI_VOC_DOCUMENT_OPERATION_REMOVE, 0,
|
||||
res.keySize());
|
||||
// transaction size limit reached -- fail
|
||||
if (res.fail()) {
|
||||
THROW_ARANGO_EXCEPTION(res);
|
||||
|
|
|
@ -85,6 +85,10 @@ RocksDBLogValue RocksDBLogValue::ViewDrop(TRI_voc_cid_t cid,
|
|||
return RocksDBLogValue(RocksDBLogType::ViewDrop, cid, iid);
|
||||
}
|
||||
|
||||
RocksDBLogValue RocksDBLogValue::DocumentOpsPrologue(TRI_voc_cid_t cid) {
|
||||
return RocksDBLogValue(RocksDBLogType::DocumentOperationsPrologue, cid);
|
||||
}
|
||||
|
||||
RocksDBLogValue RocksDBLogValue::DocumentRemove(
|
||||
arangodb::StringRef const& key) {
|
||||
return RocksDBLogValue(RocksDBLogType::DocumentRemove, key);
|
||||
|
@ -105,7 +109,8 @@ RocksDBLogValue::RocksDBLogValue(RocksDBLogType type, uint64_t val)
|
|||
: _buffer() {
|
||||
switch (type) {
|
||||
case RocksDBLogType::DatabaseDrop:
|
||||
case RocksDBLogType::CollectionCreate: {
|
||||
case RocksDBLogType::CollectionCreate:
|
||||
case RocksDBLogType::DocumentOperationsPrologue: {
|
||||
_buffer.reserve(sizeof(RocksDBLogType) + sizeof(uint64_t));
|
||||
_buffer += static_cast<char>(type);
|
||||
uint64ToPersistent(_buffer, val); // database or collection ID
|
||||
|
|
|
@ -64,7 +64,7 @@ class RocksDBLogValue {
|
|||
|
||||
static RocksDBLogValue ViewCreate(TRI_voc_cid_t, TRI_idx_iid_t);
|
||||
static RocksDBLogValue ViewDrop(TRI_voc_cid_t, TRI_idx_iid_t);
|
||||
|
||||
static RocksDBLogValue DocumentOpsPrologue(TRI_voc_cid_t cid);
|
||||
static RocksDBLogValue DocumentRemove(arangodb::StringRef const&);
|
||||
|
||||
public:
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
|
||||
using namespace arangodb;
|
||||
|
||||
// for the RocksDB engine we do not need any additional data
|
||||
// for the RocksDB engine we do not need any additional data
|
||||
struct RocksDBTransactionData final : public TransactionData {};
|
||||
|
||||
RocksDBSavePoint::RocksDBSavePoint(rocksdb::Transaction* trx)
|
||||
|
@ -98,7 +98,8 @@ RocksDBTransactionState::RocksDBTransactionState(
|
|||
_numInserts(0),
|
||||
_numUpdates(0),
|
||||
_numRemoves(0),
|
||||
_intermediateTransactionEnabled(intermediateTransactionEnabled) {}
|
||||
_intermediateTransactionEnabled(intermediateTransactionEnabled),
|
||||
_lastUsedCollection(UINT64_MAX) {}
|
||||
|
||||
/// @brief free a transaction container
|
||||
RocksDBTransactionState::~RocksDBTransactionState() {
|
||||
|
@ -111,9 +112,9 @@ RocksDBTransactionState::~RocksDBTransactionState() {
|
|||
|
||||
/// @brief start a transaction
|
||||
Result RocksDBTransactionState::beginTransaction(transaction::Hints hints) {
|
||||
LOG_TRX(this, _nestingLevel) << "beginning " << AccessMode::typeString(_type)
|
||||
<< " transaction";
|
||||
|
||||
LOG_TRX(this, _nestingLevel)
|
||||
<< "beginning " << AccessMode::typeString(_type) << " transaction";
|
||||
|
||||
Result result = useCollections(_nestingLevel);
|
||||
|
||||
if (result.ok()) {
|
||||
|
@ -157,23 +158,23 @@ Result RocksDBTransactionState::beginTransaction(transaction::Hints hints) {
|
|||
_rocksWriteOptions, rocksdb::TransactionOptions()));
|
||||
_rocksTransaction->SetSnapshot();
|
||||
_rocksReadOptions.snapshot = _rocksTransaction->GetSnapshot();
|
||||
|
||||
RocksDBLogValue header = RocksDBLogValue::BeginTransaction(_vocbase->id(),
|
||||
_id);
|
||||
|
||||
RocksDBLogValue header =
|
||||
RocksDBLogValue::BeginTransaction(_vocbase->id(), _id);
|
||||
_rocksTransaction->PutLogData(header.slice());
|
||||
|
||||
|
||||
} else {
|
||||
TRI_ASSERT(_status == transaction::Status::RUNNING);
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// @brief commit a transaction
|
||||
Result RocksDBTransactionState::commitTransaction(
|
||||
transaction::Methods* activeTrx) {
|
||||
LOG_TRX(this, _nestingLevel) << "committing " << AccessMode::typeString(_type)
|
||||
<< " transaction";
|
||||
LOG_TRX(this, _nestingLevel)
|
||||
<< "committing " << AccessMode::typeString(_type) << " transaction";
|
||||
|
||||
TRI_ASSERT(_status == transaction::Status::RUNNING);
|
||||
TRI_IF_FAILURE("TransactionWriteCommitMarker") {
|
||||
|
@ -189,7 +190,7 @@ Result RocksDBTransactionState::commitTransaction(
|
|||
_rocksWriteOptions.sync = true;
|
||||
_rocksTransaction->SetWriteOptions(_rocksWriteOptions);
|
||||
}
|
||||
|
||||
|
||||
// TODO wait for response on github issue to see how we can use the
|
||||
// sequence number
|
||||
result = rocksutils::convertStatus(_rocksTransaction->Commit());
|
||||
|
@ -245,8 +246,8 @@ Result RocksDBTransactionState::commitTransaction(
|
|||
/// @brief abort and rollback a transaction
|
||||
Result RocksDBTransactionState::abortTransaction(
|
||||
transaction::Methods* activeTrx) {
|
||||
LOG_TRX(this, _nestingLevel) << "aborting " << AccessMode::typeString(_type)
|
||||
<< " transaction";
|
||||
LOG_TRX(this, _nestingLevel)
|
||||
<< "aborting " << AccessMode::typeString(_type) << " transaction";
|
||||
TRI_ASSERT(_status == transaction::Status::RUNNING);
|
||||
Result result;
|
||||
|
||||
|
@ -277,6 +278,26 @@ Result RocksDBTransactionState::abortTransaction(
|
|||
return result;
|
||||
}
|
||||
|
||||
void RocksDBTransactionState::prepareOperation(
|
||||
TRI_voc_cid_t collectionId, TRI_voc_rid_t revisionId,
|
||||
TRI_voc_document_operation_e operationType) {
|
||||
switch (operationType) {
|
||||
case TRI_VOC_DOCUMENT_OPERATION_UNKNOWN:
|
||||
break;
|
||||
case TRI_VOC_DOCUMENT_OPERATION_INSERT:
|
||||
case TRI_VOC_DOCUMENT_OPERATION_UPDATE:
|
||||
case TRI_VOC_DOCUMENT_OPERATION_REPLACE:
|
||||
case TRI_VOC_DOCUMENT_OPERATION_REMOVE: {
|
||||
if (collectionId != _lastUsedCollection) {
|
||||
RocksDBLogValue logValue =
|
||||
RocksDBLogValue::DocumentOpsPrologue(collectionId);
|
||||
//_rocksTransaction->PutLogData(logValue.slice());
|
||||
_lastUsedCollection = collectionId;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief add an operation for a transaction collection
|
||||
RocksDBOperationResult RocksDBTransactionState::addOperation(
|
||||
TRI_voc_cid_t cid, TRI_voc_rid_t revisionId,
|
||||
|
@ -298,7 +319,7 @@ RocksDBOperationResult RocksDBTransactionState::addOperation(
|
|||
static_cast<RocksDBTransactionCollection*>(findCollection(cid));
|
||||
|
||||
if (collection == nullptr) {
|
||||
std::string message = "collection '" + std::to_string(cid) +
|
||||
std::string message = "collection '" + std::to_string(cid) +
|
||||
"' not found in transaction state";
|
||||
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, message);
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ namespace rocksdb {
|
|||
class Transaction;
|
||||
class Slice;
|
||||
class Iterator;
|
||||
}
|
||||
} // namespace rocksdb
|
||||
|
||||
namespace arangodb {
|
||||
namespace cache {
|
||||
|
@ -62,6 +62,7 @@ class RocksDBSavePoint {
|
|||
~RocksDBSavePoint();
|
||||
|
||||
void commit();
|
||||
|
||||
private:
|
||||
void rollback();
|
||||
|
||||
|
@ -101,6 +102,9 @@ class RocksDBTransactionState final : public TransactionState {
|
|||
return (_status == transaction::Status::ABORTED) && hasOperations();
|
||||
}
|
||||
|
||||
void prepareOperation(TRI_voc_cid_t collectionId, TRI_voc_rid_t revisionId,
|
||||
TRI_voc_document_operation_e operationType);
|
||||
|
||||
/// @brief add an operation for a transaction collection
|
||||
RocksDBOperationResult addOperation(
|
||||
TRI_voc_cid_t collectionId, TRI_voc_rid_t revisionId,
|
||||
|
@ -135,7 +139,10 @@ class RocksDBTransactionState final : public TransactionState {
|
|||
uint64_t _numUpdates;
|
||||
uint64_t _numRemoves;
|
||||
bool _intermediateTransactionEnabled;
|
||||
|
||||
/// Last collection used for transaction
|
||||
TRI_voc_cid_t _lastUsedCollection;
|
||||
};
|
||||
}
|
||||
} // namespace arangodb
|
||||
|
||||
#endif
|
||||
|
|
|
@ -57,7 +57,8 @@ enum class RocksDBLogType : char {
|
|||
ViewCreate = '9',
|
||||
ViewDrop = ':',
|
||||
ViewChange = ';',
|
||||
DocumentRemove = '<'
|
||||
DocumentOperationsPrologue = '<',
|
||||
DocumentRemove = '='
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -734,8 +734,9 @@ static void CreateVocBase(v8::FunctionCallbackInfo<v8::Value> const& args,
|
|||
}
|
||||
|
||||
std::unique_ptr<LogicalCollection> col =
|
||||
ClusterMethods::createCollectionOnCoordinator(collectionType, vocbase,
|
||||
infoSlice, true, createWaitsForSyncReplication);
|
||||
ClusterMethods::createCollectionOnCoordinator(
|
||||
collectionType, vocbase, infoSlice, false,
|
||||
createWaitsForSyncReplication);
|
||||
TRI_V8_RETURN(WrapCollection(isolate, col.release()));
|
||||
}
|
||||
|
||||
|
|
|
@ -499,15 +499,7 @@ std::string LogicalCollection::name() const {
|
|||
}
|
||||
|
||||
std::string const LogicalCollection::distributeShardsLike() const {
|
||||
if (!_distributeShardsLike.empty()) {
|
||||
CollectionNameResolver resolver(_vocbase);
|
||||
TRI_voc_cid_t shardLike =
|
||||
resolver.getCollectionIdCluster(_distributeShardsLike);
|
||||
if (shardLike != 0) {
|
||||
return basics::StringUtils::itoa(shardLike);
|
||||
}
|
||||
}
|
||||
return "";
|
||||
return _distributeShardsLike;
|
||||
}
|
||||
|
||||
void LogicalCollection::distributeShardsLike(std::string const& cid) {
|
||||
|
|
|
@ -0,0 +1,193 @@
|
|||
/* global describe, it */
|
||||
'use strict';
|
||||
const expect = require('chai').expect;
|
||||
const sinon = require('sinon');
|
||||
const statuses = require('statuses');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const internal = require('internal');
|
||||
const crypto = require('@arangodb/crypto');
|
||||
const SyntheticResponse = require('@arangodb/foxx/router/response');
|
||||
|
||||
describe('SyntheticResponse', function () {
|
||||
describe('headers', function () {
|
||||
it('exposes the headers of the native response', function () {
|
||||
require("console").log('exposes the headers of the native response');
|
||||
const rawRes = {headers: {hello: 'world'}};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
expect(res.headers).to.equal(rawRes.headers);
|
||||
});
|
||||
});
|
||||
describe('statusCode', function () {
|
||||
it('exposes the responseCode of the native response', function () {
|
||||
require("console").log('exposes the responseCode of the native response');
|
||||
const rawRes = {responseCode: 999};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
expect(res.statusCode).to.equal(rawRes.responseCode);
|
||||
});
|
||||
it('allows setting the responseCode of the native response', function () {
|
||||
require("console").log('allows setting the responseCode of the native response');
|
||||
const rawRes = {responseCode: 999};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.statusCode = 666;
|
||||
expect(res.statusCode).to.equal(rawRes.responseCode).and.to.equal(666);
|
||||
});
|
||||
});
|
||||
describe('body', function () {
|
||||
it('exposes the body of the native response', function () {
|
||||
require("console").log('exposes the body of the native response');
|
||||
const rawRes = {body: 'banana'};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
expect(res.body).to.equal(rawRes.body);
|
||||
});
|
||||
it('allows setting the native response body to a string', function () {
|
||||
require("console").log('allows setting the native response body to a string');
|
||||
const rawRes = {body: 'banana'};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.body = 'potato';
|
||||
expect(rawRes.body).to.equal('potato');
|
||||
});
|
||||
it('allows setting the native response body to a buffer', function () {
|
||||
require("console").log('allows setting the native response body to a buffer');
|
||||
const rawRes = {body: 'banana'};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.body = new Buffer('potato');
|
||||
expect(rawRes.body).to.eql(new Buffer('potato'));
|
||||
});
|
||||
it('allows removing the native response body with null', function () {
|
||||
require("console").log('allows removing the native response body with null');
|
||||
const rawRes = {body: 'banana'};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.body = null;
|
||||
expect(rawRes).not.to.have.a.property('body');
|
||||
});
|
||||
it('allows removing the native response body with undefined', function () {
|
||||
require("console").log('allows removing the native response body with undefined');
|
||||
const rawRes = {body: 'banana'};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.body = undefined;
|
||||
expect(rawRes).not.to.have.a.property('body');
|
||||
});
|
||||
it('converts objects to JSON', function () {
|
||||
require("console").log('converts objects to JSON');
|
||||
const value = {hello: 'world'};
|
||||
const rawRes = {body: 'banana'};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.body = value;
|
||||
expect(rawRes.body).to.equal(JSON.stringify(value));
|
||||
});
|
||||
it('converts arrays to JSON', function () {
|
||||
require("console").log('converts arrays to JSON');
|
||||
const value = [1, 2, 3];
|
||||
const rawRes = {body: 'banana'};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.body = value;
|
||||
expect(rawRes.body).to.equal(JSON.stringify(value));
|
||||
});
|
||||
[0, 23, -1, false, true].forEach(function (value) {
|
||||
it(`converts ${value} to a string`, function () {
|
||||
require("console").log(`converts ${value} to a string`);
|
||||
const rawRes = {body: 'banana'};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.body = value;
|
||||
expect(rawRes.body).to.equal(String(value));
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('getHeader', function () {
|
||||
it('returns the header by name', function () {
|
||||
require("console").log('returns the header by name');
|
||||
const rawRes = {headers: {hello: 'world'}};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
expect(res.getHeader('hello')).to.equal('world');
|
||||
});
|
||||
it('converts the name to lowercase', function () {
|
||||
require("console").log('converts the name to lowercase');
|
||||
const rawRes = {headers: {hello: 'world'}};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
expect(res.getHeader('Hello')).to.equal(res.getHeader('hello'));
|
||||
});
|
||||
it('intercepts content-type headers', function () {
|
||||
require("console").log('intercepts content-type headers');
|
||||
const rawRes = {contentType: 'application/x-meow'};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
expect(res.getHeader('content-type')).to.equal(rawRes.contentType);
|
||||
});
|
||||
it('intercepts content-type headers in any case', function () {
|
||||
require("console").log('intercepts content-type headers in any case');
|
||||
const rawRes = {contentType: 'application/x-meow'};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
expect(res.getHeader('Content-Type')).to.equal(rawRes.contentType);
|
||||
});
|
||||
});
|
||||
describe('removeHeader', function () {
|
||||
it('removes the header by name', function () {
|
||||
require("console").log('removes the header by name');
|
||||
const rawRes = {headers: {hello: 'world'}};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.removeHeader('hello');
|
||||
expect(rawRes.headers).not.to.have.a.property('hello');
|
||||
});
|
||||
it('converts the name to lowercase', function () {
|
||||
require("console").log('converts the name to lowercase');
|
||||
const rawRes = {headers: {hello: 'world'}};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.removeHeader('Hello');
|
||||
expect(rawRes.headers).not.to.have.a.property('hello');
|
||||
});
|
||||
it('intercepts content-type headers', function () {
|
||||
require("console").log('intercepts content-type headers');
|
||||
const rawRes = {contentType: 'application/x-meow'};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.removeHeader('content-type');
|
||||
expect(rawRes).not.to.have.a.property('contentType');
|
||||
});
|
||||
it('intercepts content-type headers in any case', function () {
|
||||
require("console").log('intercepts content-type headers in any case');
|
||||
const rawRes = {contentType: 'application/x-meow'};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.removeHeader('Content-Type');
|
||||
expect(rawRes).not.to.have.a.property('contentType');
|
||||
});
|
||||
});
|
||||
describe('setHeader', function () {
|
||||
it('updates the header by name', function () {
|
||||
require("console").log('updates the header by name');
|
||||
const rawRes = {headers: {hello: 'world'}};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.setHeader('hello', 'pancakes');
|
||||
expect(rawRes.headers.hello).to.equal('pancakes');
|
||||
});
|
||||
it('converts the name to lowercase', function () {
|
||||
require("console").log('converts the name to lowercase');
|
||||
const rawRes = {headers: {hello: 'world'}};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.setHeader('Hello', 'pancakes');
|
||||
expect(rawRes.headers.hello).to.equal('pancakes');
|
||||
});
|
||||
it('intercepts content-type headers', function () {
|
||||
require("console").log('intercepts content-type headers');
|
||||
const rawRes = {contentType: 'application/x-meow'};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.setHeader('content-type', 'application/x-woof');
|
||||
expect(rawRes.contentType).to.equal('application/x-woof');
|
||||
});
|
||||
it('intercepts content-type headers in any case', function () {
|
||||
require("console").log('intercepts content-type headers in any case');
|
||||
const rawRes = {contentType: 'application/x-meow'};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.setHeader('Content-Type', 'application/x-woof');
|
||||
expect(rawRes.contentType).to.equal('application/x-woof');
|
||||
});
|
||||
it('has no effect when called without a name', function () {
|
||||
require("console").log('has no effect when called without a name');
|
||||
const rawRes = {headers: {}, contentType: 'application/x-wat'};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
Object.freeze(rawRes.headers);
|
||||
Object.freeze(rawRes);
|
||||
expect(function () {
|
||||
res.setHeader();
|
||||
}).not.to.throw();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,346 @@
|
|||
/* global describe, it */
|
||||
'use strict';
|
||||
const expect = require('chai').expect;
|
||||
const sinon = require('sinon');
|
||||
const statuses = require('statuses');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const internal = require('internal');
|
||||
const crypto = require('@arangodb/crypto');
|
||||
const SyntheticResponse = require('@arangodb/foxx/router/response');
|
||||
|
||||
describe('SyntheticResponse', function () {
|
||||
describe('write', function () {
|
||||
describe('when the native response has no body', function () {
|
||||
it('allows setting the native response body to a string', function () {
|
||||
require("console").log('allows setting the native response body to a string');
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.write('potato');
|
||||
expect(rawRes.body).to.equal('potato');
|
||||
});
|
||||
it('allows setting the native response body to a buffer', function () {
|
||||
require("console").log('allows setting the native response body to a buffer');
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.write(new Buffer('potato'));
|
||||
expect(rawRes.body).to.eql(new Buffer('potato'));
|
||||
});
|
||||
it('ignores null values', function () {
|
||||
require("console").log('ignores null values');
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.write(null);
|
||||
expect(rawRes).not.to.have.a.property('body');
|
||||
});
|
||||
it('ignores undefined values', function () {
|
||||
require("console").log('ignores undefined values');
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.write(undefined);
|
||||
expect(rawRes).not.to.have.a.property('body');
|
||||
});
|
||||
it('converts objects to JSON', function () {
|
||||
require("console").log('converts objects to JSON');
|
||||
const value = {hello: 'world'};
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.write(value);
|
||||
expect(rawRes.body).to.equal(JSON.stringify(value));
|
||||
});
|
||||
it('converts arrays to JSON', function () {
|
||||
require("console").log('converts arrays to JSON');
|
||||
const value = [1, 2, 3];
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.write(value);
|
||||
expect(rawRes.body).to.equal(JSON.stringify(value));
|
||||
});
|
||||
[0, 23, -1, false, true].forEach(function (value) {
|
||||
it(`converts ${value} to a string`, function () {
|
||||
require("console").log(`converts ${value} to a string`);
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.write(value);
|
||||
expect(rawRes.body).to.equal(String(value));
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('when the native response has a string body', function () {
|
||||
const body = 'banana';
|
||||
it('allows adding a string to the native response body', function () {
|
||||
require("console").log('allows adding a string to the native response body');
|
||||
const rawRes = {body: body};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.write('potato');
|
||||
expect(rawRes.body).to.equal(body + 'potato');
|
||||
});
|
||||
it('allows adding a buffer to the native response body', function () {
|
||||
require("console").log('allows adding a buffer to the native response body');
|
||||
const rawRes = {body: body};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.write(new Buffer('potato'));
|
||||
expect(rawRes.body).to.eql(new Buffer(body + 'potato'));
|
||||
});
|
||||
it('ignores null values', function () {
|
||||
require("console").log('ignores null values');
|
||||
const rawRes = {body: body};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.write(null);
|
||||
expect(rawRes.body).to.equal(body);
|
||||
});
|
||||
it('ignores undefined values', function () {
|
||||
require("console").log('ignores undefined values');
|
||||
const rawRes = {body: body};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.write(undefined);
|
||||
expect(rawRes.body).to.equal(body);
|
||||
});
|
||||
it('converts objects to JSON', function () {
|
||||
require("console").log('converts objects to JSON');
|
||||
const value = {hello: 'world'};
|
||||
const rawRes = {body: body};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.write(value);
|
||||
expect(rawRes.body).to.equal(body + JSON.stringify(value));
|
||||
});
|
||||
it('converts arrays to JSON', function () {
|
||||
require("console").log('converts arrays to JSON');
|
||||
const value = [1, 2, 3];
|
||||
const rawRes = {body: body};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.write(value);
|
||||
expect(rawRes.body).to.equal(body + JSON.stringify(value));
|
||||
});
|
||||
[0, 23, -1, false, true].forEach(function (value) {
|
||||
it(`converts ${value} to a string`, function () {
|
||||
require("console").log(`converts ${value} to a string`);
|
||||
const rawRes = {body: body};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.write(value);
|
||||
expect(rawRes.body).to.equal(body + String(value));
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('when the native response has a buffer body', function () {
|
||||
const body = 'banana';
|
||||
it('allows adding a string to the native response body', function () {
|
||||
require("console").log('allows adding a string to the native response body');
|
||||
const rawRes = {body: new Buffer(body)};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.write('potato');
|
||||
expect(rawRes.body).to.eql(new Buffer(body + 'potato'));
|
||||
});
|
||||
it('allows adding a buffer to the native response body', function () {
|
||||
require("console").log('allows adding a buffer to the native response body');
|
||||
const rawRes = {body: new Buffer(body)};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.write(new Buffer('potato'));
|
||||
expect(rawRes.body).to.eql(new Buffer(body + 'potato'));
|
||||
});
|
||||
it('ignores null values', function () {
|
||||
require("console").log('ignores null values');
|
||||
const buf = new Buffer(body);
|
||||
const rawRes = {body: buf};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.write(null);
|
||||
expect(rawRes.body).to.equal(buf);
|
||||
});
|
||||
it('ignores undefined values', function () {
|
||||
require("console").log('ignores undefined values');
|
||||
const buf = new Buffer(body);
|
||||
const rawRes = {body: buf};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.write(undefined);
|
||||
expect(rawRes.body).to.equal(buf);
|
||||
});
|
||||
it('converts objects to JSON', function () {
|
||||
require("console").log('converts objects to JSON');
|
||||
const value = {hello: 'world'};
|
||||
const rawRes = {body: new Buffer(body)};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.write(value);
|
||||
expect(rawRes.body).to.eql(new Buffer(body + JSON.stringify(value)));
|
||||
});
|
||||
it('converts arrays to JSON', function () {
|
||||
require("console").log('converts arrays to JSON');
|
||||
const value = [1, 2, 3];
|
||||
const rawRes = {body: new Buffer(body)};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.write(value);
|
||||
expect(rawRes.body).to.eql(new Buffer(body + JSON.stringify(value)));
|
||||
});
|
||||
[0, 23, -1, false, true].forEach(function (value) {
|
||||
it(`converts ${value} to a string`, function () {
|
||||
require("console").log(`converts ${value} to a string`);
|
||||
const rawRes = {body: new Buffer(body)};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.write(value);
|
||||
expect(rawRes.body).to.eql(new Buffer(body + String(value)));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('attachment', function () {
|
||||
it('adds a content-disposition header', function () {
|
||||
require("console").log('adds a content-disposition header');
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.attachment('lol.js');
|
||||
expect(rawRes.headers).to.have.a.property(
|
||||
'content-disposition',
|
||||
'attachment; filename="lol.js"'
|
||||
);
|
||||
});
|
||||
it('only exposes the basename', function () {
|
||||
require("console").log('only exposes the basename');
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.attachment('/hello/world/lol.js');
|
||||
expect(rawRes.headers).to.have.a.property(
|
||||
'content-disposition',
|
||||
'attachment; filename="lol.js"'
|
||||
);
|
||||
});
|
||||
it('escapes quotation marks in the filename', function () {
|
||||
require("console").log('escapes quotation marks in the filename');
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.attachment('"lol".js');
|
||||
expect(rawRes.headers).to.have.a.property(
|
||||
'content-disposition',
|
||||
'attachment; filename="\\"lol\\".js"'
|
||||
);
|
||||
});
|
||||
it('escapes special characters', function () {
|
||||
require("console").log('escapes special characters');
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.attachment('l\rl.js');
|
||||
expect(rawRes.headers).to.have.a.property(
|
||||
'content-disposition',
|
||||
'attachment; filename="l?l.js"; filename*=UTF-8\'\'l%0Dl.js'
|
||||
);
|
||||
});
|
||||
[
|
||||
['js', 'application/javascript'],
|
||||
['json', 'application/json'],
|
||||
['txt', 'text/plain'],
|
||||
['unknown mime type', 'application/octet-stream']
|
||||
].forEach(function (t) {
|
||||
it(`sets the content-type header to ${t[1]} for ${t[0]} files`, function () {
|
||||
require("console").log(`sets the content-type header to ${t[1]} for ${t[0]} files`);
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.attachment(`lol.${t[0]}`);
|
||||
expect(rawRes.contentType).to.equal(t[1]);
|
||||
});
|
||||
});
|
||||
it('does not override existing content-type', function () {
|
||||
require("console").log('does not override existing content-type');
|
||||
const rawRes = {contentType: 'application/json'};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.attachment('hello.txt');
|
||||
expect(rawRes.contentType).to.equal('application/json');
|
||||
});
|
||||
it('overrides existing content-disposition headers', function () {
|
||||
require("console").log('overrides existing content-disposition headers');
|
||||
const rawRes = {headers: {'content-disposition': 'lolcat'}};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.attachment('hello.txt');
|
||||
expect(rawRes.headers).to.have.a.property(
|
||||
'content-disposition',
|
||||
'attachment; filename="hello.txt"'
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('download', function () {
|
||||
it('passes the arguments to attachment and sendFile', function () {
|
||||
require("console").log('passes the arguments to attachment and sendFile');
|
||||
const path = '/hello/world.js';
|
||||
const filename = 'lol.js';
|
||||
const res = new SyntheticResponse({}, {});
|
||||
res.attachment = sinon.spy();
|
||||
res.sendFile = sinon.spy();
|
||||
res.download(path, filename);
|
||||
expect(res.attachment.calledOnce).to.equal(true);
|
||||
expect(res.attachment.args[0]).to.eql([filename]);
|
||||
expect(res.sendFile.calledOnce).to.equal(true);
|
||||
expect(res.sendFile.args[0]).to.eql([path]);
|
||||
});
|
||||
it('falls back to path if filename is omitted', function () {
|
||||
require("console").log('falls back to path if filename is omitted');
|
||||
const path = '/hello/world.js';
|
||||
const res = new SyntheticResponse({}, {});
|
||||
res.attachment = sinon.spy();
|
||||
res.sendFile = sinon.spy();
|
||||
res.download(path);
|
||||
expect(res.attachment.calledOnce).to.equal(true);
|
||||
expect(res.attachment.args[0]).to.eql([path]);
|
||||
expect(res.sendFile.calledOnce).to.equal(true);
|
||||
expect(res.sendFile.args[0]).to.eql([path]);
|
||||
});
|
||||
});
|
||||
describe('json', function () {
|
||||
[{hello: 'world'}, [1, 2, 3], 'a string', 23, null, false, true, -1].forEach(function (value) {
|
||||
it(`converts ${value} to JSON`, function () {
|
||||
require("console").log(`converts ${value} to JSON`);
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.json(value);
|
||||
expect(rawRes.body).to.equal(JSON.stringify(value));
|
||||
});
|
||||
});
|
||||
it('sets the content-type to JSON', function () {
|
||||
require("console").log('sets the content-type to JSON');
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.json({some: 'json'});
|
||||
expect(rawRes.contentType).to.equal('application/json; charset=utf-8');
|
||||
});
|
||||
it('does not override the existing content-type', function () {
|
||||
require("console").log('does not override the existing content-type');
|
||||
const rawRes = {contentType: 'application/x-lolcat'};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.json({some: 'json'});
|
||||
expect(rawRes.contentType).to.equal('application/x-lolcat');
|
||||
});
|
||||
});
|
||||
describe('redirect', function () {
|
||||
it('sets the responseCode of the native request', function () {
|
||||
require("console").log('sets the responseCode of the native request');
|
||||
const rawRes = {responseCode: 999};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.redirect(303, '/lol/cat');
|
||||
expect(rawRes.responseCode).to.equal(303);
|
||||
});
|
||||
it('sets the location header of the native request', function () {
|
||||
require("console").log('sets the location header of the native request');
|
||||
const rawRes = {responseCode: 999};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.redirect(303, '/lol/cat');
|
||||
expect(rawRes.headers).to.have.a.property('location', '/lol/cat');
|
||||
});
|
||||
it('defaults to code 302 if no code is provided', function () {
|
||||
require("console").log('defaults to code 302 if no code is provided');
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.redirect('/lol/cat');
|
||||
expect(rawRes.responseCode).to.equal(302);
|
||||
});
|
||||
it('sets responseCode to 301 if code is "permanent"', function () {
|
||||
require("console").log('sets responseCode to 301 if code is "permanent"');
|
||||
const rawRes = {responseCode: 999};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.redirect('permanent', '/lol/cat');
|
||||
expect(rawRes.responseCode).to.equal(301);
|
||||
});
|
||||
it('does not override responseCode if no code is provided', function () {
|
||||
require("console").log('does not override responseCode if no code is provided');
|
||||
const rawRes = {responseCode: 999};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.redirect('/lol/cat');
|
||||
expect(rawRes.responseCode).to.equal(999);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,184 @@
|
|||
/* global describe, it */
|
||||
'use strict';
|
||||
const expect = require('chai').expect;
|
||||
const sinon = require('sinon');
|
||||
const statuses = require('statuses');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const internal = require('internal');
|
||||
const crypto = require('@arangodb/crypto');
|
||||
const SyntheticResponse = require('@arangodb/foxx/router/response');
|
||||
|
||||
describe('SyntheticResponse', function () {
|
||||
describe('sendFile', function () {
|
||||
const filename = fs.normalize(fs.makeAbsolute(path.join(
|
||||
internal.startupPath,
|
||||
'common',
|
||||
'test-data',
|
||||
'foxx',
|
||||
'toomanysecrets.txt'
|
||||
)));
|
||||
const body = fs.readBuffer(filename);
|
||||
const lastModified = new Date(fs.mtime(filename) * 1000).toUTCString();
|
||||
it('sets the native request body to the file contents', function () {
|
||||
require("console").log('sets the native request body to the file contents');
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.sendFile(filename);
|
||||
expect(rawRes.body).to.eql(body);
|
||||
});
|
||||
it('sets the last-modified header by default', function () {
|
||||
require("console").log('sets the last-modified header by default');
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.sendFile(filename);
|
||||
expect(rawRes.headers).to.have.a.property('last-modified', lastModified);
|
||||
});
|
||||
it('does not override existing last-modified header', function () {
|
||||
require("console").log('does not override existing last-modified header');
|
||||
const rawRes = {headers: {'last-modified': 'not today'}};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.sendFile(filename);
|
||||
expect(rawRes.headers).to.have.a.property('last-modified', 'not today');
|
||||
});
|
||||
it('overrides last-modified header if lastModified is true', function () {
|
||||
require("console").log('overrides last-modified header if lastModified is true');
|
||||
const rawRes = {headers: {'last-modified': 'not today'}};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.sendFile(filename, {lastModified: true});
|
||||
expect(rawRes.headers).to.have.a.property('last-modified', lastModified);
|
||||
});
|
||||
it('does not set the last-modified header if lastModified is false', function () {
|
||||
require("console").log('does not set the last-modified header if lastModified is false');
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.sendFile(filename, {lastModified: false});
|
||||
expect(rawRes).not.to.have.a.property('headers');
|
||||
});
|
||||
it('treats options boolean as lastModified', function () {
|
||||
require("console").log('treats options boolean as lastModified');
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.sendFile(filename, false);
|
||||
expect(rawRes).not.to.have.a.property('headers');
|
||||
});
|
||||
});
|
||||
describe('sendStatus', function () {
|
||||
it('sets the responseCode of the native request', function () {
|
||||
require("console").log('sets the responseCode of the native request');
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.sendStatus(400);
|
||||
expect(rawRes.responseCode).to.equal(400);
|
||||
});
|
||||
it('sets the response body to the matching message', function () {
|
||||
require("console").log('sets the response body to the matching message');
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.sendStatus(400);
|
||||
expect(rawRes.body).to.equal(statuses[400]);
|
||||
});
|
||||
it('sets the response body to the status code if no message exists', function () {
|
||||
require("console").log('sets the response body to the status code if no message exists');
|
||||
expect(statuses).not.to.have.a.property('999');
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.sendStatus(999);
|
||||
expect(rawRes.body).to.equal('999');
|
||||
});
|
||||
});
|
||||
describe('set', function () {
|
||||
it('updates the header by name', function () {
|
||||
require("console").log('updates the header by name');
|
||||
const rawRes = {headers: {hello: 'world'}};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.set('hello', 'pancakes');
|
||||
expect(rawRes.headers.hello).to.equal('pancakes');
|
||||
});
|
||||
it('converts the name to lowercase', function () {
|
||||
require("console").log('converts the name to lowercase');
|
||||
const rawRes = {headers: {hello: 'world'}};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.set('Hello', 'pancakes');
|
||||
expect(rawRes.headers.hello).to.equal('pancakes');
|
||||
});
|
||||
it('intercepts content-type headers', function () {
|
||||
require("console").log('intercepts content-type headers');
|
||||
const rawRes = {contentType: 'application/x-meow'};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.set('content-type', 'application/x-woof');
|
||||
expect(rawRes.contentType).to.equal('application/x-woof');
|
||||
});
|
||||
it('intercepts content-type headers in any case', function () {
|
||||
require("console").log('intercepts content-type headers in any case');
|
||||
const rawRes = {contentType: 'application/x-meow'};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.set('Content-Type', 'application/x-woof');
|
||||
expect(rawRes.contentType).to.equal('application/x-woof');
|
||||
});
|
||||
it('has no effect when called without a name', function () {
|
||||
require("console").log('has no effect when called without a name');
|
||||
const rawRes = {headers: {}, contentType: 'application/x-wat'};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
Object.freeze(rawRes.headers);
|
||||
Object.freeze(rawRes);
|
||||
expect(function () {
|
||||
res.set();
|
||||
}).not.to.throw();
|
||||
});
|
||||
it('accepts a headers object', function () {
|
||||
require("console").log('accepts a headers object');
|
||||
const rawRes = {headers: {a: '1'}};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.set({b: '2', c: '3'});
|
||||
expect(rawRes.headers).to.eql({a: '1', b: '2', c: '3'});
|
||||
});
|
||||
});
|
||||
describe('status', function () {
|
||||
it('allows setting the responseCode of the native response', function () {
|
||||
require("console").log('allows setting the responseCode of the native response');
|
||||
const rawRes = {responseCode: 999};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.status(666);
|
||||
expect(rawRes.responseCode).to.equal(666);
|
||||
});
|
||||
});
|
||||
describe('vary', function () {
|
||||
it('manipulates the vary header', function () {
|
||||
require("console").log('manipulates the vary header');
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.vary('Origin');
|
||||
expect(res.headers).to.have.a.property('vary', 'Origin');
|
||||
res.vary('User-Agent');
|
||||
expect(res.headers).to.have.a.property('vary', 'Origin, User-Agent');
|
||||
});
|
||||
it('ignores duplicates', function () {
|
||||
require("console").log('ignores duplicates');
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.vary('x, y');
|
||||
expect(res.headers).to.have.a.property('vary', 'x, y');
|
||||
res.vary('x, z');
|
||||
expect(res.headers).to.have.a.property('vary', 'x, y, z');
|
||||
});
|
||||
it('understands arrays', function () {
|
||||
require("console").log();
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.vary('x');
|
||||
expect(res.headers).to.have.a.property('vary', 'x');
|
||||
res.vary(['y', 'z']);
|
||||
expect(res.headers).to.have.a.property('vary', 'x, y, z');
|
||||
});
|
||||
it('understands wildcards', function () {
|
||||
require("console").log('understands wildcards');
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.vary('*');
|
||||
expect(res.headers).to.have.a.property('vary', '*');
|
||||
res.vary('User-Agent');
|
||||
expect(res.headers).to.have.a.property('vary', '*');
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,697 +0,0 @@
|
|||
/* global describe, it */
|
||||
'use strict';
|
||||
const expect = require('chai').expect;
|
||||
const sinon = require('sinon');
|
||||
const statuses = require('statuses');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const internal = require('internal');
|
||||
const crypto = require('@arangodb/crypto');
|
||||
const SyntheticResponse = require('@arangodb/foxx/router/response');
|
||||
|
||||
describe('SyntheticResponse', function () {
|
||||
describe('headers', function () {
|
||||
it('exposes the headers of the native response', function () {
|
||||
require("console").log('exposes the headers of the native response');
|
||||
const rawRes = {headers: {hello: 'world'}};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
expect(res.headers).to.equal(rawRes.headers);
|
||||
});
|
||||
});
|
||||
describe('statusCode', function () {
|
||||
it('exposes the responseCode of the native response', function () {
|
||||
require("console").log('exposes the responseCode of the native response');
|
||||
const rawRes = {responseCode: 999};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
expect(res.statusCode).to.equal(rawRes.responseCode);
|
||||
});
|
||||
it('allows setting the responseCode of the native response', function () {
|
||||
require("console").log('allows setting the responseCode of the native response');
|
||||
const rawRes = {responseCode: 999};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.statusCode = 666;
|
||||
expect(res.statusCode).to.equal(rawRes.responseCode).and.to.equal(666);
|
||||
});
|
||||
});
|
||||
describe('body', function () {
|
||||
it('exposes the body of the native response', function () {
|
||||
require("console").log('exposes the body of the native response');
|
||||
const rawRes = {body: 'banana'};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
expect(res.body).to.equal(rawRes.body);
|
||||
});
|
||||
it('allows setting the native response body to a string', function () {
|
||||
require("console").log('allows setting the native response body to a string');
|
||||
const rawRes = {body: 'banana'};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.body = 'potato';
|
||||
expect(rawRes.body).to.equal('potato');
|
||||
});
|
||||
it('allows setting the native response body to a buffer', function () {
|
||||
require("console").log('allows setting the native response body to a buffer');
|
||||
const rawRes = {body: 'banana'};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.body = new Buffer('potato');
|
||||
expect(rawRes.body).to.eql(new Buffer('potato'));
|
||||
});
|
||||
it('allows removing the native response body with null', function () {
|
||||
require("console").log('allows removing the native response body with null');
|
||||
const rawRes = {body: 'banana'};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.body = null;
|
||||
expect(rawRes).not.to.have.a.property('body');
|
||||
});
|
||||
it('allows removing the native response body with undefined', function () {
|
||||
require("console").log('allows removing the native response body with undefined');
|
||||
const rawRes = {body: 'banana'};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.body = undefined;
|
||||
expect(rawRes).not.to.have.a.property('body');
|
||||
});
|
||||
it('converts objects to JSON', function () {
|
||||
require("console").log('converts objects to JSON');
|
||||
const value = {hello: 'world'};
|
||||
const rawRes = {body: 'banana'};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.body = value;
|
||||
expect(rawRes.body).to.equal(JSON.stringify(value));
|
||||
});
|
||||
it('converts arrays to JSON', function () {
|
||||
require("console").log('converts arrays to JSON');
|
||||
const value = [1, 2, 3];
|
||||
const rawRes = {body: 'banana'};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.body = value;
|
||||
expect(rawRes.body).to.equal(JSON.stringify(value));
|
||||
});
|
||||
[0, 23, -1, false, true].forEach(function (value) {
|
||||
it(`converts ${value} to a string`, function () {
|
||||
require("console").log(`converts ${value} to a string`);
|
||||
const rawRes = {body: 'banana'};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.body = value;
|
||||
expect(rawRes.body).to.equal(String(value));
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('getHeader', function () {
|
||||
it('returns the header by name', function () {
|
||||
require("console").log('returns the header by name');
|
||||
const rawRes = {headers: {hello: 'world'}};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
expect(res.getHeader('hello')).to.equal('world');
|
||||
});
|
||||
it('converts the name to lowercase', function () {
|
||||
require("console").log('converts the name to lowercase');
|
||||
const rawRes = {headers: {hello: 'world'}};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
expect(res.getHeader('Hello')).to.equal(res.getHeader('hello'));
|
||||
});
|
||||
it('intercepts content-type headers', function () {
|
||||
require("console").log('intercepts content-type headers');
|
||||
const rawRes = {contentType: 'application/x-meow'};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
expect(res.getHeader('content-type')).to.equal(rawRes.contentType);
|
||||
});
|
||||
it('intercepts content-type headers in any case', function () {
|
||||
require("console").log('intercepts content-type headers in any case');
|
||||
const rawRes = {contentType: 'application/x-meow'};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
expect(res.getHeader('Content-Type')).to.equal(rawRes.contentType);
|
||||
});
|
||||
});
|
||||
describe('removeHeader', function () {
|
||||
it('removes the header by name', function () {
|
||||
require("console").log('removes the header by name');
|
||||
const rawRes = {headers: {hello: 'world'}};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.removeHeader('hello');
|
||||
expect(rawRes.headers).not.to.have.a.property('hello');
|
||||
});
|
||||
it('converts the name to lowercase', function () {
|
||||
require("console").log('converts the name to lowercase');
|
||||
const rawRes = {headers: {hello: 'world'}};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.removeHeader('Hello');
|
||||
expect(rawRes.headers).not.to.have.a.property('hello');
|
||||
});
|
||||
it('intercepts content-type headers', function () {
|
||||
require("console").log('intercepts content-type headers');
|
||||
const rawRes = {contentType: 'application/x-meow'};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.removeHeader('content-type');
|
||||
expect(rawRes).not.to.have.a.property('contentType');
|
||||
});
|
||||
it('intercepts content-type headers in any case', function () {
|
||||
require("console").log('intercepts content-type headers in any case');
|
||||
const rawRes = {contentType: 'application/x-meow'};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.removeHeader('Content-Type');
|
||||
expect(rawRes).not.to.have.a.property('contentType');
|
||||
});
|
||||
});
|
||||
describe('setHeader', function () {
|
||||
it('updates the header by name', function () {
|
||||
require("console").log('updates the header by name');
|
||||
const rawRes = {headers: {hello: 'world'}};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.setHeader('hello', 'pancakes');
|
||||
expect(rawRes.headers.hello).to.equal('pancakes');
|
||||
});
|
||||
it('converts the name to lowercase', function () {
|
||||
require("console").log('converts the name to lowercase');
|
||||
const rawRes = {headers: {hello: 'world'}};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.setHeader('Hello', 'pancakes');
|
||||
expect(rawRes.headers.hello).to.equal('pancakes');
|
||||
});
|
||||
it('intercepts content-type headers', function () {
|
||||
require("console").log('intercepts content-type headers');
|
||||
const rawRes = {contentType: 'application/x-meow'};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.setHeader('content-type', 'application/x-woof');
|
||||
expect(rawRes.contentType).to.equal('application/x-woof');
|
||||
});
|
||||
it('intercepts content-type headers in any case', function () {
|
||||
require("console").log('intercepts content-type headers in any case');
|
||||
const rawRes = {contentType: 'application/x-meow'};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.setHeader('Content-Type', 'application/x-woof');
|
||||
expect(rawRes.contentType).to.equal('application/x-woof');
|
||||
});
|
||||
it('has no effect when called without a name', function () {
|
||||
require("console").log('has no effect when called without a name');
|
||||
const rawRes = {headers: {}, contentType: 'application/x-wat'};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
Object.freeze(rawRes.headers);
|
||||
Object.freeze(rawRes);
|
||||
expect(function () {
|
||||
res.setHeader();
|
||||
}).not.to.throw();
|
||||
});
|
||||
});
|
||||
describe('write', function () {
|
||||
describe('when the native response has no body', function () {
|
||||
it('allows setting the native response body to a string', function () {
|
||||
require("console").log('allows setting the native response body to a string');
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.write('potato');
|
||||
expect(rawRes.body).to.equal('potato');
|
||||
});
|
||||
it('allows setting the native response body to a buffer', function () {
|
||||
require("console").log('allows setting the native response body to a buffer');
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.write(new Buffer('potato'));
|
||||
expect(rawRes.body).to.eql(new Buffer('potato'));
|
||||
});
|
||||
it('ignores null values', function () {
|
||||
require("console").log('ignores null values');
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.write(null);
|
||||
expect(rawRes).not.to.have.a.property('body');
|
||||
});
|
||||
it('ignores undefined values', function () {
|
||||
require("console").log('ignores undefined values');
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.write(undefined);
|
||||
expect(rawRes).not.to.have.a.property('body');
|
||||
});
|
||||
it('converts objects to JSON', function () {
|
||||
require("console").log('converts objects to JSON');
|
||||
const value = {hello: 'world'};
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.write(value);
|
||||
expect(rawRes.body).to.equal(JSON.stringify(value));
|
||||
});
|
||||
it('converts arrays to JSON', function () {
|
||||
require("console").log('converts arrays to JSON');
|
||||
const value = [1, 2, 3];
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.write(value);
|
||||
expect(rawRes.body).to.equal(JSON.stringify(value));
|
||||
});
|
||||
[0, 23, -1, false, true].forEach(function (value) {
|
||||
it(`converts ${value} to a string`, function () {
|
||||
require("console").log(`converts ${value} to a string`);
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.write(value);
|
||||
expect(rawRes.body).to.equal(String(value));
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('when the native response has a string body', function () {
|
||||
const body = 'banana';
|
||||
it('allows adding a string to the native response body', function () {
|
||||
require("console").log('allows adding a string to the native response body');
|
||||
const rawRes = {body: body};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.write('potato');
|
||||
expect(rawRes.body).to.equal(body + 'potato');
|
||||
});
|
||||
it('allows adding a buffer to the native response body', function () {
|
||||
require("console").log('allows adding a buffer to the native response body');
|
||||
const rawRes = {body: body};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.write(new Buffer('potato'));
|
||||
expect(rawRes.body).to.eql(new Buffer(body + 'potato'));
|
||||
});
|
||||
it('ignores null values', function () {
|
||||
require("console").log('ignores null values');
|
||||
const rawRes = {body: body};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.write(null);
|
||||
expect(rawRes.body).to.equal(body);
|
||||
});
|
||||
it('ignores undefined values', function () {
|
||||
require("console").log('ignores undefined values');
|
||||
const rawRes = {body: body};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.write(undefined);
|
||||
expect(rawRes.body).to.equal(body);
|
||||
});
|
||||
it('converts objects to JSON', function () {
|
||||
require("console").log('converts objects to JSON');
|
||||
const value = {hello: 'world'};
|
||||
const rawRes = {body: body};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.write(value);
|
||||
expect(rawRes.body).to.equal(body + JSON.stringify(value));
|
||||
});
|
||||
it('converts arrays to JSON', function () {
|
||||
require("console").log('converts arrays to JSON');
|
||||
const value = [1, 2, 3];
|
||||
const rawRes = {body: body};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.write(value);
|
||||
expect(rawRes.body).to.equal(body + JSON.stringify(value));
|
||||
});
|
||||
[0, 23, -1, false, true].forEach(function (value) {
|
||||
it(`converts ${value} to a string`, function () {
|
||||
require("console").log(`converts ${value} to a string`);
|
||||
const rawRes = {body: body};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.write(value);
|
||||
expect(rawRes.body).to.equal(body + String(value));
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('when the native response has a buffer body', function () {
|
||||
const body = 'banana';
|
||||
it('allows adding a string to the native response body', function () {
|
||||
require("console").log('allows adding a string to the native response body');
|
||||
const rawRes = {body: new Buffer(body)};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.write('potato');
|
||||
expect(rawRes.body).to.eql(new Buffer(body + 'potato'));
|
||||
});
|
||||
it('allows adding a buffer to the native response body', function () {
|
||||
require("console").log('allows adding a buffer to the native response body');
|
||||
const rawRes = {body: new Buffer(body)};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.write(new Buffer('potato'));
|
||||
expect(rawRes.body).to.eql(new Buffer(body + 'potato'));
|
||||
});
|
||||
it('ignores null values', function () {
|
||||
require("console").log('ignores null values');
|
||||
const buf = new Buffer(body);
|
||||
const rawRes = {body: buf};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.write(null);
|
||||
expect(rawRes.body).to.equal(buf);
|
||||
});
|
||||
it('ignores undefined values', function () {
|
||||
require("console").log('ignores undefined values');
|
||||
const buf = new Buffer(body);
|
||||
const rawRes = {body: buf};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.write(undefined);
|
||||
expect(rawRes.body).to.equal(buf);
|
||||
});
|
||||
it('converts objects to JSON', function () {
|
||||
require("console").log('converts objects to JSON');
|
||||
const value = {hello: 'world'};
|
||||
const rawRes = {body: new Buffer(body)};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.write(value);
|
||||
expect(rawRes.body).to.eql(new Buffer(body + JSON.stringify(value)));
|
||||
});
|
||||
it('converts arrays to JSON', function () {
|
||||
require("console").log('converts arrays to JSON');
|
||||
const value = [1, 2, 3];
|
||||
const rawRes = {body: new Buffer(body)};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.write(value);
|
||||
expect(rawRes.body).to.eql(new Buffer(body + JSON.stringify(value)));
|
||||
});
|
||||
[0, 23, -1, false, true].forEach(function (value) {
|
||||
it(`converts ${value} to a string`, function () {
|
||||
require("console").log(`converts ${value} to a string`);
|
||||
const rawRes = {body: new Buffer(body)};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.write(value);
|
||||
expect(rawRes.body).to.eql(new Buffer(body + String(value)));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('attachment', function () {
|
||||
it('adds a content-disposition header', function () {
|
||||
require("console").log('adds a content-disposition header');
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.attachment('lol.js');
|
||||
expect(rawRes.headers).to.have.a.property(
|
||||
'content-disposition',
|
||||
'attachment; filename="lol.js"'
|
||||
);
|
||||
});
|
||||
it('only exposes the basename', function () {
|
||||
require("console").log('only exposes the basename');
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.attachment('/hello/world/lol.js');
|
||||
expect(rawRes.headers).to.have.a.property(
|
||||
'content-disposition',
|
||||
'attachment; filename="lol.js"'
|
||||
);
|
||||
});
|
||||
it('escapes quotation marks in the filename', function () {
|
||||
require("console").log('escapes quotation marks in the filename');
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.attachment('"lol".js');
|
||||
expect(rawRes.headers).to.have.a.property(
|
||||
'content-disposition',
|
||||
'attachment; filename="\\"lol\\".js"'
|
||||
);
|
||||
});
|
||||
it('escapes special characters', function () {
|
||||
require("console").log('escapes special characters');
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.attachment('l\rl.js');
|
||||
expect(rawRes.headers).to.have.a.property(
|
||||
'content-disposition',
|
||||
'attachment; filename="l?l.js"; filename*=UTF-8\'\'l%0Dl.js'
|
||||
);
|
||||
});
|
||||
[
|
||||
['js', 'application/javascript'],
|
||||
['json', 'application/json'],
|
||||
['txt', 'text/plain'],
|
||||
['unknown mime type', 'application/octet-stream']
|
||||
].forEach(function (t) {
|
||||
it(`sets the content-type header to ${t[1]} for ${t[0]} files`, function () {
|
||||
require("console").log(`sets the content-type header to ${t[1]} for ${t[0]} files`);
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.attachment(`lol.${t[0]}`);
|
||||
expect(rawRes.contentType).to.equal(t[1]);
|
||||
});
|
||||
});
|
||||
it('does not override existing content-type', function () {
|
||||
require("console").log('does not override existing content-type');
|
||||
const rawRes = {contentType: 'application/json'};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.attachment('hello.txt');
|
||||
expect(rawRes.contentType).to.equal('application/json');
|
||||
});
|
||||
it('overrides existing content-disposition headers', function () {
|
||||
require("console").log('overrides existing content-disposition headers');
|
||||
const rawRes = {headers: {'content-disposition': 'lolcat'}};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.attachment('hello.txt');
|
||||
expect(rawRes.headers).to.have.a.property(
|
||||
'content-disposition',
|
||||
'attachment; filename="hello.txt"'
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('download', function () {
|
||||
it('passes the arguments to attachment and sendFile', function () {
|
||||
require("console").log('passes the arguments to attachment and sendFile');
|
||||
const path = '/hello/world.js';
|
||||
const filename = 'lol.js';
|
||||
const res = new SyntheticResponse({}, {});
|
||||
res.attachment = sinon.spy();
|
||||
res.sendFile = sinon.spy();
|
||||
res.download(path, filename);
|
||||
expect(res.attachment.calledOnce).to.equal(true);
|
||||
expect(res.attachment.args[0]).to.eql([filename]);
|
||||
expect(res.sendFile.calledOnce).to.equal(true);
|
||||
expect(res.sendFile.args[0]).to.eql([path]);
|
||||
});
|
||||
it('falls back to path if filename is omitted', function () {
|
||||
require("console").log('falls back to path if filename is omitted');
|
||||
const path = '/hello/world.js';
|
||||
const res = new SyntheticResponse({}, {});
|
||||
res.attachment = sinon.spy();
|
||||
res.sendFile = sinon.spy();
|
||||
res.download(path);
|
||||
expect(res.attachment.calledOnce).to.equal(true);
|
||||
expect(res.attachment.args[0]).to.eql([path]);
|
||||
expect(res.sendFile.calledOnce).to.equal(true);
|
||||
expect(res.sendFile.args[0]).to.eql([path]);
|
||||
});
|
||||
});
|
||||
describe('json', function () {
|
||||
[{hello: 'world'}, [1, 2, 3], 'a string', 23, null, false, true, -1].forEach(function (value) {
|
||||
it(`converts ${value} to JSON`, function () {
|
||||
require("console").log(`converts ${value} to JSON`);
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.json(value);
|
||||
expect(rawRes.body).to.equal(JSON.stringify(value));
|
||||
});
|
||||
});
|
||||
it('sets the content-type to JSON', function () {
|
||||
require("console").log('sets the content-type to JSON');
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.json({some: 'json'});
|
||||
expect(rawRes.contentType).to.equal('application/json; charset=utf-8');
|
||||
});
|
||||
it('does not override the existing content-type', function () {
|
||||
require("console").log('does not override the existing content-type');
|
||||
const rawRes = {contentType: 'application/x-lolcat'};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.json({some: 'json'});
|
||||
expect(rawRes.contentType).to.equal('application/x-lolcat');
|
||||
});
|
||||
});
|
||||
describe('redirect', function () {
|
||||
it('sets the responseCode of the native request', function () {
|
||||
require("console").log('sets the responseCode of the native request');
|
||||
const rawRes = {responseCode: 999};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.redirect(303, '/lol/cat');
|
||||
expect(rawRes.responseCode).to.equal(303);
|
||||
});
|
||||
it('sets the location header of the native request', function () {
|
||||
require("console").log('sets the location header of the native request');
|
||||
const rawRes = {responseCode: 999};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.redirect(303, '/lol/cat');
|
||||
expect(rawRes.headers).to.have.a.property('location', '/lol/cat');
|
||||
});
|
||||
it('defaults to code 302 if no code is provided', function () {
|
||||
require("console").log('defaults to code 302 if no code is provided');
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.redirect('/lol/cat');
|
||||
expect(rawRes.responseCode).to.equal(302);
|
||||
});
|
||||
it('sets responseCode to 301 if code is "permanent"', function () {
|
||||
require("console").log('sets responseCode to 301 if code is "permanent"');
|
||||
const rawRes = {responseCode: 999};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.redirect('permanent', '/lol/cat');
|
||||
expect(rawRes.responseCode).to.equal(301);
|
||||
});
|
||||
it('does not override responseCode if no code is provided', function () {
|
||||
require("console").log('does not override responseCode if no code is provided');
|
||||
const rawRes = {responseCode: 999};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.redirect('/lol/cat');
|
||||
expect(rawRes.responseCode).to.equal(999);
|
||||
});
|
||||
});
|
||||
describe('sendFile', function () {
|
||||
const filename = fs.normalize(fs.makeAbsolute(path.join(
|
||||
internal.startupPath,
|
||||
'common',
|
||||
'test-data',
|
||||
'foxx',
|
||||
'toomanysecrets.txt'
|
||||
)));
|
||||
const body = fs.readBuffer(filename);
|
||||
const lastModified = new Date(fs.mtime(filename) * 1000).toUTCString();
|
||||
it('sets the native request body to the file contents', function () {
|
||||
require("console").log('sets the native request body to the file contents');
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.sendFile(filename);
|
||||
expect(rawRes.body).to.eql(body);
|
||||
});
|
||||
it('sets the last-modified header by default', function () {
|
||||
require("console").log('sets the last-modified header by default');
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.sendFile(filename);
|
||||
expect(rawRes.headers).to.have.a.property('last-modified', lastModified);
|
||||
});
|
||||
it('does not override existing last-modified header', function () {
|
||||
require("console").log('does not override existing last-modified header');
|
||||
const rawRes = {headers: {'last-modified': 'not today'}};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.sendFile(filename);
|
||||
expect(rawRes.headers).to.have.a.property('last-modified', 'not today');
|
||||
});
|
||||
it('overrides last-modified header if lastModified is true', function () {
|
||||
require("console").log('overrides last-modified header if lastModified is true');
|
||||
const rawRes = {headers: {'last-modified': 'not today'}};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.sendFile(filename, {lastModified: true});
|
||||
expect(rawRes.headers).to.have.a.property('last-modified', lastModified);
|
||||
});
|
||||
it('does not set the last-modified header if lastModified is false', function () {
|
||||
require("console").log('does not set the last-modified header if lastModified is false');
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.sendFile(filename, {lastModified: false});
|
||||
expect(rawRes).not.to.have.a.property('headers');
|
||||
});
|
||||
it('treats options boolean as lastModified', function () {
|
||||
require("console").log('treats options boolean as lastModified');
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.sendFile(filename, false);
|
||||
expect(rawRes).not.to.have.a.property('headers');
|
||||
});
|
||||
});
|
||||
describe('sendStatus', function () {
|
||||
it('sets the responseCode of the native request', function () {
|
||||
require("console").log('sets the responseCode of the native request');
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.sendStatus(400);
|
||||
expect(rawRes.responseCode).to.equal(400);
|
||||
});
|
||||
it('sets the response body to the matching message', function () {
|
||||
require("console").log('sets the response body to the matching message');
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.sendStatus(400);
|
||||
expect(rawRes.body).to.equal(statuses[400]);
|
||||
});
|
||||
it('sets the response body to the status code if no message exists', function () {
|
||||
require("console").log('sets the response body to the status code if no message exists');
|
||||
expect(statuses).not.to.have.a.property('999');
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.sendStatus(999);
|
||||
expect(rawRes.body).to.equal('999');
|
||||
});
|
||||
});
|
||||
describe('set', function () {
|
||||
it('updates the header by name', function () {
|
||||
require("console").log('updates the header by name');
|
||||
const rawRes = {headers: {hello: 'world'}};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.set('hello', 'pancakes');
|
||||
expect(rawRes.headers.hello).to.equal('pancakes');
|
||||
});
|
||||
it('converts the name to lowercase', function () {
|
||||
require("console").log('converts the name to lowercase');
|
||||
const rawRes = {headers: {hello: 'world'}};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.set('Hello', 'pancakes');
|
||||
expect(rawRes.headers.hello).to.equal('pancakes');
|
||||
});
|
||||
it('intercepts content-type headers', function () {
|
||||
require("console").log('intercepts content-type headers');
|
||||
const rawRes = {contentType: 'application/x-meow'};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.set('content-type', 'application/x-woof');
|
||||
expect(rawRes.contentType).to.equal('application/x-woof');
|
||||
});
|
||||
it('intercepts content-type headers in any case', function () {
|
||||
require("console").log('intercepts content-type headers in any case');
|
||||
const rawRes = {contentType: 'application/x-meow'};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.set('Content-Type', 'application/x-woof');
|
||||
expect(rawRes.contentType).to.equal('application/x-woof');
|
||||
});
|
||||
it('has no effect when called without a name', function () {
|
||||
require("console").log('has no effect when called without a name');
|
||||
const rawRes = {headers: {}, contentType: 'application/x-wat'};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
Object.freeze(rawRes.headers);
|
||||
Object.freeze(rawRes);
|
||||
expect(function () {
|
||||
res.set();
|
||||
}).not.to.throw();
|
||||
});
|
||||
it('accepts a headers object', function () {
|
||||
require("console").log('accepts a headers object');
|
||||
const rawRes = {headers: {a: '1'}};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.set({b: '2', c: '3'});
|
||||
expect(rawRes.headers).to.eql({a: '1', b: '2', c: '3'});
|
||||
});
|
||||
});
|
||||
describe('status', function () {
|
||||
it('allows setting the responseCode of the native response', function () {
|
||||
require("console").log('allows setting the responseCode of the native response');
|
||||
const rawRes = {responseCode: 999};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.status(666);
|
||||
expect(rawRes.responseCode).to.equal(666);
|
||||
});
|
||||
});
|
||||
describe('vary', function () {
|
||||
it('manipulates the vary header', function () {
|
||||
require("console").log('manipulates the vary header');
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.vary('Origin');
|
||||
expect(res.headers).to.have.a.property('vary', 'Origin');
|
||||
res.vary('User-Agent');
|
||||
expect(res.headers).to.have.a.property('vary', 'Origin, User-Agent');
|
||||
});
|
||||
it('ignores duplicates', function () {
|
||||
require("console").log('ignores duplicates');
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.vary('x, y');
|
||||
expect(res.headers).to.have.a.property('vary', 'x, y');
|
||||
res.vary('x, z');
|
||||
expect(res.headers).to.have.a.property('vary', 'x, y, z');
|
||||
});
|
||||
it('understands arrays', function () {
|
||||
require("console").log();
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.vary('x');
|
||||
expect(res.headers).to.have.a.property('vary', 'x');
|
||||
res.vary(['y', 'z']);
|
||||
expect(res.headers).to.have.a.property('vary', 'x, y, z');
|
||||
});
|
||||
it('understands wildcards', function () {
|
||||
require("console").log('understands wildcards');
|
||||
const rawRes = {};
|
||||
const res = new SyntheticResponse(rawRes, {});
|
||||
res.vary('*');
|
||||
expect(res.headers).to.have.a.property('vary', '*');
|
||||
res.vary('User-Agent');
|
||||
expect(res.headers).to.have.a.property('vary', '*');
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1687,7 +1687,7 @@ int32_t int32(std::string const& str) {
|
|||
struct reent buffer;
|
||||
return _strtol_r(&buffer, str.c_str(), 0, 10);
|
||||
#else
|
||||
return strtol(str.c_str(), 0, 10);
|
||||
return (int32_t)strtol(str.c_str(), 0, 10);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
@ -1713,7 +1713,7 @@ int32_t int32(char const* value, size_t size) {
|
|||
struct reent buffer;
|
||||
return _strtol_r(&buffer, value, 0, 10);
|
||||
#else
|
||||
return strtol(value, 0, 10);
|
||||
return (int32_t)strtol(value, 0, 10);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
@ -1727,7 +1727,7 @@ uint32_t uint32(std::string const& str) {
|
|||
struct reent buffer;
|
||||
return _strtoul_r(&buffer, str.c_str(), 0, 10);
|
||||
#else
|
||||
return strtoul(str.c_str(), 0, 10);
|
||||
return (uint32_t)strtoul(str.c_str(), 0, 10);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
@ -1741,7 +1741,7 @@ uint32_t unhexUint32(std::string const& str) {
|
|||
struct reent buffer;
|
||||
return _strtoul_r(&buffer, str.c_str(), 0, 16);
|
||||
#else
|
||||
return strtoul(str.c_str(), 0, 16);
|
||||
return (uint32_t)strtoul(str.c_str(), 0, 16);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
@ -1767,7 +1767,7 @@ uint32_t uint32(char const* value, size_t size) {
|
|||
struct reent buffer;
|
||||
return _strtoul_r(&buffer, value, 0, 10);
|
||||
#else
|
||||
return strtoul(value, 0, 10);
|
||||
return (uint32_t)strtoul(value, 0, 10);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
@ -1793,7 +1793,7 @@ uint32_t unhexUint32(char const* value, size_t size) {
|
|||
struct reent buffer;
|
||||
return _strtoul_r(&buffer, value, 0, 16);
|
||||
#else
|
||||
return strtoul(value, 0, 16);
|
||||
return (uint32_t)strtoul(value, 0, 16);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -105,11 +105,11 @@ static inline int TRI_bind(TRI_socket_t s, const struct sockaddr* address,
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static inline int TRI_connect(TRI_socket_t s, const struct sockaddr* address,
|
||||
int addr_len) {
|
||||
size_t addr_len) {
|
||||
#ifdef _WIN32
|
||||
return connect(s.fileHandle, address, addr_len);
|
||||
return connect(s.fileHandle, address, (int)addr_len);
|
||||
#else
|
||||
return connect(s.fileDescriptor, address, addr_len);
|
||||
return connect(s.fileDescriptor, address, (socklen_t)addr_len);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -117,7 +117,7 @@ static inline int TRI_connect(TRI_socket_t s, const struct sockaddr* address,
|
|||
/// @brief send abstraction for different OSes
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static inline int TRI_send(TRI_socket_t s, const void* buffer, size_t length,
|
||||
static inline long TRI_send(TRI_socket_t s, const void* buffer, size_t length,
|
||||
int flags) {
|
||||
#ifdef _WIN32
|
||||
return send(s.fileHandle, (char*)buffer, (int)length, flags);
|
||||
|
|
|
@ -89,7 +89,7 @@ int gettimeofday(struct timeval* tv, void* tz) {
|
|||
#endif
|
||||
|
||||
void TRI_localtime(time_t tt, struct tm* tb) {
|
||||
#ifdef TRI_HAVE_LOCALTIME_R
|
||||
#ifdef ARANGODB_HAVE_LOCALTIME_R
|
||||
localtime_r(&tt, tb);
|
||||
#else
|
||||
#ifdef ARANGODB_HAVE_LOCALTIME_S
|
||||
|
@ -105,10 +105,10 @@ void TRI_localtime(time_t tt, struct tm* tb) {
|
|||
}
|
||||
|
||||
void TRI_gmtime(time_t tt, struct tm* tb) {
|
||||
#ifdef TRI_HAVE_GMTIME_R
|
||||
#ifdef ARANGODB_HAVE_GMTIME_R
|
||||
gmtime_r(&tt, tb);
|
||||
#else
|
||||
#ifdef TRI_HAVE_GMTIME_S
|
||||
#ifdef ARANGODB_HAVE_GMTIME_S
|
||||
gmtime_s(tb, &tt);
|
||||
#else
|
||||
struct tm* tp = gmtime(&tt);
|
||||
|
|
|
@ -228,7 +228,7 @@ TRI_socket_t EndpointIp::connectSocket(const struct addrinfo* aip,
|
|||
setTimeout(listenSocket, connectTimeout);
|
||||
|
||||
int result = TRI_connect(listenSocket, (const struct sockaddr*)aip->ai_addr,
|
||||
(int)aip->ai_addrlen);
|
||||
aip->ai_addrlen);
|
||||
|
||||
if (result != 0) {
|
||||
pErr = STR_ERROR();
|
||||
|
|
|
@ -326,15 +326,15 @@ bool ClientConnection::writeClientConnection(void const* buffer, size_t length,
|
|||
|
||||
#if defined(__APPLE__)
|
||||
// MSG_NOSIGNAL not supported on apple platform
|
||||
int status = TRI_send(_socket, buffer, length, 0);
|
||||
long status = TRI_send(_socket, buffer, length, 0);
|
||||
#elif defined(_WIN32)
|
||||
// MSG_NOSIGNAL not supported on windows platform
|
||||
int status = TRI_send(_socket, buffer, length, 0);
|
||||
long status = TRI_send(_socket, buffer, length, 0);
|
||||
#elif defined(__sun)
|
||||
// MSG_NOSIGNAL not supported on solaris platform
|
||||
int status = TRI_send(_socket, buffer, length, 0);
|
||||
long status = TRI_send(_socket, buffer, length, 0);
|
||||
#else
|
||||
int status = TRI_send(_socket, buffer, length, MSG_NOSIGNAL);
|
||||
long status = TRI_send(_socket, buffer, length, MSG_NOSIGNAL);
|
||||
#endif
|
||||
|
||||
if (status < 0) {
|
||||
|
|
Loading…
Reference in New Issue