diff options
author | Benoit Foucher <benoit@zeroc.com> | 2017-03-23 15:29:25 +0100 |
---|---|---|
committer | Benoit Foucher <benoit@zeroc.com> | 2017-03-23 15:29:25 +0100 |
commit | 1597a75419cd8049252cfbca6fce6ae95ef8b2c7 (patch) | |
tree | 2b2c858df1dbe68c1d576cae06c4713fd2ad5c40 | |
parent | Use Ice\None with PHP namespace mapping (diff) | |
download | ice-1597a75419cd8049252cfbca6fce6ae95ef8b2c7.tar.bz2 ice-1597a75419cd8049252cfbca6fce6ae95ef8b2c7.tar.xz ice-1597a75419cd8049252cfbca6fce6ae95ef8b2c7.zip |
Fix for ICE-7125 - Added support for Ice.ClassGraphDepthMax
116 files changed, 2147 insertions, 716 deletions
diff --git a/CHANGELOG-3.7.md b/CHANGELOG-3.7.md index 809930f7010..35cc50ade1a 100644 --- a/CHANGELOG-3.7.md +++ b/CHANGELOG-3.7.md @@ -17,6 +17,19 @@ These are the changes since Ice 3.6.3. ## General Changes +- Added support for a new Ice.ClassGraphDepthMax property to prevent stack + overflows in case a sender sends a very large graph. + + The unmarshaling or destruction of a graph of Slice class instances is a + recursive operation. This property limits the amount of stack size required to + perform these operations. This property is supported with all the language + mappings except Java and JavaScript where it's not needed (the runtime + environment allows graceful handling or stack overflows). + + The default maximum class graph depth is 100. If you increase this value, you + must ensure the thread pool stack size is large enough to allow reading graphs + without causing a stack overflow. + - Added support for IceStorm subscriber `locatorCacheTimeout` and `connectionCached` QoS settings. These settings match the proxy settings and allow configuring per-request load balancing on the subscriber proxy. diff --git a/config/PropertyNames.xml b/config/PropertyNames.xml index c12367fc58e..93d56730542 100644 --- a/config/PropertyNames.xml +++ b/config/PropertyNames.xml @@ -327,6 +327,7 @@ generated from the section label. <property name="BatchAutoFlush" deprecated="true"/> <property name="BatchAutoFlushSize" /> <property name="ChangeUser" /> + <property name="ClassGraphDepthMax" /> <property name="ClientAccessPolicyProtocol" /> <property name="Compression.Level" /> <property name="CollectObjects"/> diff --git a/cpp/include/Ice/InputStream.h b/cpp/include/Ice/InputStream.h index 4684d0eda69..363f41767ed 100644 --- a/cpp/include/Ice/InputStream.h +++ b/cpp/include/Ice/InputStream.h @@ -138,6 +138,8 @@ public: void setTraceSlicing(bool); + void setClassGraphDepthMax(size_t); + void* getClosure() const; void* setClosure(void*); @@ -738,8 +740,10 @@ private: protected: - EncapsDecoder(InputStream* stream, Encaps* encaps, bool sliceValues, const Ice::ValueFactoryManagerPtr& f) : - _stream(stream), _encaps(encaps), _sliceValues(sliceValues), _valueFactoryManager(f), _typeIdIndex(0) + EncapsDecoder(InputStream* stream, Encaps* encaps, bool sliceValues, size_t classGraphDepthMax, + const Ice::ValueFactoryManagerPtr& f) : + _stream(stream), _encaps(encaps), _sliceValues(sliceValues), _classGraphDepthMax(classGraphDepthMax), + _classGraphDepth(0), _valueFactoryManager(f), _typeIdIndex(0) { } @@ -756,6 +760,7 @@ private: { PatchFunc patchFunc; void* patchAddr; + size_t classGraphDepth; }; typedef std::vector<PatchEntry> PatchList; typedef std::map<Int, PatchList> PatchMap; @@ -763,6 +768,8 @@ private: InputStream* _stream; Encaps* _encaps; const bool _sliceValues; + const size_t _classGraphDepthMax; + size_t _classGraphDepth; Ice::ValueFactoryManagerPtr _valueFactoryManager; // Encapsulation attributes for object un-marshalling @@ -781,8 +788,10 @@ private: { public: - EncapsDecoder10(InputStream* stream, Encaps* encaps, bool sliceValues, const Ice::ValueFactoryManagerPtr& f) : - EncapsDecoder(stream, encaps, sliceValues, f), _sliceType(NoSlice) + EncapsDecoder10(InputStream* stream, Encaps* encaps, bool sliceValues, size_t classGraphDepthMax, + const Ice::ValueFactoryManagerPtr& f) : + EncapsDecoder(stream, encaps, sliceValues, classGraphDepthMax, f), + _sliceType(NoSlice) { } @@ -814,8 +823,10 @@ private: { public: - EncapsDecoder11(InputStream* stream, Encaps* encaps, bool sliceValues, const Ice::ValueFactoryManagerPtr& f) : - EncapsDecoder(stream, encaps, sliceValues, f), _preAllocatedInstanceData(0), _current(0), _valueIdIndex(1) + EncapsDecoder11(InputStream* stream, Encaps* encaps, bool sliceValues, size_t classGraphDepthMax, + const Ice::ValueFactoryManagerPtr& f) : + EncapsDecoder(stream, encaps, sliceValues, classGraphDepthMax, f), + _preAllocatedInstanceData(0), _current(0), _valueIdIndex(1) { } @@ -956,6 +967,8 @@ private: bool _traceSlicing; + size_t _classGraphDepthMax; + void* _closure; bool _sliceValues; diff --git a/cpp/src/Ice/InputStream.cpp b/cpp/src/Ice/InputStream.cpp index e10bc107df9..61f71c7b5ba 100644 --- a/cpp/src/Ice/InputStream.cpp +++ b/cpp/src/Ice/InputStream.cpp @@ -167,6 +167,7 @@ Ice::InputStream::initialize(Instance* instance, const EncodingVersion& encoding _collectObjects = _instance->collectObjects(); #endif _traceSlicing = _instance->traceLevels()->slicing > 0; + _classGraphDepthMax = _instance->classGraphDepthMax(); } void @@ -179,6 +180,7 @@ Ice::InputStream::initialize(const EncodingVersion& encoding) _collectObjects = false; #endif _traceSlicing = false; + _classGraphDepthMax = 0x7fffffff; _closure = 0; _sliceValues = true; _startSeq = -1; @@ -241,6 +243,19 @@ Ice::InputStream::setTraceSlicing(bool b) _traceSlicing = b; } +void +Ice::InputStream::setClassGraphDepthMax(size_t classGraphDepthMax) +{ + if(classGraphDepthMax < 1) + { + _classGraphDepthMax = 0x7fffffff; + } + else + { + _classGraphDepthMax = classGraphDepthMax; + } +} + void* Ice::InputStream::getClosure() const { @@ -266,6 +281,7 @@ Ice::InputStream::swap(InputStream& other) std::swap(_collectObjects, other._collectObjects); #endif std::swap(_traceSlicing, other._traceSlicing); + std::swap(_classGraphDepthMax, other._classGraphDepthMax); std::swap(_closure, other._closure); std::swap(_sliceValues, other._sliceValues); @@ -1740,11 +1756,11 @@ Ice::InputStream::initEncaps() ValueFactoryManagerPtr vfm = valueFactoryManager(); if(_currentEncaps->encoding == Encoding_1_0) { - _currentEncaps->decoder = new EncapsDecoder10(this, _currentEncaps, _sliceValues, vfm); + _currentEncaps->decoder = new EncapsDecoder10(this, _currentEncaps, _sliceValues, _classGraphDepthMax, vfm); } else { - _currentEncaps->decoder = new EncapsDecoder11(this, _currentEncaps, _sliceValues, vfm); + _currentEncaps->decoder = new EncapsDecoder11(this, _currentEncaps, _sliceValues, _classGraphDepthMax, vfm); } } } @@ -1884,6 +1900,7 @@ Ice::InputStream::EncapsDecoder::addPatchEntry(Int index, PatchFunc patchFunc, v PatchEntry e; e.patchFunc = patchFunc; e.patchAddr = patchAddr; + e.classGraphDepth = _classGraphDepth; q->second.push_back(e); } @@ -2233,6 +2250,30 @@ Ice::InputStream::EncapsDecoder10::readInstance() } // + // Compute the biggest class graph depth of this object. To compute this, + // we get the class graph depth of each ancestor from the patch map and + // keep the biggest one. + // + _classGraphDepth = 0; + PatchMap::iterator patchPos = _patchMap.find(index); + if(patchPos != _patchMap.end()) + { + assert(patchPos->second.size() > 0); + for(PatchList::iterator k = patchPos->second.begin(); k != patchPos->second.end(); ++k) + { + if(k->classGraphDepth > _classGraphDepth) + { + _classGraphDepth = k->classGraphDepth; + } + } + } + + if(++_classGraphDepth > _classGraphDepthMax) + { + throw MarshalException(__FILE__, __LINE__, "maximum class graph depth reached"); + } + + // // Unmarshal the instance and add it to the map of unmarshaled instances. // unmarshal(index, v); @@ -2668,11 +2709,18 @@ Ice::InputStream::EncapsDecoder11::readInstance(Int index, PatchFunc patchFunc, startSlice(); // Read next Slice header for next iteration. } + if(++_classGraphDepth > _classGraphDepthMax) + { + throw MarshalException(__FILE__, __LINE__, "maximum class graph depth reached"); + } + // // Unmarshal the object. // unmarshal(index, v); + --_classGraphDepth; + if(!_current && !_patchMap.empty()) { // diff --git a/cpp/src/Ice/Instance.cpp b/cpp/src/Ice/Instance.cpp index c49e386d2e9..cba9085ba4f 100644 --- a/cpp/src/Ice/Instance.cpp +++ b/cpp/src/Ice/Instance.cpp @@ -948,6 +948,7 @@ IceInternal::Instance::Instance(const CommunicatorPtr& communicator, const Initi _initData(initData), _messageSizeMax(0), _batchAutoFlushSize(0), + _classGraphDepthMax(0), _collectObjects(false), _toStringMode(ICE_ENUM(ToStringMode, Unicode)), _implicitContext(0), @@ -1189,6 +1190,19 @@ IceInternal::Instance::Instance(const CommunicatorPtr& communicator, const Initi } } + { + static const int defaultValue = 100; + Int num = _initData.properties->getPropertyAsIntWithDefault("Ice.ClassGraphDepthMax", defaultValue); + if(num < 1 || static_cast<size_t>(num) > static_cast<size_t>(0x7fffffff)) + { + const_cast<size_t&>(_classGraphDepthMax) = static_cast<size_t>(0x7fffffff); + } + else + { + const_cast<size_t&>(_classGraphDepthMax) = static_cast<size_t>(num); + } + } + const_cast<bool&>(_collectObjects) = _initData.properties->getPropertyAsInt("Ice.CollectObjects") > 0; string toStringModeStr = _initData.properties->getPropertyWithDefault("Ice.ToStringMode", "Unicode"); diff --git a/cpp/src/Ice/Instance.h b/cpp/src/Ice/Instance.h index ba1d367b84f..9bcc78e0990 100644 --- a/cpp/src/Ice/Instance.h +++ b/cpp/src/Ice/Instance.h @@ -108,6 +108,7 @@ public: Ice::PluginManagerPtr pluginManager() const; size_t messageSizeMax() const { return _messageSizeMax; } size_t batchAutoFlushSize() const { return _batchAutoFlushSize; } + size_t classGraphDepthMax() const { return _classGraphDepthMax; } bool collectObjects() const { return _collectObjects; } Ice::ToStringMode toStringMode() const { return _toStringMode; } const ACMConfig& clientACM() const; @@ -176,6 +177,7 @@ private: const DefaultsAndOverridesPtr _defaultsAndOverrides; // Immutable, not reset by destroy(). const size_t _messageSizeMax; // Immutable, not reset by destroy(). const size_t _batchAutoFlushSize; // Immutable, not reset by destroy(). + const size_t _classGraphDepthMax; // Immutable, not reset by destroy(). const bool _collectObjects; // Immutable, not reset by destroy(). const Ice::ToStringMode _toStringMode; // Immutable, not reset by destroy() ACMConfig _clientACM; diff --git a/cpp/src/Ice/PropertyNames.cpp b/cpp/src/Ice/PropertyNames.cpp index 02ee0f7ac2c..527d7e84d6d 100644 --- a/cpp/src/Ice/PropertyNames.cpp +++ b/cpp/src/Ice/PropertyNames.cpp @@ -6,7 +6,7 @@ // ICE_LICENSE file included in this distribution. // // ********************************************************************** -// Generated by makeprops.py from file ./config/PropertyNames.xml, Tue Feb 28 15:01:12 2017 +// Generated by makeprops.py from file ./config/PropertyNames.xml, Thu Mar 23 15:24:16 2017 // IMPORTANT: Do not edit this file -- any edits made here will be lost! @@ -77,6 +77,7 @@ const IceInternal::Property IcePropsData[] = IceInternal::Property("Ice.BatchAutoFlush", true, 0), IceInternal::Property("Ice.BatchAutoFlushSize", false, 0), IceInternal::Property("Ice.ChangeUser", false, 0), + IceInternal::Property("Ice.ClassGraphDepthMax", false, 0), IceInternal::Property("Ice.ClientAccessPolicyProtocol", false, 0), IceInternal::Property("Ice.Compression.Level", false, 0), IceInternal::Property("Ice.CollectObjects", false, 0), diff --git a/cpp/src/Ice/PropertyNames.h b/cpp/src/Ice/PropertyNames.h index 171fa1bed8c..485d4afaaa1 100644 --- a/cpp/src/Ice/PropertyNames.h +++ b/cpp/src/Ice/PropertyNames.h @@ -6,7 +6,7 @@ // ICE_LICENSE file included in this distribution. // // ********************************************************************** -// Generated by makeprops.py from file ./config/PropertyNames.xml, Tue Feb 28 15:01:12 2017 +// Generated by makeprops.py from file ./config/PropertyNames.xml, Thu Mar 23 15:24:16 2017 // IMPORTANT: Do not edit this file -- any edits made here will be lost! diff --git a/cpp/src/Ice/ThreadPool.cpp b/cpp/src/Ice/ThreadPool.cpp index 946a05e2b08..4b14a7e1ce8 100644 --- a/cpp/src/Ice/ThreadPool.cpp +++ b/cpp/src/Ice/ThreadPool.cpp @@ -346,7 +346,16 @@ IceInternal::ThreadPool::ThreadPool(const InstancePtr& instance, const string& p _selector.setup(_sizeIO); #endif - int stackSize = properties->getPropertyAsInt(_prefix + ".StackSize"); +#if defined(__APPLE__) + // + // We use a default stack size of 1MB on macOS and the new C++11 mapping to allow transmitting + // class graphs with a depth of 100 (maximum default), 512KB is not enough otherwise. + // + int defaultStackSize = 1024 * 1024; // 1MB +#else + int defaultStackSize = 0; +#endif + int stackSize = properties->getPropertyAsIntWithDefault(_prefix + ".StackSize", defaultStackSize); if(stackSize < 0) { Warning out(_instance->initializationData().logger); diff --git a/cpp/test/Ice/echo/BlobjectI.cpp b/cpp/test/Ice/echo/BlobjectI.cpp index 024b239ac4f..894e217569c 100644 --- a/cpp/test/Ice/echo/BlobjectI.cpp +++ b/cpp/test/Ice/echo/BlobjectI.cpp @@ -54,6 +54,14 @@ BlobjectI::BlobjectI() : } void +BlobjectI::setConnection(const Ice::ConnectionPtr& connection) +{ + Lock sync(*this); + _connection = connection; + notifyAll(); +} + +void BlobjectI::startBatch() { assert(!_batchProxy); @@ -75,8 +83,9 @@ BlobjectI::ice_invokeAsync(std::vector<Ice::Byte> inEncaps, std::function<void(std::exception_ptr)> ex, const Ice::Current& current) { + auto connection = getConnection(current); const bool twoway = current.requestId > 0; - auto obj = current.con->createProxy(current.id); + auto obj = connection->createProxy(current.id); if(!twoway) { if(_startBatch) @@ -124,8 +133,9 @@ void BlobjectI::ice_invoke_async(const Ice::AMD_Object_ice_invokePtr& amdCb, const vector<Ice::Byte>& inEncaps, const Ice::Current& current) { + Ice::ConnectionPtr connection = getConnection(current); const bool twoway = current.requestId > 0; - Ice::ObjectPrx obj = current.con->createProxy(current.id); + Ice::ObjectPrx obj = connection->createProxy(current.id); if(!twoway) { if(_startBatch) @@ -171,3 +181,30 @@ BlobjectI::ice_invoke_async(const Ice::AMD_Object_ice_invokePtr& amdCb, const ve } } #endif + +Ice::ConnectionPtr +BlobjectI::getConnection(const Ice::Current& current) +{ + Lock sync(*this); + if(!_connection) + { + return current.con; + } + + try + { + _connection->throwException(); + } + catch(const Ice::ConnectionLostException&) + { + // If we lost the connection, wait 5 seconds for the server to re-establish it. Some tests, + // involve connection closure (e.g.: exceptions MemoryLimitException test) and the server + // automatically re-establishes the connection with the echo server. + timedWait(IceUtil::Time::seconds(5)); + if(!_connection) + { + throw; + } + } + return _connection; +} diff --git a/cpp/test/Ice/echo/BlobjectI.h b/cpp/test/Ice/echo/BlobjectI.h index fe8091c8f88..16db90e0b5c 100644 --- a/cpp/test/Ice/echo/BlobjectI.h +++ b/cpp/test/Ice/echo/BlobjectI.h @@ -12,7 +12,7 @@ #include <Ice/Object.h> -class BlobjectI : public Ice::BlobjectAsync +class BlobjectI : public Ice::BlobjectAsync, private IceUtil::Monitor<IceUtil::Mutex> { public: @@ -20,6 +20,7 @@ public: void startBatch(); void flushBatch(); + void setConnection(const Ice::ConnectionPtr&); #ifdef ICE_CPP11_MAPPING @@ -35,8 +36,11 @@ public: private: + Ice::ConnectionPtr getConnection(const Ice::Current&); + bool _startBatch; Ice::ObjectPrxPtr _batchProxy; + Ice::ConnectionPtr _connection; }; ICE_DEFINE_PTR(BlobjectIPtr, BlobjectI); diff --git a/cpp/test/Ice/echo/Server.cpp b/cpp/test/Ice/echo/Server.cpp index 56cd9f534bf..b0576241b02 100644 --- a/cpp/test/Ice/echo/Server.cpp +++ b/cpp/test/Ice/echo/Server.cpp @@ -25,6 +25,11 @@ public: { } + virtual void setConnection(const Ice::Current& current) + { + _blob->setConnection(current.con); + } + virtual void startBatch(const Ice::Current&) { _blob->startBatch(); diff --git a/cpp/test/Ice/echo/Test.ice b/cpp/test/Ice/echo/Test.ice index 57f7e92da21..7cf7ec721bd 100644 --- a/cpp/test/Ice/echo/Test.ice +++ b/cpp/test/Ice/echo/Test.ice @@ -17,6 +17,7 @@ module Test // interface Echo { + void setConnection(); void startBatch(); void flushBatch(); void shutdown(); diff --git a/cpp/test/Ice/echo/test.py b/cpp/test/Ice/echo/test.py index 3f25f4bfa15..717826f73a2 100644 --- a/cpp/test/Ice/echo/test.py +++ b/cpp/test/Ice/echo/test.py @@ -9,7 +9,10 @@ class EchoServerTestCase(ClientServerTestCase): + def __init__(self): + ClientServerTestCase.__init__(self, "server", server=Server(quiet=True, waitForShutdown=False)) + def runClientSide(self, current): pass -TestSuite(__name__, [EchoServerTestCase(name="server", server=Server(quiet=True, waitForShutdown=False))]) +TestSuite(__name__, [EchoServerTestCase()]) diff --git a/cpp/test/Ice/exceptions/AllTests.cpp b/cpp/test/Ice/exceptions/AllTests.cpp index 7fb9c1a930a..32302c5c6d8 100644 --- a/cpp/test/Ice/exceptions/AllTests.cpp +++ b/cpp/test/Ice/exceptions/AllTests.cpp @@ -988,32 +988,42 @@ allTests(const Ice::CommunicatorPtr& communicator) catch(const Ice::ConnectionLostException&) { } + catch(const Ice::UnknownLocalException&) + { + // Expected with JS bidir server + } catch(const Ice::LocalException& ex) { cerr << ex << endl; test(false); } - ThrowerPrxPtr thrower2 = - ICE_UNCHECKED_CAST(ThrowerPrx, communicator->stringToProxy("thrower:" + getTestEndpoint(communicator, 1))); - try - { - thrower2->throwMemoryLimitException(Ice::ByteSeq(2 * 1024 * 1024)); // 2MB (no limits) - } - catch(const Ice::MemoryLimitException&) - { - } - ThrowerPrxPtr thrower3 = - ICE_UNCHECKED_CAST(ThrowerPrx, communicator->stringToProxy("thrower:" + getTestEndpoint(communicator, 2))); try { - thrower3->throwMemoryLimitException(Ice::ByteSeq(1024)); // 1KB limit - test(false); + ThrowerPrxPtr thrower2 = + ICE_UNCHECKED_CAST(ThrowerPrx, communicator->stringToProxy("thrower:" + getTestEndpoint(communicator, 1))); + try + { + thrower2->throwMemoryLimitException(Ice::ByteSeq(2 * 1024 * 1024)); // 2MB (no limits) + } + catch(const Ice::MemoryLimitException&) + { + } + ThrowerPrxPtr thrower3 = + ICE_UNCHECKED_CAST(ThrowerPrx, communicator->stringToProxy("thrower:" + getTestEndpoint(communicator, 2))); + try + { + thrower3->throwMemoryLimitException(Ice::ByteSeq(1024)); // 1KB limit + test(false); + } + catch(const Ice::ConnectionLostException&) + { + } } - catch(const Ice::ConnectionLostException&) + catch(const Ice::ConnectionRefusedException&) { + // Expected with JS bidir server } - cout << "ok" << endl; } diff --git a/cpp/test/Ice/objects/AllTests.cpp b/cpp/test/Ice/objects/AllTests.cpp index 5e6ba0460b8..95d44d6b962 100644 --- a/cpp/test/Ice/objects/AllTests.cpp +++ b/cpp/test/Ice/objects/AllTests.cpp @@ -323,6 +323,38 @@ allTests(const Ice::CommunicatorPtr& communicator) test(retS.size() == 1 && outS.size() == 1); cout << "ok" << endl; + cout << "testing recursive type... " << flush; + RecursivePtr top = ICE_MAKE_SHARED(Recursive); + RecursivePtr p = top; + int depth = 0; + try + { + for(; depth <= 2000; ++depth) + { + p->v = ICE_MAKE_SHARED(Recursive); + p = p->v; + if((depth < 10 && (depth % 10) == 0) || + (depth < 1000 && (depth % 100) == 0) || + (depth < 10000 && (depth % 1000) == 0) || + (depth % 10000) == 0) + { + initial->setRecursive(top); + } + } + test(!initial->supportsClassGraphDepthMax()); + } + catch(const Ice::UnknownLocalException&) + { + // Expected marshal exception from the server (max class graph depth reached) + test(depth == 100); // The default is 100. + } + catch(const Ice::UnknownException&) + { + // Expected stack overflow from the server (Java only) + } + initial->setRecursive(ICE_MAKE_SHARED(Recursive)); + cout << "ok" << endl; + cout << "testing compact ID..." << flush; try { diff --git a/cpp/test/Ice/objects/Collocated.cpp b/cpp/test/Ice/objects/Collocated.cpp index 60330b7061b..8c2d71b399b 100644 --- a/cpp/test/Ice/objects/Collocated.cpp +++ b/cpp/test/Ice/objects/Collocated.cpp @@ -154,6 +154,7 @@ main(int argc, char* argv[]) try { Ice::InitializationData initData = getTestInitData(argc, argv); + initData.properties->setProperty("Ice.Warn.Dispatch", "0"); Ice::CommunicatorHolder ich(argc, argv, initData); return run(argc, argv, ich.communicator()); } diff --git a/cpp/test/Ice/objects/Server.cpp b/cpp/test/Ice/objects/Server.cpp index 991233bfa0a..a501281b29b 100644 --- a/cpp/test/Ice/objects/Server.cpp +++ b/cpp/test/Ice/objects/Server.cpp @@ -88,6 +88,7 @@ main(int argc, char* argv[]) try { Ice::InitializationData initData = getTestInitData(argc, argv); + initData.properties->setProperty("Ice.Warn.Dispatch", "0"); Ice::CommunicatorHolder ich(argc, argv, initData); return run(argc, argv, ich.communicator()); } diff --git a/cpp/test/Ice/objects/Test.ice b/cpp/test/Ice/objects/Test.ice index 134a1aa2ea5..7d64f20614e 100644 --- a/cpp/test/Ice/objects/Test.ice +++ b/cpp/test/Ice/objects/Test.ice @@ -167,6 +167,11 @@ exception EDerived extends EBase A1 a4; }; +class Recursive +{ + Recursive v; +}; + interface Initial { void shutdown(); @@ -177,6 +182,9 @@ interface Initial E getE(); F getF(); + void setRecursive(Recursive p); + bool supportsClassGraphDepthMax(); + ["marshaled-result"] B getMB(); ["amd", "marshaled-result"] B getAMDMB(); diff --git a/cpp/test/Ice/objects/TestI.cpp b/cpp/test/Ice/objects/TestI.cpp index f17e1a7960d..803a278fba7 100644 --- a/cpp/test/Ice/objects/TestI.cpp +++ b/cpp/test/Ice/objects/TestI.cpp @@ -161,6 +161,17 @@ InitialI::getF(const Ice::Current&) return _f; } +void +InitialI::setRecursive(ICE_IN(RecursivePtr), const Ice::Current&) +{ +} + +bool +InitialI::supportsClassGraphDepthMax(const Ice::Current&) +{ + return true; +} + #ifdef ICE_CPP11_MAPPING InitialI::GetMBMarshaledResult InitialI::getMB(const Ice::Current& current) diff --git a/cpp/test/Ice/objects/TestI.h b/cpp/test/Ice/objects/TestI.h index a7243ed95f6..1a467fc0f33 100644 --- a/cpp/test/Ice/objects/TestI.h +++ b/cpp/test/Ice/objects/TestI.h @@ -94,6 +94,9 @@ public: virtual Test::EPtr getE(const Ice::Current&); virtual Test::FPtr getF(const Ice::Current&); + virtual void setRecursive(ICE_IN(Test::RecursivePtr), const Ice::Current&); + virtual bool supportsClassGraphDepthMax(const Ice::Current&); + #ifdef ICE_CPP11_MAPPING virtual GetMBMarshaledResult getMB(const Ice::Current&); virtual void getAMDMBAsync(std::function<void(const GetAMDMBMarshaledResult&)>, diff --git a/csharp/src/Ice/InputStream.cs b/csharp/src/Ice/InputStream.cs index c942e132a82..0dd8c98b624 100644 --- a/csharp/src/Ice/InputStream.cs +++ b/csharp/src/Ice/InputStream.cs @@ -245,7 +245,7 @@ namespace Ice _instance = instance; _traceSlicing = _instance.traceLevels().slicing > 0; - + _classGraphDepthMax = _instance.classGraphDepthMax(); _valueFactoryManager = _instance.initializationData().valueFactoryManager; _logger = _instance.initializationData().logger; _classResolver = _instance.resolveClass; @@ -258,6 +258,7 @@ namespace Ice _encapsStack = null; _encapsCache = null; _traceSlicing = false; + _classGraphDepthMax = 0x7fffffff; _closure = null; _sliceValues = true; _startSeq = -1; @@ -360,6 +361,22 @@ namespace Ice } /// <summary> + /// Set the maximum depth allowed for graph of Slice class instances. + /// </summary> + /// <param name="classGraphDepthMax">The maximum depth.</param> + public void setClassGraphDepthMax(int classGraphDepthMax) + { + if(classGraphDepthMax < 1) + { + _classGraphDepthMax = 0x7fffffff; + } + else + { + _classGraphDepthMax = classGraphDepthMax; + } + } + + /// <summary> /// Retrieves the closure object associated with this stream. /// </summary> /// <returns>The closure object.</returns> @@ -413,6 +430,10 @@ namespace Ice other._sliceValues = _sliceValues; _sliceValues = tmpSliceValues; + int tmpClassGraphDepthMax = other._classGraphDepthMax; + other._classGraphDepthMax = _classGraphDepthMax; + _classGraphDepthMax = tmpClassGraphDepthMax; + // // Swap is never called for InputStreams that have encapsulations being read. However, // encapsulations might still be set in case un-marshalling failed. We just @@ -2733,12 +2754,27 @@ namespace Ice abstract private class EncapsDecoder { - internal EncapsDecoder(InputStream stream, Encaps encaps, bool sliceValues, ValueFactoryManager f, + protected struct PatchEntry + { + public PatchEntry(System.Action<Value> cb, int classGraphDepth) + { + this.cb = cb; + this.classGraphDepth = classGraphDepth; + } + + public System.Action<Value> cb; + public int classGraphDepth; + }; + + internal EncapsDecoder(InputStream stream, Encaps encaps, bool sliceValues, + int classGraphDepthMax, ValueFactoryManager f, System.Func<string, Type> cr) { _stream = stream; _encaps = encaps; _sliceValues = sliceValues; + _classGraphDepthMax = classGraphDepthMax; + _classGraphDepth = 0; _valueFactoryManager = f; _classResolver = cr; _typeIdIndex = 0; @@ -2889,7 +2925,7 @@ namespace Ice if(_patchMap == null) { - _patchMap = new Dictionary<int, LinkedList<System.Action<Value>>>(); + _patchMap = new Dictionary<int, LinkedList<PatchEntry>>(); } // @@ -2897,21 +2933,21 @@ namespace Ice // the callback will be called when the instance is // unmarshaled. // - LinkedList<System.Action<Value>> l; + LinkedList<PatchEntry> l; if(!_patchMap.TryGetValue(index, out l)) { // // We have no outstanding instances to be patched for this // index, so make a new entry in the patch map. // - l = new LinkedList<System.Action<Value>>(); + l = new LinkedList<PatchEntry>(); _patchMap.Add(index, l); } // // Append a patch entry for this instance. // - l.AddLast(cb); + l.AddLast(new PatchEntry(cb, _classGraphDepth)); } protected void unmarshal(int index, Value v) @@ -2932,7 +2968,7 @@ namespace Ice // // Patch all instances now that the instance is unmarshaled. // - LinkedList<System.Action<Value>> l; + LinkedList<PatchEntry> l; if(_patchMap.TryGetValue(index, out l)) { Debug.Assert(l.Count > 0); @@ -2940,9 +2976,9 @@ namespace Ice // // Patch all pointers that refer to the instance. // - foreach(System.Action<Value> cb in l) + foreach(PatchEntry entry in l) { - cb(v); + entry.cb(v); } // @@ -3001,13 +3037,15 @@ namespace Ice protected readonly InputStream _stream; protected readonly Encaps _encaps; protected readonly bool _sliceValues; + protected readonly int _classGraphDepthMax; + protected int _classGraphDepth; protected ValueFactoryManager _valueFactoryManager; protected System.Func<string, Type> _classResolver; // // Encapsulation attributes for object unmarshaling. // - protected Dictionary<int, LinkedList<System.Action<Value>> > _patchMap; + protected Dictionary<int, LinkedList<PatchEntry>> _patchMap; private Dictionary<int, Value> _unmarshaledMap; private Dictionary<int, string> _typeIdMap; private int _typeIdIndex; @@ -3017,9 +3055,9 @@ namespace Ice private sealed class EncapsDecoder10 : EncapsDecoder { - internal EncapsDecoder10(InputStream stream, Encaps encaps, bool sliceValues, ValueFactoryManager f, - System.Func<string, Type> cr) - : base(stream, encaps, sliceValues, f, cr) + internal EncapsDecoder10(InputStream stream, Encaps encaps, bool sliceValues, int classGraphDepthMax, + ValueFactoryManager f, System.Func<string, Type> cr) + : base(stream, encaps, sliceValues, classGraphDepthMax, f, cr) { _sliceType = SliceType.NoSlice; } @@ -3297,6 +3335,30 @@ namespace Ice } // + // Compute the biggest class graph depth of this object. To compute this, + // we get the class graph depth of each ancestor from the patch map and + // keep the biggest one. + // + _classGraphDepth = 0; + LinkedList<PatchEntry> l; + if(_patchMap != null && _patchMap.TryGetValue(index, out l)) + { + Debug.Assert(l.Count > 0); + foreach(PatchEntry entry in l) + { + if(entry.classGraphDepth > _classGraphDepth) + { + _classGraphDepth = entry.classGraphDepth; + } + } + } + + if(++_classGraphDepth > _classGraphDepthMax) + { + throw new MarshalException("maximum class graph depth reached"); + } + + // // Unmarshal the instance and add it to the map of unmarshaled instances. // unmarshal(index, v); @@ -3313,9 +3375,9 @@ namespace Ice private sealed class EncapsDecoder11 : EncapsDecoder { - internal EncapsDecoder11(InputStream stream, Encaps encaps, bool sliceValues, ValueFactoryManager f, - System.Func<string, Type> cr, System.Func<int, string> r) - : base(stream, encaps, sliceValues, f, cr) + internal EncapsDecoder11(InputStream stream, Encaps encaps, bool sliceValues, int classGraphDepthMax, + ValueFactoryManager f, System.Func<string, Type> cr, System.Func<int, string> r) + : base(stream, encaps, sliceValues, classGraphDepthMax, f, cr) { _compactIdResolver = r; _current = null; @@ -3841,11 +3903,18 @@ namespace Ice startSlice(); // Read next Slice header for next iteration. } + if(++_classGraphDepth > _classGraphDepthMax) + { + throw new MarshalException("maximum class graph depth reached"); + } + // // Unmarshal the instance. // unmarshal(index, v); + --_classGraphDepth; + if(_current == null && _patchMap != null && _patchMap.Count > 0) { // @@ -4008,19 +4077,20 @@ namespace Ice { if(_encapsStack.encoding_1_0) { - _encapsStack.decoder = new EncapsDecoder10(this, _encapsStack, _sliceValues, _valueFactoryManager, - _classResolver); + _encapsStack.decoder = new EncapsDecoder10(this, _encapsStack, _sliceValues, _classGraphDepthMax, + _valueFactoryManager, _classResolver); } else { - _encapsStack.decoder = new EncapsDecoder11(this, _encapsStack, _sliceValues, _valueFactoryManager, - _classResolver, _compactIdResolver); + _encapsStack.decoder = new EncapsDecoder11(this, _encapsStack, _sliceValues, _classGraphDepthMax, + _valueFactoryManager, _classResolver, _compactIdResolver); } } } private bool _sliceValues; private bool _traceSlicing; + private int _classGraphDepthMax; private int _startSeq; private int _minSeqSize; diff --git a/csharp/src/Ice/Instance.cs b/csharp/src/Ice/Instance.cs index a4a1c3e7c1d..423b24b96d2 100644 --- a/csharp/src/Ice/Instance.cs +++ b/csharp/src/Ice/Instance.cs @@ -336,6 +336,12 @@ namespace IceInternal return _batchAutoFlushSize; } + public int classGraphDepthMax() + { + // No mutex lock, immutable. + return _classGraphDepthMax; + } + public Ice.ToStringMode toStringMode() { @@ -857,6 +863,19 @@ namespace IceInternal } } + { + const int defaultValue = 100; + var num = _initData.properties.getPropertyAsIntWithDefault("Ice.ClassGraphDepthMax", defaultValue); + if(num < 1 || num > 0x7fffffff) + { + _classGraphDepthMax = 0x7fffffff; + } + else + { + _classGraphDepthMax = num; + } + } + string toStringModeStr = _initData.properties.getPropertyWithDefault("Ice.ToStringMode", "Unicode"); if(toStringModeStr == "Unicode") { @@ -1560,6 +1579,7 @@ namespace IceInternal private DefaultsAndOverrides _defaultsAndOverrides; // Immutable, not reset by destroy(). private int _messageSizeMax; // Immutable, not reset by destroy(). private int _batchAutoFlushSize; // Immutable, not reset by destroy(). + private int _classGraphDepthMax; // Immutable, not reset by destroy(). private Ice.ToStringMode _toStringMode; // Immutable, not reset by destroy(). private int _cacheMessageBuffers; // Immutable, not reset by destroy(). private ACMConfig _clientACM; // Immutable, not reset by destroy(). diff --git a/csharp/src/Ice/PropertyNames.cs b/csharp/src/Ice/PropertyNames.cs index b5fa1fec421..3d1359ac6de 100644 --- a/csharp/src/Ice/PropertyNames.cs +++ b/csharp/src/Ice/PropertyNames.cs @@ -6,7 +6,7 @@ // ICE_LICENSE file included in this distribution. // // ********************************************************************** -// Generated by makeprops.py from file ./config/PropertyNames.xml, Tue Feb 28 15:01:12 2017 +// Generated by makeprops.py from file ./config/PropertyNames.xml, Thu Mar 23 15:24:16 2017 // IMPORTANT: Do not edit this file -- any edits made here will be lost! @@ -79,6 +79,7 @@ namespace IceInternal new Property(@"^Ice\.BatchAutoFlush$", true, null), new Property(@"^Ice\.BatchAutoFlushSize$", false, null), new Property(@"^Ice\.ChangeUser$", false, null), + new Property(@"^Ice\.ClassGraphDepthMax$", false, null), new Property(@"^Ice\.ClientAccessPolicyProtocol$", false, null), new Property(@"^Ice\.Compression\.Level$", false, null), new Property(@"^Ice\.CollectObjects$", false, null), diff --git a/csharp/test/Ice/exceptions/AllTests.cs b/csharp/test/Ice/exceptions/AllTests.cs index b0e7b109849..2627821fb7c 100644 --- a/csharp/test/Ice/exceptions/AllTests.cs +++ b/csharp/test/Ice/exceptions/AllTests.cs @@ -426,29 +426,40 @@ public class AllTests : TestCommon.AllTests catch(Ice.ConnectionLostException) { } + catch(Ice.UnknownLocalException) + { + // Expected with JS bidir server + } catch(Exception) { test(false); } - ThrowerPrx thrower2 = ThrowerPrxHelper.uncheckedCast( - communicator.stringToProxy("thrower:" + app.getTestEndpoint(1))); - try - { - thrower2.throwMemoryLimitException(new byte[2 * 1024 * 1024]); // 2MB (no limits) - } - catch(Ice.MemoryLimitException) - { - } - ThrowerPrx thrower3 = ThrowerPrxHelper.uncheckedCast( - communicator.stringToProxy("thrower:" + app.getTestEndpoint(2))); try { - thrower3.throwMemoryLimitException(new byte[1024]); // 1KB limit - test(false); + ThrowerPrx thrower2 = ThrowerPrxHelper.uncheckedCast( + communicator.stringToProxy("thrower:" + app.getTestEndpoint(1))); + try + { + thrower2.throwMemoryLimitException(new byte[2 * 1024 * 1024]); // 2MB (no limits) + } + catch(Ice.MemoryLimitException) + { + } + ThrowerPrx thrower3 = ThrowerPrxHelper.uncheckedCast( + communicator.stringToProxy("thrower:" + app.getTestEndpoint(2))); + try + { + thrower3.throwMemoryLimitException(new byte[1024]); // 1KB limit + test(false); + } + catch(Ice.ConnectionLostException) + { + } } - catch(Ice.ConnectionLostException) + catch(Ice.ConnectionRefusedException) { + // Expected with JS bidir server } WriteLine("ok"); diff --git a/csharp/test/Ice/objects/AllTests.cs b/csharp/test/Ice/objects/AllTests.cs index d050088c288..e61141f5daa 100644 --- a/csharp/test/Ice/objects/AllTests.cs +++ b/csharp/test/Ice/objects/AllTests.cs @@ -276,6 +276,38 @@ public class AllTests : TestCommon.AllTests } WriteLine("ok"); + Write("testing recursive type... "); + Flush(); + Recursive top = new Recursive(); + Recursive p = top; + int depth = 0; + try + { + for(; depth <= 1000; ++depth) + { + p.v = new Recursive(); + p = p.v; + if((depth < 10 && (depth % 10) == 0) || + (depth < 1000 && (depth % 100) == 0) || + (depth < 10000 && (depth % 1000) == 0) || + (depth % 10000) == 0) + { + initial.setRecursive(top); + } + } + test(!initial.supportsClassGraphDepthMax()); + } + catch(Ice.UnknownLocalException) + { + // Expected marshal exception from the server (max class graph depth reached) + } + catch(Ice.UnknownException) + { + // Expected stack overflow from the server (Java only) + } + initial.setRecursive(new Recursive()); + WriteLine("ok"); + Write("testing compact ID..."); Flush(); try diff --git a/csharp/test/Ice/objects/Collocated.cs b/csharp/test/Ice/objects/Collocated.cs index 637b8a01b77..7a034a4eb44 100644 --- a/csharp/test/Ice/objects/Collocated.cs +++ b/csharp/test/Ice/objects/Collocated.cs @@ -33,6 +33,13 @@ public class Collocated : TestCommon.Application return 0; } + protected override Ice.InitializationData getInitData(ref string[] args) + { + Ice.InitializationData initData = base.getInitData(ref args); + initData.properties.setProperty("Ice.Warn.Dispatch", "0"); + return initData; + } + public static int Main(string[] args) { Collocated app = new Collocated(); diff --git a/csharp/test/Ice/objects/InitialI.cs b/csharp/test/Ice/objects/InitialI.cs index 686beac8e0f..05f133c40c6 100644 --- a/csharp/test/Ice/objects/InitialI.cs +++ b/csharp/test/Ice/objects/InitialI.cs @@ -44,7 +44,7 @@ public sealed class InitialI : InitialDisp_ c = _c; d = _d; } - + public override B getB1(Ice.Current current) { return _b1; @@ -89,7 +89,16 @@ public sealed class InitialI : InitialDisp_ { return new HI(); } - + + public override void setRecursive(Recursive r, Ice.Current current) + { + } + + public override bool supportsClassGraphDepthMax(Ice.Current current) + { + return true; + } + public override D1 getD1(D1 d1, Ice.Current current) { return d1; diff --git a/csharp/test/Ice/objects/Server.cs b/csharp/test/Ice/objects/Server.cs index 26157bc146a..ab1f3c9cce2 100644 --- a/csharp/test/Ice/objects/Server.cs +++ b/csharp/test/Ice/objects/Server.cs @@ -54,6 +54,13 @@ public class Server : TestCommon.Application return 0; } + protected override Ice.InitializationData getInitData(ref string[] args) + { + Ice.InitializationData initData = base.getInitData(ref args); + initData.properties.setProperty("Ice.Warn.Dispatch", "0"); + return initData; + } + public static int Main(string[] args) { Server app = new Server(); diff --git a/csharp/test/Ice/objects/Test.ice b/csharp/test/Ice/objects/Test.ice index d985d0676ed..e33229ad4e9 100644 --- a/csharp/test/Ice/objects/Test.ice +++ b/csharp/test/Ice/objects/Test.ice @@ -162,6 +162,11 @@ exception EDerived extends EBase A1 a4; }; +class Recursive +{ + Recursive v; +}; + interface Initial { void shutdown(); @@ -172,6 +177,9 @@ interface Initial E getE(); F getF(); + void setRecursive(Recursive p); + bool supportsClassGraphDepthMax(); + ["marshaled-result"] B getMB(); ["amd", "marshaled-result"] B getAMDMB(); diff --git a/java-compat/src/Ice/src/main/java/Ice/ConnectionI.java b/java-compat/src/Ice/src/main/java/Ice/ConnectionI.java index 165b6578b0e..08336df7d02 100644 --- a/java-compat/src/Ice/src/main/java/Ice/ConnectionI.java +++ b/java-compat/src/Ice/src/main/java/Ice/ConnectionI.java @@ -2823,7 +2823,9 @@ public final class ConnectionI extends IceInternal.EventHandler // // Suppress AssertionError and OutOfMemoryError, rethrow everything else. // - if(!(t instanceof java.lang.AssertionError || t instanceof java.lang.OutOfMemoryError)) + if(!(t instanceof java.lang.AssertionError || + t instanceof java.lang.OutOfMemoryError || + t instanceof java.lang.StackOverflowError)) { throw (java.lang.Error)t; } @@ -2848,7 +2850,9 @@ public final class ConnectionI extends IceInternal.EventHandler // // Suppress AssertionError and OutOfMemoryError, rethrow everything else. // - if(!(ex instanceof java.lang.AssertionError || ex instanceof java.lang.OutOfMemoryError)) + if(!(ex instanceof java.lang.AssertionError || + ex instanceof java.lang.OutOfMemoryError || + ex instanceof java.lang.StackOverflowError)) { throw ex; } diff --git a/java-compat/src/Ice/src/main/java/IceInternal/CollocatedRequestHandler.java b/java-compat/src/Ice/src/main/java/IceInternal/CollocatedRequestHandler.java index ac11851836e..94402c7389e 100644 --- a/java-compat/src/Ice/src/main/java/IceInternal/CollocatedRequestHandler.java +++ b/java-compat/src/Ice/src/main/java/IceInternal/CollocatedRequestHandler.java @@ -340,7 +340,9 @@ public class CollocatedRequestHandler implements RequestHandler, ResponseHandler // // Suppress AssertionError and OutOfMemoryError, rethrow everything else. // - if(!(t instanceof java.lang.AssertionError || t instanceof java.lang.OutOfMemoryError)) + if(!(t instanceof java.lang.AssertionError || + t instanceof java.lang.OutOfMemoryError || + t instanceof java.lang.StackOverflowError)) { throw (java.lang.Error)t; } @@ -365,13 +367,17 @@ public class CollocatedRequestHandler implements RequestHandler, ResponseHandler // // Suppress AssertionError and OutOfMemoryError, rethrow everything else. // - if(!(ex instanceof java.lang.AssertionError || ex instanceof java.lang.OutOfMemoryError)) + if(!(ex instanceof java.lang.AssertionError || + ex instanceof java.lang.OutOfMemoryError || + ex instanceof java.lang.StackOverflowError)) { throw ex; } } - - _adapter.decDirectCount(); + finally + { + _adapter.decDirectCount(); + } } private void diff --git a/java-compat/src/Ice/src/main/java/IceInternal/PropertyNames.java b/java-compat/src/Ice/src/main/java/IceInternal/PropertyNames.java index 1b2db0f1030..dc971363790 100644 --- a/java-compat/src/Ice/src/main/java/IceInternal/PropertyNames.java +++ b/java-compat/src/Ice/src/main/java/IceInternal/PropertyNames.java @@ -6,7 +6,7 @@ // ICE_LICENSE file included in this distribution. // // ********************************************************************** -// Generated by makeprops.py from file ./config/PropertyNames.xml, Tue Feb 28 15:01:12 2017 +// Generated by makeprops.py from file ./config/PropertyNames.xml, Thu Mar 23 15:24:16 2017 // IMPORTANT: Do not edit this file -- any edits made here will be lost! @@ -79,6 +79,7 @@ public final class PropertyNames new Property("Ice\\.BatchAutoFlush", true, null), new Property("Ice\\.BatchAutoFlushSize", false, null), new Property("Ice\\.ChangeUser", false, null), + new Property("Ice\\.ClassGraphDepthMax", false, null), new Property("Ice\\.ClientAccessPolicyProtocol", false, null), new Property("Ice\\.Compression\\.Level", false, null), new Property("Ice\\.CollectObjects", false, null), diff --git a/java-compat/test/src/main/java/test/Ice/exceptions/AllTests.java b/java-compat/test/src/main/java/test/Ice/exceptions/AllTests.java index d00bd7bef7c..bb5e82db6f4 100644 --- a/java-compat/test/src/main/java/test/Ice/exceptions/AllTests.java +++ b/java-compat/test/src/main/java/test/Ice/exceptions/AllTests.java @@ -1131,6 +1131,10 @@ public class AllTests catch(Ice.ConnectionLostException ex) { } + catch(Ice.UnknownLocalException ex) + { + // Expected with JS bidir server + } catch(Ice.SocketException ex) { // This can be raised if the connection is closed during the client's call to write(). @@ -1141,24 +1145,31 @@ public class AllTests test(false); } - ThrowerPrx thrower2 = ThrowerPrxHelper.uncheckedCast( - communicator.stringToProxy("thrower:" + app.getTestEndpoint(1))); try { - thrower2.throwMemoryLimitException(new byte[2 * 1024 * 1024]); // 2MB (no limits) - } - catch(Ice.MemoryLimitException ex) - { - } - ThrowerPrx thrower3 = ThrowerPrxHelper.uncheckedCast( - communicator.stringToProxy("thrower:" + app.getTestEndpoint(2))); - try - { - thrower3.throwMemoryLimitException(new byte[1024]); // 1KB limit - test(false); + ThrowerPrx thrower2 = ThrowerPrxHelper.uncheckedCast( + communicator.stringToProxy("thrower:" + app.getTestEndpoint(1))); + try + { + thrower2.throwMemoryLimitException(new byte[2 * 1024 * 1024]); // 2MB (no limits) + } + catch(Ice.MemoryLimitException ex) + { + } + ThrowerPrx thrower3 = ThrowerPrxHelper.uncheckedCast( + communicator.stringToProxy("thrower:" + app.getTestEndpoint(2))); + try + { + thrower3.throwMemoryLimitException(new byte[1024]); // 1KB limit + test(false); + } + catch(Ice.ConnectionLostException ex) + { + } } - catch(Ice.ConnectionLostException ex) + catch(Ice.ConnectionRefusedException ex) { + // Expected with JS bidir server } out.println("ok"); diff --git a/java-compat/test/src/main/java/test/Ice/objects/AllTests.java b/java-compat/test/src/main/java/test/Ice/objects/AllTests.java index f71bf5010a4..0e4588c6e94 100644 --- a/java-compat/test/src/main/java/test/Ice/objects/AllTests.java +++ b/java-compat/test/src/main/java/test/Ice/objects/AllTests.java @@ -31,6 +31,7 @@ import test.Ice.objects.Test.BaseSeqHolder; import test.Ice.objects.Test.InitialPrx; import test.Ice.objects.Test.InitialPrxHelper; import test.Ice.objects.Test.J; +import test.Ice.objects.Test.Recursive; import test.Ice.objects.Test.UnexpectedObjectExceptionTestPrx; import test.Ice.objects.Test.UnexpectedObjectExceptionTestPrxHelper; @@ -251,6 +252,42 @@ public class AllTests } out.println("ok"); + out.print("testing recursive type... "); + out.flush(); + Recursive top = new Recursive(); + Recursive p = top; + int depth = 0; + try + { + for(; depth <= 20000; ++depth) + { + p.v = new Recursive(); + p = p.v; + if((depth < 10 && (depth % 10) == 0) || + (depth < 1000 && (depth % 100) == 0) || + (depth < 10000 && (depth % 1000) == 0) || + (depth % 10000) == 0) + { + initial.setRecursive(top); + } + } + test(!initial.supportsClassGraphDepthMax()); + } + catch(Ice.UnknownLocalException ex) + { + // Expected marshal exception from the server (max class graph depth reached) + } + catch(Ice.UnknownException ex) + { + // Expected stack overflow from the server (Java only) + } + catch(java.lang.StackOverflowError ex) + { + // Stack overflow while writing instances + } + initial.setRecursive(new Recursive()); + out.println("ok"); + out.print("testing compact ID..."); out.flush(); try diff --git a/java-compat/test/src/main/java/test/Ice/objects/Collocated.java b/java-compat/test/src/main/java/test/Ice/objects/Collocated.java index f83e0167f26..9a66174ba08 100644 --- a/java-compat/test/src/main/java/test/Ice/objects/Collocated.java +++ b/java-compat/test/src/main/java/test/Ice/objects/Collocated.java @@ -105,6 +105,7 @@ public class Collocated extends test.Util.Application { Ice.InitializationData initData = super.getInitData(argsH); initData.properties.setProperty("Ice.Package.Test", "test.Ice.objects"); + initData.properties.setProperty("Ice.Warn.Dispatch", "0"); return initData; } diff --git a/java-compat/test/src/main/java/test/Ice/objects/InitialI.java b/java-compat/test/src/main/java/test/Ice/objects/InitialI.java index ddb1957d013..24ae8c3e697 100644 --- a/java-compat/test/src/main/java/test/Ice/objects/InitialI.java +++ b/java-compat/test/src/main/java/test/Ice/objects/InitialI.java @@ -24,6 +24,7 @@ import test.Ice.objects.Test.D1; import test.Ice.objects.Test.EDerived; import test.Ice.objects.Test.Base; import test.Ice.objects.Test.BaseSeqHolder; +import test.Ice.objects.Test.Recursive; import test.Ice.objects.Test.Initial; import test.Ice.objects.Test.Compact; import test.Ice.objects.Test.CompactExt; @@ -126,6 +127,18 @@ public final class InitialI extends Initial } @Override + public void + setRecursive(Recursive r, Ice.Current current) + { + } + + @Override + public boolean supportsClassGraphDepthMax(Ice.Current current) + { + return false; + } + + @Override public B getMB(Ice.Current current) { @@ -159,14 +172,14 @@ public final class InitialI extends Initial { return new HI(); } - + @Override public D1 getD1(D1 d1, Ice.Current current) { return d1; } - + @Override public void throwEDerived(Ice.Current current) throws EDerived diff --git a/java-compat/test/src/main/java/test/Ice/objects/Server.java b/java-compat/test/src/main/java/test/Ice/objects/Server.java index 560befcbe0d..6d36d75e5f7 100644 --- a/java-compat/test/src/main/java/test/Ice/objects/Server.java +++ b/java-compat/test/src/main/java/test/Ice/objects/Server.java @@ -58,6 +58,7 @@ public class Server extends test.Util.Application { Ice.InitializationData initData = super.getInitData(argsH); initData.properties.setProperty("Ice.Package.Test", "test.Ice.objects"); + initData.properties.setProperty("Ice.Warn.Dispatch", "0"); initData.properties.setProperty("TestAdapter.Endpoints", getTestEndpoint(initData.properties, 0)); return initData; } diff --git a/java-compat/test/src/main/java/test/Ice/objects/Test.ice b/java-compat/test/src/main/java/test/Ice/objects/Test.ice index 629cc8c10b8..07cfcd797d4 100644 --- a/java-compat/test/src/main/java/test/Ice/objects/Test.ice +++ b/java-compat/test/src/main/java/test/Ice/objects/Test.ice @@ -163,6 +163,11 @@ exception EDerived extends EBase A1 a4; }; +class Recursive +{ + Recursive v; +}; + class Initial { void shutdown(); @@ -173,6 +178,9 @@ class Initial E getE(); F getF(); + void setRecursive(Recursive p); + bool supportsClassGraphDepthMax(); + ["marshaled-result"] B getMB(); ["amd", "marshaled-result"] B getAMDMB(); diff --git a/java/src/Ice/src/main/java/com/zeroc/Ice/ConnectionI.java b/java/src/Ice/src/main/java/com/zeroc/Ice/ConnectionI.java index 296f0af7969..c1c33414122 100644 --- a/java/src/Ice/src/main/java/com/zeroc/Ice/ConnectionI.java +++ b/java/src/Ice/src/main/java/com/zeroc/Ice/ConnectionI.java @@ -2727,7 +2727,9 @@ public final class ConnectionI extends com.zeroc.IceInternal.EventHandler // // Suppress AssertionError and OutOfMemoryError, rethrow everything else. // - if(!(t instanceof java.lang.AssertionError || t instanceof java.lang.OutOfMemoryError)) + if(!(t instanceof java.lang.AssertionError || + t instanceof java.lang.OutOfMemoryError || + t instanceof java.lang.StackOverflowError)) { throw (java.lang.Error)t; } @@ -2752,7 +2754,9 @@ public final class ConnectionI extends com.zeroc.IceInternal.EventHandler // // Suppress AssertionError and OutOfMemoryError, rethrow everything else. // - if(!(ex instanceof java.lang.AssertionError || ex instanceof java.lang.OutOfMemoryError)) + if(!(ex instanceof java.lang.AssertionError || + ex instanceof java.lang.OutOfMemoryError || + ex instanceof java.lang.StackOverflowError)) { throw ex; } diff --git a/java/src/Ice/src/main/java/com/zeroc/IceInternal/CollocatedRequestHandler.java b/java/src/Ice/src/main/java/com/zeroc/IceInternal/CollocatedRequestHandler.java index 7512638a7c0..a9a6ee0f919 100644 --- a/java/src/Ice/src/main/java/com/zeroc/IceInternal/CollocatedRequestHandler.java +++ b/java/src/Ice/src/main/java/com/zeroc/IceInternal/CollocatedRequestHandler.java @@ -341,7 +341,9 @@ public class CollocatedRequestHandler implements RequestHandler, ResponseHandler // // Suppress AssertionError and OutOfMemoryError, rethrow everything else. // - if(!(t instanceof java.lang.AssertionError || t instanceof java.lang.OutOfMemoryError)) + if(!(t instanceof java.lang.AssertionError || + t instanceof java.lang.OutOfMemoryError || + t instanceof java.lang.StackOverflowError)) { throw (java.lang.Error)t; } @@ -366,13 +368,17 @@ public class CollocatedRequestHandler implements RequestHandler, ResponseHandler // // Suppress AssertionError and OutOfMemoryError, rethrow everything else. // - if(!(ex instanceof java.lang.AssertionError || ex instanceof java.lang.OutOfMemoryError)) + if(!(ex instanceof java.lang.AssertionError || + ex instanceof java.lang.OutOfMemoryError || + ex instanceof java.lang.StackOverflowError)) { throw ex; } } - - _adapter.decDirectCount(); + finally + { + _adapter.decDirectCount(); + } } private void diff --git a/java/src/Ice/src/main/java/com/zeroc/IceInternal/PropertyNames.java b/java/src/Ice/src/main/java/com/zeroc/IceInternal/PropertyNames.java index eb3319e9b46..77db7c18407 100644 --- a/java/src/Ice/src/main/java/com/zeroc/IceInternal/PropertyNames.java +++ b/java/src/Ice/src/main/java/com/zeroc/IceInternal/PropertyNames.java @@ -6,7 +6,7 @@ // ICE_LICENSE file included in this distribution. // // ********************************************************************** -// Generated by makeprops.py from file ./config/PropertyNames.xml, Tue Feb 28 15:01:12 2017 +// Generated by makeprops.py from file ./config/PropertyNames.xml, Thu Mar 23 15:24:16 2017 // IMPORTANT: Do not edit this file -- any edits made here will be lost! @@ -79,6 +79,7 @@ public final class PropertyNames new Property("Ice\\.BatchAutoFlush", true, null), new Property("Ice\\.BatchAutoFlushSize", false, null), new Property("Ice\\.ChangeUser", false, null), + new Property("Ice\\.ClassGraphDepthMax", false, null), new Property("Ice\\.ClientAccessPolicyProtocol", false, null), new Property("Ice\\.Compression\\.Level", false, null), new Property("Ice\\.CollectObjects", false, null), diff --git a/java/test/src/main/java/test/Ice/exceptions/AllTests.java b/java/test/src/main/java/test/Ice/exceptions/AllTests.java index 1cce083ca40..acfb3dc000b 100644 --- a/java/test/src/main/java/test/Ice/exceptions/AllTests.java +++ b/java/test/src/main/java/test/Ice/exceptions/AllTests.java @@ -438,6 +438,10 @@ public class AllTests catch(com.zeroc.Ice.ConnectionLostException ex) { } + catch(com.zeroc.Ice.UnknownLocalException ex) + { + // Expected with JS bidir server + } catch(com.zeroc.Ice.SocketException ex) { // This can be raised if the connection is closed during the client's call to write(). @@ -448,24 +452,31 @@ public class AllTests test(false); } - ThrowerPrx thrower2 = ThrowerPrx.uncheckedCast(communicator.stringToProxy("thrower:" + - app.getTestEndpoint(1))); - try - { - thrower2.throwMemoryLimitException(new byte[2 * 1024 * 1024]); // 2MB (no limits) - } - catch(com.zeroc.Ice.MemoryLimitException ex) - { - } - ThrowerPrx thrower3 = ThrowerPrx.uncheckedCast(communicator.stringToProxy("thrower:" + - app.getTestEndpoint(2))); try { - thrower3.throwMemoryLimitException(new byte[1024]); // 1KB limit - test(false); - } - catch(com.zeroc.Ice.ConnectionLostException ex) - { + ThrowerPrx thrower2 = ThrowerPrx.uncheckedCast(communicator.stringToProxy("thrower:" + + app.getTestEndpoint(1))); + try + { + thrower2.throwMemoryLimitException(new byte[2 * 1024 * 1024]); // 2MB (no limits) + } + catch(com.zeroc.Ice.MemoryLimitException ex) + { + } + ThrowerPrx thrower3 = ThrowerPrx.uncheckedCast(communicator.stringToProxy("thrower:" + + app.getTestEndpoint(2))); + try + { + thrower3.throwMemoryLimitException(new byte[1024]); // 1KB limit + test(false); + } + catch(com.zeroc.Ice.ConnectionLostException ex) + { + } + } + catch(com.zeroc.Ice.ConnectionRefusedException ex) + { + // Expected with JS bidir server } out.println("ok"); diff --git a/java/test/src/main/java/test/Ice/objects/AllTests.java b/java/test/src/main/java/test/Ice/objects/AllTests.java index c7b65fe7164..31dc2f69cea 100644 --- a/java/test/src/main/java/test/Ice/objects/AllTests.java +++ b/java/test/src/main/java/test/Ice/objects/AllTests.java @@ -27,6 +27,7 @@ import test.Ice.objects.Test.S; import test.Ice.objects.Test.Initial; import test.Ice.objects.Test.InitialPrx; import test.Ice.objects.Test.J; +import test.Ice.objects.Test.Recursive; import test.Ice.objects.Test.UnexpectedObjectExceptionTestPrx; public class AllTests @@ -241,6 +242,42 @@ public class AllTests } out.println("ok"); + out.print("testing recursive type... "); + out.flush(); + Recursive top = new Recursive(); + Recursive p = top; + int depth = 0; + try + { + for(; depth <= 20000; ++depth) + { + p.v = new Recursive(); + p = p.v; + if((depth < 10 && (depth % 10) == 0) || + (depth < 1000 && (depth % 100) == 0) || + (depth < 10000 && (depth % 1000) == 0) || + (depth % 10000) == 0) + { + initial.setRecursive(top); + } + } + test(!initial.supportsClassGraphDepthMax()); + } + catch(com.zeroc.Ice.UnknownLocalException ex) + { + // Expected marshal exception from the server (max class graph depth reached) + } + catch(com.zeroc.Ice.UnknownException ex) + { + // Expected stack overflow from the server (Java only) + } + catch(java.lang.StackOverflowError ex) + { + // Stack overflow while writing instances + } + initial.setRecursive(new Recursive()); + out.println("ok"); + out.print("testing compact ID..."); out.flush(); try diff --git a/java/test/src/main/java/test/Ice/objects/Collocated.java b/java/test/src/main/java/test/Ice/objects/Collocated.java index 44ca644bf4d..ffb62ec24e4 100644 --- a/java/test/src/main/java/test/Ice/objects/Collocated.java +++ b/java/test/src/main/java/test/Ice/objects/Collocated.java @@ -108,6 +108,7 @@ public class Collocated extends test.Util.Application { com.zeroc.Ice.InitializationData initData = super.getInitData(args, rArgs); initData.properties.setProperty("Ice.Package.Test", "test.Ice.objects"); + initData.properties.setProperty("Ice.Warn.Dispatch", "0"); return initData; } diff --git a/java/test/src/main/java/test/Ice/objects/InitialI.java b/java/test/src/main/java/test/Ice/objects/InitialI.java index 8b0876bc4c6..fe879cf5276 100644 --- a/java/test/src/main/java/test/Ice/objects/InitialI.java +++ b/java/test/src/main/java/test/Ice/objects/InitialI.java @@ -106,6 +106,17 @@ public final class InitialI implements Initial } @Override + public void setRecursive(Recursive r, com.zeroc.Ice.Current current) + { + } + + @Override + public boolean supportsClassGraphDepthMax(com.zeroc.Ice.Current current) + { + return false; + } + + @Override public com.zeroc.Ice.Value getI(com.zeroc.Ice.Current current) { return new II(); diff --git a/java/test/src/main/java/test/Ice/objects/Server.java b/java/test/src/main/java/test/Ice/objects/Server.java index f6989af992b..d8e051a0592 100644 --- a/java/test/src/main/java/test/Ice/objects/Server.java +++ b/java/test/src/main/java/test/Ice/objects/Server.java @@ -58,6 +58,7 @@ public class Server extends test.Util.Application { com.zeroc.Ice.InitializationData initData = super.getInitData(args, rArgs); initData.properties.setProperty("Ice.Package.Test", "test.Ice.objects"); + initData.properties.setProperty("Ice.Warn.Dispatch", "0"); initData.properties.setProperty("TestAdapter.Endpoints", getTestEndpoint(initData.properties, 0)); return initData; } diff --git a/java/test/src/main/java/test/Ice/objects/Test.ice b/java/test/src/main/java/test/Ice/objects/Test.ice index c9b3b592b26..173d3e50d97 100644 --- a/java/test/src/main/java/test/Ice/objects/Test.ice +++ b/java/test/src/main/java/test/Ice/objects/Test.ice @@ -163,6 +163,11 @@ exception EDerived extends EBase A1 a4; }; +class Recursive +{ + Recursive v; +}; + interface Initial { void shutdown(); @@ -173,6 +178,9 @@ interface Initial E getE(); F getF(); + void setRecursive(Recursive p); + bool supportsClassGraphDepthMax(); + ["marshaled-result"] B getMB(); ["amd", "marshaled-result"] B getAMDMB(); diff --git a/js/bin/HttpServer.js b/js/bin/HttpServer.js index 53c42327368..5390d306be3 100644 --- a/js/bin/HttpServer.js +++ b/js/bin/HttpServer.js @@ -26,13 +26,12 @@ function Init() json: "application/json", }; - var TestData = - { - languages: [{value: "cpp", name: "C++"}, {value: "java", name: "Java"}] - }; + var TestData = {}; + + var languages = [{value: "cpp", name: "C++"}, {value: "java", name: "Java"}] if(process.platform == "win32") { - TestData.languages.push({value: "csharp", name: "C#"}); + languages.push({value: "csharp", name: "C#"}); } var libraries = ["/lib/Ice.js", "/lib/Ice.min.js", @@ -98,9 +97,9 @@ function Init() } else { - var languages = TestData.languages.map(function(o) { return o.value; }); - var j = languages.indexOf(language); - language = languages[j == languages.length - 1 ? 0 : j + 1]; + var lgs = languages.map(function(o) { return o.value; }); + var j = lgs.indexOf(language); + language = lgs[j == lgs.length - 1 ? 0 : j + 1]; worker = false; protocol = "http"; } @@ -159,6 +158,11 @@ function Init() "/test/Common/TestSuite.js" ]; } + TestData.languages = languages.slice(); + if(testSuite.files.indexOf("Server.js") >= 0) + { + TestData.languages.push({value: "js", name: "JavaScript"}); + } res.writeHead(200, {"Content-Type": "text/html"}); res.end(template.render(TestData)); console.log("HTTP/200 (Ok)" + req.method + " " + req.url.pathname); diff --git a/js/src/Ice/Buffer.js b/js/src/Ice/Buffer.js index d6f395629ba..499d8726cdc 100644 --- a/js/src/Ice/Buffer.js +++ b/js/src/Ice/Buffer.js @@ -371,12 +371,12 @@ class Buffer s = decodeURIComponent(escape(s)); return s; } - + get position() { return this._position; } - + set position(value) { if(value >= 0 && value <= this._limit) @@ -384,12 +384,12 @@ class Buffer this._position = value; } } - + get limit() { return this._limit; } - + set limit(value) { if(value <= this.capacity) @@ -401,17 +401,17 @@ class Buffer } } } - + get capacity() { return this.b === null ? 0 : this.b.byteLength; } - + get remaining() { return this._limit - this._position; } - + // // Create a native buffer from an array of bytes. // diff --git a/js/src/Ice/ConnectionI.js b/js/src/Ice/ConnectionI.js index 1bf5c7d0b28..d937186a6fb 100644 --- a/js/src/Ice/ConnectionI.js +++ b/js/src/Ice/ConnectionI.js @@ -1729,9 +1729,10 @@ class ConnectionI } return AsyncStatus.Sent; } + message.doAdopt(); - this._writeStream.swap(stream); + this._writeStream.swap(message.stream); this._sendStreams.push(message); this.scheduleTimeout(SocketOperation.Write, this._endpoint.timeout()); @@ -1930,9 +1931,18 @@ class ConnectionI { this.invokeException(ex, invokeNum); } + else if(ex instanceof Ice.ServantError) + { + // Ignore + } else { - throw ex; + // + // An Error was raised outside of servant code (i.e., by Ice code). + // Attempt to log the error and clean up. + // + this._logger.error("unexpected exception:\n" + ex.toString()); + this.invokeException(requestId, new Ice.UnknownException(ex), invokeNum, false); } } } diff --git a/js/src/Ice/Exception.js b/js/src/Ice/Exception.js index 3ad61513fa7..14d9472df16 100644 --- a/js/src/Ice/Exception.js +++ b/js/src/Ice/Exception.js @@ -51,6 +51,17 @@ const toString = function(key, object, objectTable, ident) return s; }; +class ServantError extends Error +{ + constructor(cause) + { + super(); + this.cause = cause; + } +} + +Ice.ServantError = ServantError; + // // Ice.Exception // @@ -99,7 +110,7 @@ class Exception extends Error this._inToStringAlready = false; return s; } - + static captureStackTrace(object) { const stack = new Error().stack; @@ -112,7 +123,7 @@ class Exception extends Error Object.defineProperty(object, "stack", { get: function() { - return stack; + return stack; } }); } diff --git a/js/src/Ice/IncomingAsync.js b/js/src/Ice/IncomingAsync.js index 76e4a29666b..4ef1526eb44 100644 --- a/js/src/Ice/IncomingAsync.js +++ b/js/src/Ice/IncomingAsync.js @@ -150,22 +150,7 @@ class IncomingAsync this._instance.initializationData().logger.warning(s.join("")); } - servantLocatorFinished() - { - Debug.assert(this._locator !== null && this._servant !== null); - try - { - this._locator.finished(this._current, this._servant, this._cookie.value); - return true; - } - catch(ex) - { - this.handleException(ex); - } - return false; - } - - handleException(ex) + handleException(ex, amd) { Debug.assert(this._connection !== null); @@ -366,6 +351,11 @@ class IncomingAsync { this._connection.sendNoResponse(); } + + if(!amd) + { + throw new Ice.ServantError(ex); + } } this._connection = null; @@ -431,7 +421,7 @@ class IncomingAsync catch(ex) { this.skipReadParams(); // Required for batch requests. - this.handleException(ex); + this.handleException(ex, false); return; } } @@ -457,7 +447,7 @@ class IncomingAsync catch(ex) { this.skipReadParams(); // Required for batch requests. - this.handleException(ex); + this.handleException(ex, false); return; } } @@ -468,16 +458,16 @@ class IncomingAsync let promise = this._servant._iceDispatch(this, this._current); if(promise !== null) { - promise.then(() => this.response(), (ex) => this.exception(ex)); + promise.then(() => this.completed(null, true), (ex) => this.completed(ex, true)); return; } Debug.assert(!this._response || this._os !== null); - this.response(); + this.completed(null, false); } catch(ex) { - this.exception(ex); + this.completed(ex, false); } } @@ -512,18 +502,31 @@ class IncomingAsync this._current.encoding = this._is.skipEncapsulation(); } - response() + completed(exc, amd) { try { - if(this._locator !== null && !this.servantLocatorFinished()) + if(this._locator !== null && !this.servantLocatorFinished(amd)) { - return; + Debug.assert(this._locator !== null && this._servant !== null); + try + { + this._locator.finished(this._current, this._servant, this._cookie.value); + } + catch(ex) + { + this.handleException(ex, amd); + return; + } } Debug.assert(this._connection !== null); - if(this._response) + if(exc != null) + { + this.handleException(exc, amd); + } + else if(this._response) { this._connection.sendResponse(this._os); } @@ -534,26 +537,18 @@ class IncomingAsync } catch(ex) { - this._connection.invokeException(ex, 1); - } - this._connection = null; - } - - exception(exc) - { - try - { - if(this._locator !== null && !this.servantLocatorFinished()) + if(ex instanceof Ice.LocalException) { - return; + this._connection.invokeException(ex, 1); + } + else + { + throw ex; } - this.handleException(exc); - } - catch(ex) - { - this._connection.invokeException(ex, 1); } + this._connection = null; } + } Ice.IncomingAsync = IncomingAsync; diff --git a/js/src/Ice/ObjectAdapterFactory.js b/js/src/Ice/ObjectAdapterFactory.js index 2115358984a..d68aa5ff46e 100644 --- a/js/src/Ice/ObjectAdapterFactory.js +++ b/js/src/Ice/ObjectAdapterFactory.js @@ -48,7 +48,7 @@ class ObjectAdapterFactory this._instance = null; this._communicator = null; - this._shutdownPromise = _Promise.all(this._adapters.map(adapter => adapter.deactivate())); + _Promise.all(this._adapters.map(adapter => adapter.deactivate())).then(() => this._shutdownPromise.resolve()); return this._shutdownPromise; } diff --git a/js/src/Ice/PropertyNames.js b/js/src/Ice/PropertyNames.js index 835a981434d..7271a5973c2 100644 --- a/js/src/Ice/PropertyNames.js +++ b/js/src/Ice/PropertyNames.js @@ -6,7 +6,7 @@ // ICE_LICENSE file included in this distribution. // // ********************************************************************** -// Generated by makeprops.py from file ./config/PropertyNames.xml, Tue Feb 28 15:01:12 2017 +// Generated by makeprops.py from file ./config/PropertyNames.xml, Thu Mar 23 15:24:16 2017 // IMPORTANT: Do not edit this file -- any edits made here will be lost! @@ -80,6 +80,7 @@ PropertyNames.IceProps = new Property("/^Ice\.BatchAutoFlush/", true, null), new Property("/^Ice\.BatchAutoFlushSize/", false, null), new Property("/^Ice\.ChangeUser/", false, null), + new Property("/^Ice\.ClassGraphDepthMax/", false, null), new Property("/^Ice\.ClientAccessPolicyProtocol/", false, null), new Property("/^Ice\.Compression\.Level/", false, null), new Property("/^Ice\.CollectObjects/", false, null), diff --git a/js/src/Ice/Stream.js b/js/src/Ice/Stream.js index 85386ff8786..8ac72046c6e 100644 --- a/js/src/Ice/Stream.js +++ b/js/src/Ice/Stream.js @@ -1252,7 +1252,7 @@ class InputStream { if(this._encapsStack !== null) { - Debug.assert(this._encapsStack.next); + Debug.assert(this._encapsStack.next === null); this._encapsStack.next = this._encapsCache; this._encapsCache = this._encapsStack; this._encapsCache.reset(); @@ -1840,7 +1840,7 @@ class InputStream // this._encapsStack.decoder.readValue.call( this._encapsStack.decoder, - obj => + cb === null ? null : obj => { if(obj !== null && !(obj instanceof T)) { diff --git a/js/src/Ice/TraceUtil.js b/js/src/Ice/TraceUtil.js index eee9a10d7b1..05452817e2f 100644 --- a/js/src/Ice/TraceUtil.js +++ b/js/src/Ice/TraceUtil.js @@ -25,18 +25,8 @@ const Protocol = Ice.Protocol; const StringUtil = Ice.StringUtil; const OperationMode = Ice.OperationMode; const Identity = Ice.Identity; - const slicingIds = new Map(); -function traceSlicing(kind, typeId, slicingCat, logger) -{ - if(!slicingIds.has(typeId)) - { - logger.trace(slicingCat, `unknown ${kind} type \`${typeId}'`); - slicingIds.set(typeId, 1); - } -} - function printIdentityFacetOperation(s, stream) { let toStringMode = Ice.ToStringMode.Unicode; @@ -366,6 +356,15 @@ function getMessageTypeAsString(type) class TraceUtil { + static traceSlicing(kind, typeId, slicingCat, logger) + { + if(!slicingIds.has(typeId)) + { + logger.trace(slicingCat, `unknown ${kind} type \`${typeId}'`); + slicingIds.set(typeId, 1); + } + } + static traceSend(stream, logger, traceLevels) { if(traceLevels.protocol >= 1) diff --git a/js/test/Common/ControllerI.js b/js/test/Common/ControllerI.js index f83b3fc7083..17433db22d6 100644 --- a/js/test/Common/ControllerI.js +++ b/js/test/Common/ControllerI.js @@ -33,17 +33,40 @@ function isWindows() return navigator.userAgent.indexOf("Windows") != -1; } +class Logger extends Ice.Logger +{ + constructor(out) + { + super() + this._out = out + } + + write(message, indent) + { + if(indent) + { + message = message.replace(/\n/g, "\n "); + } + this._out.writeLine(message); + } +} + class ProcessI extends Test.Common.Process { - constructor(promise, output) + constructor(promise, output, ready) { super(); this._promise = promise; this._output = output; + this._ready = ready; } waitReady(timeout, current) { + if(this._ready) + { + return this._ready; + } } waitSuccess(timeout, current) @@ -66,11 +89,11 @@ class ProcessI extends Test.Common.Process class ProcessControllerI extends Test.Common.ProcessController { - constructor(output, logger, useWorker, scripts) + constructor(clientOutput, serverOutput, useWorker, scripts) { super(); - this._output = output; - this._logger = logger; + this._clientOutput = clientOutput; + this._serverOutput = serverOutput; this._useWorker = useWorker; this._scripts = scripts; } @@ -78,9 +101,13 @@ class ProcessControllerI extends Test.Common.ProcessController start(testSuite, exe, args, current) { let promise; + let ready = null; + if(exe === "Server" || exe === "ServerAMD") + { + ready = new Ice.Promise(); + } if(this._useWorker) { - let out = this._output; let scripts = this._scripts; promise = new Promise((resolve, reject) => { let worker; @@ -96,11 +123,23 @@ class ProcessControllerI extends Test.Common.ProcessController worker.onmessage = function(e) { if(e.data.type == "write") { - out.write(e.data.message); + this._clientOutput.write(e.data.message); } else if(e.data.type == "writeLine") { - out.writeLine(e.data.message); + this._clientOutput.writeLine(e.data.message); + } + if(e.data.type == "serverWrite") + { + this._serverOutput.write(e.data.message); + } + else if(e.data.type == "serverWriteLine") + { + this._serverOutput.writeLine(e.data.message); + } + else if(e.data.type == "ready" && (exe === "Server" || exe === "ServerAMD")) + { + ready.resolve(); } else if(e.data.type == "finished") { @@ -121,19 +160,22 @@ class ProcessControllerI extends Test.Common.ProcessController else { let initData = new Ice.InitializationData(); - initData.logger = this._logger; initData.properties = Ice.createProperties(args); process.argv = args - if(exe === "ClientBidir") + if(exe === "Server" || exe === "ServerAMD") { - promise = _testBidir(this._output, initData); + initData.logger = new Logger(this._serverOutput); + let test = exe === "Server" ? _server : _serveramd; + promise = test(this._serverOutput, initData, ready); } else { - promise = _test(this._output, initData); + initData.logger = new Logger(this._clientOutput); + promise = _test(this._clientOutput, initData); } } - return Test.Common.ProcessPrx.uncheckedCast(current.adapter.addWithUUID(new ProcessI(promise, this._output))); + let out = exe === "Server" || exe === "ServerAMD" ? this._serverOutput : this._clientOutput; + return Test.Common.ProcessPrx.uncheckedCast(current.adapter.addWithUUID(new ProcessI(promise, out, ready))); } getHost(protocol, ipv6, current) @@ -142,25 +184,31 @@ class ProcessControllerI extends Test.Common.ProcessController } }; -function runController(output, scripts) +function runController(clientOutput, serverOutput, scripts) { - let out = + function wrapOutput(output) { - write: function(msg) - { - let text = output.val(); - output.val((text === "") ? msg : (text + msg)); - }, - writeLine: function(msg) - { - out.write(msg + "\n"); - output.scrollTop(output.get(0).scrollHeight); - }, - get: function() - { - return output.val() - } - }; + return { + write: function(msg) + { + let text = output.val(); + output.val((text === "") ? msg : (text + msg)); + }, + writeLine: function(msg) + { + msg = msg + "\n"; + let text = output.val(); + output.val((text === "") ? msg : (text + msg)); + output.scrollTop(output.get(0).scrollHeight); + }, + get: function() + { + return output.val() + } + }; + } + let out = wrapOutput(clientOutput); + let serverOut = wrapOutput(serverOutput); window.onerror = function(msg, url, line, column, err) { @@ -173,24 +221,6 @@ function runController(output, scripts) return false; }; - class Logger extends Ice.Logger - { - constructor(out) - { - super() - this._out = out - } - - write(message, indent) - { - if(indent) - { - message = message.replace(/\n/g, "\n "); - } - out.writeLine(message); - } - } - let uri = new URI(document.location.href) let initData = new Ice.InitializationData(); let protocol = uri.protocol() === "http" ? "ws" : "wss"; @@ -226,7 +256,7 @@ function runController(output, scripts) let registry = Test.Common.ProcessControllerRegistryPrx.uncheckedCast(comm.stringToProxy(str)); comm.createObjectAdapter("").then(adapter => { let ident = new Ice.Identity("ProcessController", "Browser"); - let processController = adapter.add(new ProcessControllerI(out, initData.logger, worker, scripts), ident); + let processController = adapter.add(new ProcessControllerI(out, serverOut, worker, scripts), ident); adapter.activate(); registerProcessController(adapter, registry, processController); }).catch(ex => { diff --git a/js/test/Common/ControllerWorker.js b/js/test/Common/ControllerWorker.js index e01c557fe83..a9fa6071cf3 100644 --- a/js/test/Common/ControllerWorker.js +++ b/js/test/Common/ControllerWorker.js @@ -13,7 +13,7 @@ */ var process = { argv : [] }; -let out = +let clientOut = { write: function(msg) { @@ -25,6 +25,18 @@ let out = } }; +let serverOut = +{ + write: function(msg) + { + self.postMessage({type:"serverWrite", message:msg}); + }, + writeLine: function(msg) + { + self.postMessage({type:"serverWriteLine", message:msg}); + } +}; + self.onmessage = function(e) { try @@ -54,16 +66,20 @@ self.onmessage = function(e) let promise let initData = new Ice.InitializationData(); - initData.logger = new Logger(out); initData.properties = Ice.createProperties(e.data.args); process.argv = e.data.args; - if(e.data.exe === "ClientBidir") + if(e.data.exe === "Server" || e.data.exe === "ServerAMD") { - promise = _testBidir(out, initData); + initData.logger = new Logger(serverOut); + let ready = new Ice.Promise(); + let test = e.data.exe === "Server" ? _server : _serveramd; + promise = test(serverOut, initData, ready); + ready.then(() => self.postMessage({type:"ready"})); } else { - promise = _test(out, initData); + initData.logger = new Logger(clientOut); + promise = _test(clientOut, initData); } promise.then(function() { self.postMessage({ type: "finished" }); diff --git a/js/test/Common/TestRunner.js b/js/test/Common/TestRunner.js index 9725c0e9352..8fa5f6d1978 100644 --- a/js/test/Common/TestRunner.js +++ b/js/test/Common/TestRunner.js @@ -10,7 +10,7 @@ /* global _test : false, - _testBidir : false, + _runServer : false, Test : false, */ @@ -108,7 +108,6 @@ function runTest(testsuite, language, host, protocol, testcases, out) var communicator; var id = new Ice.InitializationData(); var port = protocol == "ws" ? 15002 : 15003; - var serverTestCase; id.logger = Logger; id.properties = Ice.createProperties(); id.properties.setProperty("Ice.Default.Host", host); @@ -119,7 +118,7 @@ function runTest(testsuite, language, host, protocol, testcases, out) return Ice.Promise.try( function() { - if(typeof(_runServer) === "undefined" && typeof(_testBidir) === "undefined") + if(typeof(_runServer) === "undefined") { return _test(out, id); } @@ -140,17 +139,18 @@ function runTest(testsuite, language, host, protocol, testcases, out) } var runTestCase; - if(typeof(_testBidir) !== "undefined" && client == _testBidir) + out.writeLine("[ running " + testcase.name + " test]"); + if(language === "js") { - out.writeLine("[ running bidir " + testcase.name + " test]"); - runTestCase = function() { return controller.runTestCase("cpp", "Ice/echo", "server", language); }; + runTestCase = function() { return controller.runTestCase("cpp", "Ice/echo", "server", ""); }; } else { - out.writeLine("[ running " + testcase.name + " test]"); runTestCase = function() { return controller.runTestCase("js", testsuite, testcase.name, language) }; } out.write("starting server side... "); + var serverTestCase; + var server; return runTestCase().then( function(proxy) { @@ -164,17 +164,40 @@ function runTest(testsuite, language, host, protocol, testcases, out) function() { out.writeLine("ok") + process.argv = testcase.args; + if(language === "js") + { + var initData = id.clone(); + if(testcase.args !== undefined) + { + initData.properties = Ice.createProperties(testcase.args, id.properties); + } + ready = new Ice.Promise(); + server = _server(out, initData.clone(), ready) + return ready; + } + } + ).then( + function() + { var initData = id.clone(); if(testcase.args !== undefined) { initData.properties = Ice.createProperties(testcase.args, id.properties); - process.argv = testcase.args; } return client(out, initData); } ).then( function() { + if(server) + { + return server; // Wait for server to terminate + } + } + ).then( + function() + { return serverTestCase.stopServerSide(true); } ).catch( @@ -194,19 +217,9 @@ function runTest(testsuite, language, host, protocol, testcases, out) } var p = Ice.Promise.resolve(); - if(typeof(_runServer) !== "undefined") - { - testcases.forEach(function(testcase) { - p = p.then(function() { return run(testcase, _test); }) - }); - } - if(typeof(_testBidir) !== "undefined" && language === "cpp") - { - testcases.forEach(function(testcase) { - options = typeof(_runEchoServerOptions) !== "undefined" ? _runEchoServerOptions : [] - p = p.then(function() { return run(testcase, _testBidir); }) - }); - } + testcases.forEach(function(testcase) { + p = p.then(function() { return run(testcase, _test); }) + }); return p; } ).finally( diff --git a/js/test/Common/TestSuites.json b/js/test/Common/TestSuites.json index feefddd79f9..c69de6be963 100644 --- a/js/test/Common/TestSuites.json +++ b/js/test/Common/TestSuites.json @@ -31,7 +31,7 @@ }, "Ice/exceptions": { - "files": ["Test.js", "Client.js", "ThrowerI.js", "AMDThrowerI.js", "ClientBidir.js"], + "files": ["Test.js", "Client.js", "ThrowerI.js", "AMDThrowerI.js", "Server.js", "ServerAMD.js"], "testcases": [ { @@ -49,7 +49,7 @@ }, "Ice/facets": { - "files": ["Test.js", "Client.js", "TestI.js", "ClientBidir.js"] + "files": ["Test.js", "Client.js", "TestI.js", "Server.js"] }, "Ice/hold": { @@ -61,16 +61,16 @@ }, "Ice/inheritance": { - "files": ["Test.js", "Client.js", "InitialI.js", "ClientBidir.js"] + "files": ["Test.js", "Client.js", "InitialI.js", "Server.js"] }, "Ice/operations": { "files": ["Test.js", "Twoways.js", "Oneways.js", "BatchOneways.js", "Client.js", - "MyDerivedClassI.js", "AMDMyDerivedClassI.js", "ClientBidir.js"] + "MyDerivedClassI.js", "AMDMyDerivedClassI.js", "Server.js", "ServerAMD.js"] }, "Ice/objects": { - "files": ["Test.js", "Client.js"], + "files": ["Test.js", "Client.js", "InitialI.js", "Server.js"], "testcases": [ { @@ -88,7 +88,7 @@ }, "Ice/optional": { - "files": ["Test.js", "Client.js", "ClientPrivate.js", "InitialI.js", "AMDInitialI.js", "ClientBidir.js"], + "files": ["Test.js", "Client.js", "ClientPrivate.js", "InitialI.js", "AMDInitialI.js", "Server.js", "ServerAMD.js"], "testcases": [ { diff --git a/js/test/Common/controller.html b/js/test/Common/controller.html index 24c547c5d97..33f53873f28 100644 --- a/js/test/Common/controller.html +++ b/js/test/Common/controller.html @@ -13,8 +13,9 @@ <script> $(document).foundation(); $(document).ready(function() { - $("#console").height(300); - runController($("#console"), "{{{scripts}}}".split(",")); + $("#clientConsole").height(300); + $("#serverConsole").height(100); + runController($("#clientConsole"), $("#serverConsole"), "{{{scripts}}}".split(",")); }); </script> </head> @@ -31,7 +32,8 @@ <section role="main" id="body"> <div class="row"> <div class="large-12 medium-12 columns"> - <textarea id="console" class="disabled" height="300" readonly></textarea> + <textarea id="clientConsole" class="disabled" height="300" readonly></textarea> + <textarea id="serverConsole" class="disabled" height="100" readonly></textarea> </div> </div> </section> diff --git a/js/test/Common/run.js b/js/test/Common/run.js index f4fa106f176..105085ef5f2 100755 --- a/js/test/Common/run.js +++ b/js/test/Common/run.js @@ -25,19 +25,28 @@ var writeLine = function(msg) this.write(msg + "\n"); }; +var exception = function(ex) +{ + console.log(ex.toString()); + if(ex.stack) + { + console.log(ex.stack); + } + process.exit(1); +}; + var id = new Ice.InitializationData(); id.properties = Ice.createProperties(process.argv); exe = process.argv[2] var test = module.require(exe) -test = exe === "ClientBidir" ? test._testBidir : test._test; - -test({write: write, writeLine: writeLine}, id).catch( - ex => - { - console.log(ex.toString()); - if(ex.stack) - { - console.log(ex.stack); - } - process.exit(1); - }); +if(exe === "Server" || exe === "ServerAMD") +{ + var ready = new Ice.Promise(); + test = exe === "Server" ? test._server : test._serveramd; + test({write: write, writeLine: writeLine}, id, ready).catch(exception) + ready.then(() => console.log("server ready")); +} +else +{ + test._test({write: write, writeLine: writeLine}, id).catch(exception) +}
\ No newline at end of file diff --git a/js/test/Ice/exceptions/AMDThrowerI.js b/js/test/Ice/exceptions/AMDThrowerI.js index a19e0904d07..b7adcbe5000 100644 --- a/js/test/Ice/exceptions/AMDThrowerI.js +++ b/js/test/Ice/exceptions/AMDThrowerI.js @@ -11,7 +11,6 @@ { var Ice = require("ice").Ice; var Test = require("Test").Test; - var Class = Ice.Class; var test = function(b) { diff --git a/js/test/Ice/exceptions/Client.js b/js/test/Ice/exceptions/Client.js index a4841d61a0d..c613df0fa74 100644 --- a/js/test/Ice/exceptions/Client.js +++ b/js/test/Ice/exceptions/Client.js @@ -12,13 +12,13 @@ var Ice = require("ice").Ice; var Test = require("Test").Test; - var allTests = function(out, communicator, Test, bidir) + var allTests = function(out, communicator, Test) { class EmptyI extends Test.Empty { } - class ServantLocatorI + class ServantLocatorI { locate(curr, cookie) { @@ -355,25 +355,22 @@ ).then( function() { - if(!bidir) - { - out.write("testing memory limit marshal exception..."); - return thrower.throwMemoryLimitException(null).then( - failCB, - function(ex) - { - test(ex instanceof Ice.MemoryLimitException); - return thrower.throwMemoryLimitException(Ice.Buffer.createNative(20 * 1024)); - } - ).then( - failCB, - function(ex) - { - test(ex instanceof Ice.ConnectionLostException); - out.writeLine("ok"); - } - ); - } + out.write("testing memory limit marshal exception..."); + return thrower.throwMemoryLimitException(null).then( + failCB, + function(ex) + { + test(ex instanceof Ice.MemoryLimitException); + return thrower.throwMemoryLimitException(Ice.Buffer.createNative(20 * 1024)); + } + ).then( + failCB, + function(ex) + { + test(ex.toString().indexOf("ConnectionLostException") > 0); + out.writeLine("ok"); + } + ); } ).then( function() diff --git a/js/test/Ice/exceptions/Server.js b/js/test/Ice/exceptions/Server.js new file mode 100644 index 00000000000..ffb45677831 --- /dev/null +++ b/js/test/Ice/exceptions/Server.js @@ -0,0 +1,56 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2017 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +(function(module, require, exports) +{ + var Ice = require("ice").Ice; + var Test = require("Test").Test; + var ThrowerI = require("ThrowerI").ThrowerI; + + var run = function(out, id, ready) + { + id.properties.setProperty("Ice.MessageSizeMax", "10"); + id.properties.setProperty("Ice.Warn.Dispatch", "0"); + id.properties.setProperty("Ice.Warn.Connections", "0"); + var communicator = Ice.initialize(id); + var adapter; + var echo = Test.EchoPrx.uncheckedCast(communicator.stringToProxy("__echo:default -p 12010")); + return Ice.Promise.try(() => + { + return communicator.createObjectAdapter(""); + } + ).then(adpt => + { + adapter = adpt; + adapter.add(new ThrowerI(), Ice.stringToIdentity("thrower")); + return echo.setConnection(); + } + ).then(() => + { + var connection = echo.ice_getCachedConnection(); + connection.setCloseCallback((con) => { + // Re-establish connection if it fails (necessary for MemoryLimitException test) + echo.setConnection().then(() => echo.ice_getCachedConnection().setAdapter(adapter)) + }); + connection.setAdapter(adapter); + adapter.activate(); + ready.resolve(); + return communicator.waitForShutdown(); + } + ).then(() => + { + return echo.shutdown(); + } + ).finally(() => communicator.destroy()); + }; + exports._server = run; +} +(typeof(global) !== "undefined" && typeof(global.process) !== "undefined" ? module : undefined, + typeof(global) !== "undefined" && typeof(global.process) !== "undefined" ? require : this.Ice._require, + typeof(global) !== "undefined" && typeof(global.process) !== "undefined" ? exports : this)); diff --git a/js/test/Ice/exceptions/ServerAMD.js b/js/test/Ice/exceptions/ServerAMD.js new file mode 100644 index 00000000000..f6383f2ee3d --- /dev/null +++ b/js/test/Ice/exceptions/ServerAMD.js @@ -0,0 +1,57 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2017 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +(function(module, require, exports) +{ + var Ice = require("ice").Ice; + var Test = require("Test").Test; + var AMDThrowerI = require("AMDThrowerI").AMDThrowerI; + + var run = function(out, id, ready) + { + id.properties.setProperty("Ice.MessageSizeMax", "10"); + id.properties.setProperty("Ice.Warn.Dispatch", "0"); + id.properties.setProperty("Ice.Warn.Connections", "0"); + var communicator = Ice.initialize(id); + var adapter; + var echo = Test.EchoPrx.uncheckedCast(communicator.stringToProxy("__echo:default -p 12010")); + return Ice.Promise.try(() => + { + return communicator.createObjectAdapter(""); + } + ).then(adpt => + { + adapter = adpt; + adapter.add(new AMDThrowerI(), Ice.stringToIdentity("thrower")); + return echo.setConnection(); + } + ).then(() => + { + var connection = echo.ice_getCachedConnection(); + connection.setCloseCallback((con) => { + // Re-establish connection if it fails (necessary for MemoryLimitException test) + echo.setConnection().then(() => echo.ice_getCachedConnection().setAdapter(adapter)) + }); + connection.setAdapter(adapter); + echo.ice_getCachedConnection().setAdapter(adapter); + adapter.activate(); + ready.resolve(); + return communicator.waitForShutdown(); + } + ).then(() => + { + return echo.shutdown(); + } + ).finally(() => communicator.destroy()); + }; + exports._serveramd = run; +} +(typeof(global) !== "undefined" && typeof(global.process) !== "undefined" ? module : undefined, + typeof(global) !== "undefined" && typeof(global.process) !== "undefined" ? require : this.Ice._require, + typeof(global) !== "undefined" && typeof(global.process) !== "undefined" ? exports : this)); diff --git a/js/test/Ice/exceptions/Test.ice b/js/test/Ice/exceptions/Test.ice index be0c5f0253e..1b3c3a49425 100644 --- a/js/test/Ice/exceptions/Test.ice +++ b/js/test/Ice/exceptions/Test.ice @@ -75,6 +75,7 @@ interface WrongOperation interface Echo { + void setConnection(); void startBatch(); void flushBatch(); void shutdown(); diff --git a/js/test/Ice/exceptions/ThrowerI.js b/js/test/Ice/exceptions/ThrowerI.js index 7686ecb8a92..2725cf51c87 100644 --- a/js/test/Ice/exceptions/ThrowerI.js +++ b/js/test/Ice/exceptions/ThrowerI.js @@ -12,8 +12,6 @@ var Ice = require("ice").Ice; var Test = require("Test").Test; - var Class = Ice.Class; - var test = function(b) { if(!b) diff --git a/js/test/Ice/facets/ClientBidir.js b/js/test/Ice/facets/Server.js index c301dd5e39f..1c34aeac407 100644 --- a/js/test/Ice/facets/ClientBidir.js +++ b/js/test/Ice/facets/Server.js @@ -11,7 +11,6 @@ { var Ice = require("ice").Ice; var Test = require("Test").Test; - var Client = require("Client"); var TestI = require("TestI"); var DI = TestI.DI; @@ -19,26 +18,29 @@ var HI = TestI.HI; var EmptyI = TestI.EmptyI; - var allTests = function(out, communicator) + var test = function(b) { - var p = new Ice.Promise(); - var test = function(b) + if(!b) { - if(!b) + try { - try - { - throw new Error("test failed"); - } - catch(err) - { - p.reject(err); - throw err; - } + throw new Error("test failed"); } - }; + catch(err) + { + p.reject(err); + throw err; + } + } + }; + + var run = function(out, id, ready) + { + var communicator = Ice.initialize(id); + var adapter; + var echo = Test.EchoPrx.uncheckedCast(communicator.stringToProxy("__echo:default -p 12010")); - Ice.Promise.try( + return Ice.Promise.try( function() { out.write("testing facet registration exceptions... "); @@ -102,14 +104,13 @@ return adapter.deactivate(); } - ).then( - function(r) + ).then(() => { return communicator.createObjectAdapter(""); } - ).then( - function(adapter) + ).then(adpt => { + adapter = adpt; var di = new DI(); adapter.add(di, Ice.stringToIdentity("d")); adapter.addFacet(di, Ice.stringToIdentity("d"), "facetABCD"); @@ -117,53 +118,22 @@ adapter.addFacet(fi, Ice.stringToIdentity("d"), "facetEF"); var hi = new HI(); adapter.addFacet(hi, Ice.stringToIdentity("d"), "facetGH"); - - var prx = Ice.ObjectPrx.uncheckedCast(communicator.stringToProxy("d:default -p 12010")); - return prx.ice_getConnection().then( - function(conn) - { - conn.setAdapter(adapter); - return Client._clientAllTests(out, communicator); - }); + return echo.setConnection(); } - ).then(p.resolve, p.reject); - - return p; - }; - - var run = function(out, id) - { - var communicator = Ice.initialize(id); - return Ice.Promise.try( - function() - { - out.writeLine("testing bidir callbacks with synchronous dispatch..."); - return allTests(out, communicator); - } - ).then( - function() + ).then(() => { - return communicator.destroy(); + echo.ice_getCachedConnection().setAdapter(adapter); + adapter.activate(); + ready.resolve(); + return communicator.waitForShutdown(); } - ).then( - function() - { - communicator = Ice.initialize(id); - return Test.EchoPrx.checkedCast(communicator.stringToProxy("__echo:default -p 12010")); - } - ).then( - function(prx) - { - return prx.shutdown(); - } - ).finally( - function() + ).then(() => { - return communicator.destroy(); + return echo.shutdown(); } - ); + ).finally(() => communicator.destroy()); }; - exports._testBidir = run; + exports._server = run; } (typeof(global) !== "undefined" && typeof(global.process) !== "undefined" ? module : undefined, typeof(global) !== "undefined" && typeof(global.process) !== "undefined" ? require : this.Ice._require, diff --git a/js/test/Ice/facets/Test.ice b/js/test/Ice/facets/Test.ice index 3ac9c3429f4..319b12bced0 100644 --- a/js/test/Ice/facets/Test.ice +++ b/js/test/Ice/facets/Test.ice @@ -59,6 +59,7 @@ interface H extends G interface Echo { + void setConnection(); void startBatch(); void flushBatch(); void shutdown(); diff --git a/js/test/Ice/inheritance/ClientBidir.js b/js/test/Ice/inheritance/ClientBidir.js deleted file mode 100644 index 0c908cfd4f0..00000000000 --- a/js/test/Ice/inheritance/ClientBidir.js +++ /dev/null @@ -1,73 +0,0 @@ -// ********************************************************************** -// -// Copyright (c) 2003-2017 ZeroC, Inc. All rights reserved. -// -// This copy of Ice is licensed to you under the terms described in the -// ICE_LICENSE file included in this distribution. -// -// ********************************************************************** - -(function(module, require, exports) -{ - var Ice = require("ice").Ice; - var Test = require("Test").Test; - var InitialI = require("InitialI").InitialI; - var Client = require("Client"); - - var allTests = function(out, communicator) - { - return Ice.Promise.try( - function() - { - return communicator.createObjectAdapter("").then( - function(adapter) - { - var base = communicator.stringToProxy("initial:default -p 12010"); - adapter.add(new InitialI(adapter, base), Ice.stringToIdentity("initial")); - return base.ice_getConnection().then( - function(conn) - { - conn.setAdapter(adapter); - return Client._clientAllTests(out, communicator); - }); - }); - }); - }; - - var run = function(out, id) - { - var communicator = Ice.initialize(id); - return Ice.Promise.try( - function() - { - out.writeLine("testing bidir callbacks with synchronous dispatch..."); - return allTests(out, communicator); - } - ).then( - function() - { - return communicator.destroy(); - } - ).then( - function() - { - communicator = Ice.initialize(id); - return Test.EchoPrx.checkedCast(communicator.stringToProxy("__echo:default -p 12010")); - } - ).then( - function(prx) - { - return prx.shutdown(); - } - ).finally( - function() - { - return communicator.destroy(); - } - ); - }; - exports._testBidir = run; -} -(typeof(global) !== "undefined" && typeof(global.process) !== "undefined" ? module : undefined, - typeof(global) !== "undefined" && typeof(global.process) !== "undefined" ? require : this.Ice._require, - typeof(global) !== "undefined" && typeof(global.process) !== "undefined" ? exports : this)); diff --git a/js/test/Ice/inheritance/Server.js b/js/test/Ice/inheritance/Server.js new file mode 100644 index 00000000000..3b104cf02c0 --- /dev/null +++ b/js/test/Ice/inheritance/Server.js @@ -0,0 +1,49 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2017 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +(function(module, require, exports) +{ + var Ice = require("ice").Ice; + var Test = require("Test").Test; + var InitialI = require("InitialI").InitialI; + + var run = function(out, id, ready) + { + var communicator = Ice.initialize(id); + var adapter; + var echo = Test.EchoPrx.uncheckedCast(communicator.stringToProxy("__echo:default -p 12010")); + return Ice.Promise.try(() => + { + return communicator.createObjectAdapter(""); + } + ).then(adpt => + { + adapter = adpt; + var base = communicator.stringToProxy("initial:default -p 12010"); + adapter.add(new InitialI(adapter, base), Ice.stringToIdentity("initial")); + return echo.setConnection(); + } + ).then(() => + { + echo.ice_getCachedConnection().setAdapter(adapter); + adapter.activate(); + ready.resolve(); + return communicator.waitForShutdown(); + } + ).then(() => + { + return echo.shutdown(); + } + ).finally(() => communicator.destroy()); + }; + exports._server = run; +} +(typeof(global) !== "undefined" && typeof(global.process) !== "undefined" ? module : undefined, + typeof(global) !== "undefined" && typeof(global.process) !== "undefined" ? require : this.Ice._require, + typeof(global) !== "undefined" && typeof(global.process) !== "undefined" ? exports : this)); diff --git a/js/test/Ice/inheritance/Test.ice b/js/test/Ice/inheritance/Test.ice index fe15a5c29bb..b0924bb8cdd 100644 --- a/js/test/Ice/inheritance/Test.ice +++ b/js/test/Ice/inheritance/Test.ice @@ -235,6 +235,7 @@ class D extends C interface Echo { + void setConnection(); void startBatch(); void flushBatch(); void shutdown(); diff --git a/js/test/Ice/objects/Client.js b/js/test/Ice/objects/Client.js index 91413c1d1d7..175519b65cf 100644 --- a/js/test/Ice/objects/Client.js +++ b/js/test/Ice/objects/Client.js @@ -12,6 +12,19 @@ var Ice = require("ice").Ice; var Test = require("Test").Test; + function loop(fn, repetitions) { + var i = 0; + var next = function next() { + while (i++ < repetitions) { + var r = fn.call(null, i); + if (r) { + return r.then(next); + } + } + }; + return next(); + } + class BI extends Test.B { ice_preMarshal() @@ -377,8 +390,55 @@ var [retS, outS] = r; test(retS.length === 1 && outS.length === 1); out.writeLine("ok"); - out.write("testing compact ID... "); + out.write("testing recursive types... "); + + var top = new Test.Recursive(); + var p = top; + return loop(depth => { + p.v = new Test.Recursive(); + p = p.v; + if((depth < 10 && (depth % 10) == 0) || + (depth < 1000 && (depth % 100) == 0) || + (depth < 10000 && (depth % 1000) == 0) || + (depth % 10000) == 0) + { + return initial.setRecursive(top); + } + return null; + }, 20001); + } + ).then(() => + { + return initial.supportsClassGraphDepthMax().then(function(v) { test(!v); }); + }, + (ex) => + { + if(ex instanceof Ice.UnknownLocalException) + { + // Expected marshal exception from the server (max class graph depth reached) + } + else if(ex instanceof Ice.UnknownException) + { + // Expected stack overflow from the server (Java only) + } + else if(ex instanceof RangeError) + { + } + else + { + throw ex; + } + } + ).then(()=> + { + return initial.setRecursive(new Test.Recursive()); + } + ).then(()=> + { + out.writeLine("ok"); + + out.write("testing compact ID... "); return initial.getCompact(); } ).then(compact => @@ -413,9 +473,12 @@ }, ex => { - test(ex instanceof Ice.UnexpectedObjectException); - test(ex.type == "::Test::AlsoEmpty"); - test(ex.expectedType == "::Test::Empty"); + if(!(ex instanceof Ice.ObjectNotExistException)) + { + test(ex instanceof Ice.UnexpectedObjectException); + test(ex.type == "::Test::AlsoEmpty"); + test(ex.expectedType == "::Test::Empty"); + } } ).then(() => { @@ -466,6 +529,7 @@ return Ice.Promise.try(() => allTests(out, c)).finally(() => c.destroy()); }; exports._test = run; + exports._clientAllTests = allTests; exports._runServer = true; } (typeof(global) !== "undefined" && typeof(global.process) !== "undefined" ? module : undefined, diff --git a/js/test/Ice/objects/InitialI.js b/js/test/Ice/objects/InitialI.js new file mode 100644 index 00000000000..e8cd5c4a3db --- /dev/null +++ b/js/test/Ice/objects/InitialI.js @@ -0,0 +1,319 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2017 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICEthis._LICENSE file included in this distribution. +// +// ********************************************************************** + +(function(module, require, exports) +{ + var Ice = require("ice").Ice; + var Test = require("Test").Test; + + var test = function(b) + { + if(!b) + { + throw new Error("test failed"); + } + }; + + class BI extends Test.B + { + ice_preMarshal() + { + this.preMarshalInvoked = true; + } + + ice_postUnmarshal() + { + this.postUnmarshalInvoked = true; + } + }; + + class CI extends Test.C + { + ice_preMarshal() + { + this.preMarshalInvoked = true; + } + + ice_postUnmarshal() + { + this.postUnmarshalInvoked = true; + } + }; + + class DI extends Test.D + { + ice_preMarshal() + { + this.preMarshalInvoked = true; + } + + ice_postUnmarshal() + { + this.postUnmarshalInvoked = true; + } + }; + + class EI extends Test.E + { + constructor() + { + super(1, "hello"); + } + + checkValues() + { + return this.i == 1 && this.s == "hello"; + } + }; + + class FI extends Test.F + { + constructor(e) + { + super(e, e); + } + + checkValues() + { + return this.e1 !== null && this.e1 === this.e2; + } + }; + + class HI extends Test.H + { + }; + + class II extends Ice.InterfaceByValue + { + constructor() + { + super(Test.I.ice_staticId()); + } + }; + + class JI extends Ice.InterfaceByValue + { + constructor() + { + super(Test.J.ice_staticId()); + } + }; + + function MyValueFactory(type) + { + switch(type) + { + case "::Test::B": + return new BI(); + case "::Test::C": + return new CI(); + case "::Test::D": + return new DI(); + case "::Test::E": + return new EI(); + case "::Test::F": + return new FI(); + case "::Test::I": + return new II(); + case "::Test::J": + return new JI(); + case "::Test::H": + return new HI(); + case "::Test::Inner::A": + return new Test.Inner.A(); + case "::Test::Inner::Sub::A": + return new Test.Inner.Sub.A(); + default: + break; + } + return null; + } + + class InitialI extends Test.Initial + { + constructor(communicator) + { + super(); + if(communicator !== undefined) + { + communicator.getValueFactoryManager().add(MyValueFactory, "::Test::B"); + communicator.getValueFactoryManager().add(MyValueFactory, "::Test::C"); + communicator.getValueFactoryManager().add(MyValueFactory, "::Test::D"); + communicator.getValueFactoryManager().add(MyValueFactory, "::Test::E"); + communicator.getValueFactoryManager().add(MyValueFactory, "::Test::F"); + communicator.getValueFactoryManager().add(MyValueFactory, "::Test::I"); + communicator.getValueFactoryManager().add(MyValueFactory, "::Test::J"); + communicator.getValueFactoryManager().add(MyValueFactory, "::Test::H"); + communicator.getValueFactoryManager().add(MyValueFactory, "::Test::Inner::A"); + communicator.getValueFactoryManager().add(MyValueFactory, "::Test::Inner::Sub::A"); + } + + this._b1 = new BI(); + this._b2 = new BI(); + this._c = new CI(); + this._d = new DI(); + this._e = new EI(); + this._f = new FI(this._e, this._e); + + this._b1.theA = this._b2; // Cyclic reference to another B + this._b1.theB = this._b1; // Self reference. + this._b1.theC = null; // Null reference. + + this._b2.theA = this._b2; // Self reference, using base. + this._b2.theB = this._b1; // Cyclic reference to another B + this._b2.theC = this._c; // Cyclic reference to a C. + + this._c.theB = this._b2; // Cyclic reference to a B. + + this._d.theA = this._b1; // Reference to a B. + this._d.theB = this._b2; // Reference to a B. + this._d.theC = null; // Reference to a C. + } + + getAll(current) + { + this._b1.preMarshalInvoked = false; + this._b2.preMarshalInvoked = false; + this._c.preMarshalInvoked = false; + this._d.preMarshalInvoked = false; + return [this._b1, this._b2, this._c, this._d] + } + + getB1(current) + { + this._b1.preMarshalInvoked = false; + this._b2.preMarshalInvoked = false; + this._c.preMarshalInvoked = false; + return this._b1; + } + + getB2(current) + { + this._b1.preMarshalInvoked = false; + this._b2.preMarshalInvoked = false; + this._c.preMarshalInvoked = false; + return this._b2; + } + + getC(current) + { + this._b1.preMarshalInvoked = false; + this._b2.preMarshalInvoked = false; + this._c.preMarshalInvoked = false; + return this._c; + } + + getD(current) + { + this._b1.preMarshalInvoked = false; + this._b2.preMarshalInvoked = false; + this._c.preMarshalInvoked = false; + this._d.preMarshalInvoked = false; + return this._d; + } + + getE(current) + { + return this._e; + } + + getF(current) + { + return this._f; + } + + setRecursive(r, current) + { + } + + supportsClassGraphDepthMax(current) + { + return false; + } + + getMB(current) + { + return this._b1; + } + + getAMDMB(current) + { + return Ice.Promise.resolve(this._b1); + } + + getI(current) + { + return new II(); + } + + getJ(current) + { + return new JI(); + } + + getH(current) + { + return new HI(); + } + + getD1(d1, current) + { + return d1; + } + + throwEDerived(current) + { + throw new Test.EDerived(new Test.A1("a1"), new Test.A1("a2"), new Test.A1("a3"), new Test.A1("a4")); + } + + setI(theI, current) + { + } + + opBaseSeq(inS, current) + { + return [inS, inS]; + } + + getCompact(current) + { + return new Test.CompactExt(); + } + + getInnerA(current) + { + return new Test.Inner.A(this._b1); + } + + getInnerSubA(current) + { + return new Test.Inner.Sub.A(new Test.Inner.A(this._b1)); + } + + throwInnerEx(current) + { + throw new Test.Inner.Ex("Inner::Ex"); + } + + throwInnerSubEx(current) + { + throw new Test.Inner.Sub.Ex("Inner::Sub::Ex"); + } + + shutdown(current) + { + current.adapter.getCommunicator().shutdown(); + } + } + + exports.InitialI = InitialI; +} +(typeof(global) !== "undefined" && typeof(global.process) !== "undefined" ? module : undefined, + typeof(global) !== "undefined" && typeof(global.process) !== "undefined" ? require : this.Ice._require, + typeof(global) !== "undefined" && typeof(global.process) !== "undefined" ? exports : this)); diff --git a/js/test/Ice/objects/Server.js b/js/test/Ice/objects/Server.js new file mode 100644 index 00000000000..b15a4cde8fc --- /dev/null +++ b/js/test/Ice/objects/Server.js @@ -0,0 +1,58 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2017 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +(function(module, require, exports) +{ + var Ice = require("ice").Ice; + var Test = require("Test").Test; + var InitialI = require("InitialI").InitialI; + + class UnexpectedObjectExceptionTestI extends Test.UnexpectedObjectExceptionTest + { + op(current) + { + return new Test.AlsoEmpty(); + } + }; + + var run = function(out, id, ready) + { + id.properties.setProperty("Ice.Warn.Dispatch", "0"); + var communicator = Ice.initialize(id); + var adapter; + var echo = Test.EchoPrx.uncheckedCast(communicator.stringToProxy("__echo:default -p 12010")); + return Ice.Promise.try(() => + { + return communicator.createObjectAdapter(""); + } + ).then(adpt => + { + adapter = adpt; + adapter.add(new InitialI(communicator), Ice.stringToIdentity("initial")); + adapter.add(new UnexpectedObjectExceptionTestI(), Ice.stringToIdentity("uoet")); + return echo.setConnection(); + } + ).then(() => + { + echo.ice_getCachedConnection().setAdapter(adapter); + adapter.activate(); + ready.resolve(); + return communicator.waitForShutdown(); + } + ).then(() => + { + return echo.shutdown(); + } + ).finally(() => communicator.destroy()); + }; + exports._server = run; +} +(typeof(global) !== "undefined" && typeof(global.process) !== "undefined" ? module : undefined, + typeof(global) !== "undefined" && typeof(global.process) !== "undefined" ? require : this.Ice._require, + typeof(global) !== "undefined" && typeof(global.process) !== "undefined" ? exports : this)); diff --git a/js/test/Ice/objects/Test.ice b/js/test/Ice/objects/Test.ice index b49ecf6f887..3bc810f5848 100644 --- a/js/test/Ice/objects/Test.ice +++ b/js/test/Ice/objects/Test.ice @@ -167,7 +167,12 @@ exception Ex }; -class Initial +class Recursive +{ + Recursive v; +}; + +interface Initial { void shutdown(); B getB1(); @@ -177,6 +182,9 @@ class Initial E getE(); F getF(); + void setRecursive(Recursive p); + bool supportsClassGraphDepthMax(); + ["marshaled-result"] B getMB(); ["amd", "marshaled-result"] B getAMDMB(); @@ -255,4 +263,10 @@ struct STwoMembers dictionary<int, COneMember> DOneMember; dictionary<int, CTwoMembers> DTwoMembers; +interface Echo +{ + void setConnection(); + void shutdown(); +}; + }; diff --git a/js/test/Ice/operations/AMDMyDerivedClassI.js b/js/test/Ice/operations/AMDMyDerivedClassI.js index 54f969cfc61..e62488edd95 100644 --- a/js/test/Ice/operations/AMDMyDerivedClassI.js +++ b/js/test/Ice/operations/AMDMyDerivedClassI.js @@ -25,10 +25,11 @@ // // Override the Object "pseudo" operations to verify the operation mode. // - constructor() + constructor(endpoints) { super(); this._opByteSOnewayCount = 0; + this._endpoints = endpoints; } ice_isA(id, current) @@ -154,7 +155,7 @@ var p3 = Test.MyClassPrx.uncheckedCast( current.adapter.createProxy(Ice.stringToIdentity("noSuchIdentity"))); var r = Test.MyClassPrx.uncheckedCast(current.adapter.createProxy(current.id)); - return Promise.resolve([r, p2, p3]); + return Promise.resolve([r.ice_endpoints(this._endpoints), p2, p3.ice_endpoints(this._endpoints)]); } opMyEnum(p1, current) @@ -490,6 +491,11 @@ Test.su0, Test.su1, Test.su2]); } + opWStringLiterals(current) + { + return this.opStringLiterals(current); + } + opMStruct1(current) { return Promise.resolve(new Test.Structure()); diff --git a/js/test/Ice/operations/ClientBidir.js b/js/test/Ice/operations/ClientBidir.js deleted file mode 100644 index 5aaa3775a37..00000000000 --- a/js/test/Ice/operations/ClientBidir.js +++ /dev/null @@ -1,68 +0,0 @@ -// ********************************************************************** -// -// Copyright (c) 2003-2017 ZeroC, Inc. All rights reserved. -// -// This copy of Ice is licensed to you under the terms described in the -// ICE_LICENSE file included in this distribution. -// -// ********************************************************************** - -(function(module, require, exports) -{ - var Ice = require("ice").Ice; - var Test = require("Test").Test; - var MyDerivedClassI = require("MyDerivedClassI").MyDerivedClassI; - var AMDMyDerivedClassI = require("AMDMyDerivedClassI").AMDMyDerivedClassI; - var Client = require("Client.js"); - - var allTests = function(out, communicator, amd) - { - return communicator.createObjectAdapter("").then(adapter => - { - if(amd) - { - adapter.add(new AMDMyDerivedClassI(), Ice.stringToIdentity("test")); - } - else - { - adapter.add(new MyDerivedClassI(), Ice.stringToIdentity("test")); - } - var base = communicator.stringToProxy("test:default -p 12010"); - return base.ice_getConnection().then(conn => - { - conn.setAdapter(adapter); - return Client._clientAllTests(out, communicator, Test, true); - }); - }); - }; - - var run = function(out, id) - { - id.properties.setProperty("Ice.BatchAutoFlushSize", "100"); - var communicator = Ice.initialize(id); - return Ice.Promise.try(() => - { - out.writeLine("testing bidir callbacks with synchronous dispatch..."); - return allTests(out, communicator, false); - } - ).then(() => communicator.destroy() - ).then(() => - { - communicator = Ice.initialize(id); - out.writeLine("testing bidir callbacks with asynchronous dispatch..."); - return allTests(out, communicator, true); - } - ).then(() => communicator.destroy() - ).then(() => - { - communicator = Ice.initialize(id); - return Test.EchoPrx.checkedCast(communicator.stringToProxy("__echo:default -p 12010")); - } - ).then(prx => prx.shutdown() - ).finally(() => communicator.destroy()); - }; - exports._testBidir = run; -} -(typeof(global) !== "undefined" && typeof(global.process) !== "undefined" ? module : undefined, - typeof(global) !== "undefined" && typeof(global.process) !== "undefined" ? require : this.Ice._require, - typeof(global) !== "undefined" && typeof(global.process) !== "undefined" ? exports : this)); diff --git a/js/test/Ice/operations/MyDerivedClassI.js b/js/test/Ice/operations/MyDerivedClassI.js index dcb945ef8cb..f550f28f574 100644 --- a/js/test/Ice/operations/MyDerivedClassI.js +++ b/js/test/Ice/operations/MyDerivedClassI.js @@ -25,10 +25,11 @@ // // Override the Object "pseudo" operations to verify the operation mode. // - constructor() + constructor(endpoints) { super(); this._opByteSOnewayCount = 0; + this._endpoints = endpoints; } ice_isA(id, current) @@ -152,7 +153,7 @@ var p3 = Test.MyClassPrx.uncheckedCast( current.adapter.createProxy(Ice.stringToIdentity("noSuchIdentity"))); var r = Test.MyClassPrx.uncheckedCast(current.adapter.createProxy(current.id)); - return [r, p2, p3]; + return [r.ice_endpoints(this._endpoints), p2, p3.ice_endpoints(this._endpoints)]; } opMyEnum(p1, current) @@ -483,6 +484,11 @@ Test.su0, Test.su1, Test.su2]; } + opWStringLiterals(current) + { + return this.opStringLiterals(current); + } + opMStruct1(current) { return new Test.Structure(); diff --git a/js/test/Ice/operations/Server.js b/js/test/Ice/operations/Server.js new file mode 100644 index 00000000000..e1d21e10495 --- /dev/null +++ b/js/test/Ice/operations/Server.js @@ -0,0 +1,49 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2017 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +(function(module, require, exports) +{ + var Ice = require("ice").Ice; + var Test = require("Test").Test; + var MyDerivedClassI = require("MyDerivedClassI").MyDerivedClassI; + + var run = function(out, id, ready) + { + id.properties.setProperty("Ice.BatchAutoFlushSize", "100"); + var communicator = Ice.initialize(id); + var adapter; + var echo = Test.EchoPrx.uncheckedCast(communicator.stringToProxy("__echo:default -p 12010")); + return Ice.Promise.try(() => + { + return communicator.createObjectAdapter(""); + } + ).then(adpt => + { + adapter = adpt; + adapter.add(new MyDerivedClassI(echo.ice_getEndpoints()), Ice.stringToIdentity("test")); + return echo.setConnection(); + } + ).then(() => + { + echo.ice_getCachedConnection().setAdapter(adapter); + adapter.activate(); + ready.resolve(); + return communicator.waitForShutdown(); + } + ).then(() => + { + return echo.shutdown(); + } + ).finally(() => communicator.destroy()); + }; + exports._server = run; +} +(typeof(global) !== "undefined" && typeof(global.process) !== "undefined" ? module : undefined, + typeof(global) !== "undefined" && typeof(global.process) !== "undefined" ? require : this.Ice._require, + typeof(global) !== "undefined" && typeof(global.process) !== "undefined" ? exports : this)); diff --git a/js/test/Ice/operations/ServerAMD.js b/js/test/Ice/operations/ServerAMD.js new file mode 100644 index 00000000000..60b87b2f8de --- /dev/null +++ b/js/test/Ice/operations/ServerAMD.js @@ -0,0 +1,49 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2017 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +(function(module, require, exports) +{ + var Ice = require("ice").Ice; + var Test = require("Test").Test; + var AMDMyDerivedClassI = require("AMDMyDerivedClassI").AMDMyDerivedClassI; + + var run = function(out, id, ready) + { + id.properties.setProperty("Ice.BatchAutoFlushSize", "100"); + var communicator = Ice.initialize(id); + var adapter; + var echo = Test.EchoPrx.uncheckedCast(communicator.stringToProxy("__echo:default -p 12010")); + return Ice.Promise.try(() => + { + return communicator.createObjectAdapter(""); + } + ).then(adpt => + { + adapter = adpt; + adapter.add(new AMDMyDerivedClassI(echo.ice_getEndpoints()), Ice.stringToIdentity("test")); + return echo.setConnection(); + } + ).then(() => + { + echo.ice_getCachedConnection().setAdapter(adapter); + adapter.activate(); + ready.resolve(); + return communicator.waitForShutdown(); + } + ).then(() => + { + return echo.shutdown(); + } + ).finally(() => communicator.destroy()); + }; + exports._serveramd = run; +} +(typeof(global) !== "undefined" && typeof(global.process) !== "undefined" ? module : undefined, + typeof(global) !== "undefined" && typeof(global.process) !== "undefined" ? require : this.Ice._require, + typeof(global) !== "undefined" && typeof(global.process) !== "undefined" ? exports : this)); diff --git a/js/test/Ice/operations/Test.ice b/js/test/Ice/operations/Test.ice index 7899646dcfd..c9056b5c581 100644 --- a/js/test/Ice/operations/Test.ice +++ b/js/test/Ice/operations/Test.ice @@ -43,6 +43,7 @@ sequence<long> LongS; sequence<float> FloatS; sequence<double> DoubleS; sequence<string> StringS; +sequence<["cpp:type:wstring"]string> WStringS; sequence<MyEnum> MyEnumS; sequence<MyClass*> MyClassS; @@ -248,6 +249,7 @@ interface MyClass ByteBoolD opByteBoolD2(ByteBoolD byteBoolD); StringS opStringLiterals(); + WStringS opWStringLiterals(); ["marshaled-result"] Structure opMStruct1(); ["marshaled-result"] Structure opMStruct2(Structure p1, out Structure p2); @@ -282,6 +284,7 @@ interface MyDerivedClass extends MyClass interface Echo { + void setConnection(); void startBatch(); void flushBatch(); void shutdown(); diff --git a/js/test/Ice/optional/AMDInitialI.js b/js/test/Ice/optional/AMDInitialI.js index 9a5706f10ca..7b90fa13697 100644 --- a/js/test/Ice/optional/AMDInitialI.js +++ b/js/test/Ice/optional/AMDInitialI.js @@ -337,6 +337,11 @@ return Promise.resolve(false); } + supportsCppStringView(current) + { + return false; + } + supportsCsharpSerializable(current) { return Promise.resolve(false); diff --git a/js/test/Ice/optional/Client.js b/js/test/Ice/optional/Client.js index dd45a676ed6..0847fb98194 100644 --- a/js/test/Ice/optional/Client.js +++ b/js/test/Ice/optional/Client.js @@ -319,6 +319,15 @@ } ).then(() => { + var recursive1 = [new Test.Recursive()]; + var recursive2 = [new Test.Recursive()]; + recursive1[0].value = recursive2; + var outer = new Test.Recursive(); + outer.value = recursive1; + initial.pingPong(outer); + } + ).then(() => + { var g = new Test.G(); g.gg1Opt = new Test.G1("gg1Opt"); g.gg2 = new Test.G2(new Ice.Long(0, 10)); diff --git a/js/test/Ice/optional/ClientBidir.js b/js/test/Ice/optional/ClientBidir.js deleted file mode 100644 index d61abfeb8af..00000000000 --- a/js/test/Ice/optional/ClientBidir.js +++ /dev/null @@ -1,82 +0,0 @@ -// ********************************************************************** -// -// Copyright (c) 2003-2017 ZeroC, Inc. All rights reserved. -// -// This copy of Ice is licensed to you under the terms described in the -// ICE_LICENSE file included in this distribution. -// -// ********************************************************************** - -(function(module, require, exports) -{ - var Ice = require("ice").Ice; - var Test = require("Test").Test; - var InitialI = require("InitialI").InitialI; - var AMDInitialI = require("AMDInitialI").AMDInitialI; - var Client = require("Client"); - - var ArrayUtil = Ice.ArrayUtil; - - var allTests = function(out, communicator, amd) - { - var base; - return Ice.Promise.try(() => - { - base = communicator.stringToProxy("initial:default -p 12010"); - return communicator.createObjectAdapter(""); - } - ).then(adapter => - { - if(amd) - { - adapter.add(new AMDInitialI(), Ice.stringToIdentity("initial")); - } - else - { - adapter.add(new InitialI(), Ice.stringToIdentity("initial")); - } - return base.ice_getConnection().then(conn => - { - conn.setAdapter(adapter); - return Client._clientAllTests(out, communicator, Test); - }); - }); - }; - - var run = function(out, id) - { - var communicator = null; - return Ice.Promise.try(() => - { - communicator = Ice.initialize(id); - out.writeLine("testing bidir callbacks with synchronous dispatch..."); - return allTests(out, communicator, false); - } - ).then(() => communicator.destroy() - ).then(() => - { - communicator = Ice.initialize(id); - out.writeLine("testing bidir callbacks with asynchronous dispatch..."); - return allTests(out, communicator, true); - } - ).then(() => communicator.destroy() - ).then(() => - { - communicator = Ice.initialize(id); - var base = communicator.stringToProxy("__echo:default -p 12010"); - return Test.EchoPrx.checkedCast(base); - } - ).then(prx => prx.shutdown() - ).finally(() => - { - if(communicator) - { - return communicator.destroy(); - } - }); - }; - exports._testBidir = run; -} -(typeof(global) !== "undefined" && typeof(global.process) !== "undefined" ? module : undefined, - typeof(global) !== "undefined" && typeof(global.process) !== "undefined" ? require : this.Ice._require, - typeof(global) !== "undefined" && typeof(global.process) !== "undefined" ? exports : this)); diff --git a/js/test/Ice/optional/ClientPrivate.ice b/js/test/Ice/optional/ClientPrivate.ice index ddb03cd4aa5..ea6072ee803 100644 --- a/js/test/Ice/optional/ClientPrivate.ice +++ b/js/test/Ice/optional/ClientPrivate.ice @@ -17,12 +17,16 @@ module Test // // The server doesn't know this class. // -class D extends B -{ - string ds; - optional(990) StringSeq seq; - optional(1000) A ao; -}; +// We don't define it in JavaScript to allow the cross tests to work when running +// only the JavaScript server within the browser (which loads ClientPrivate.js for +// the server as well) +// +// class D extends B +// { +// string ds; +// optional(990) StringSeq seq; +// optional(1000) A ao; +// }; // // This class is a hack that allows us to invoke the opClassAndUnknownOptional operation diff --git a/js/test/Ice/optional/InitialI.js b/js/test/Ice/optional/InitialI.js index ec7e7f6b99e..efc5ff788b7 100644 --- a/js/test/Ice/optional/InitialI.js +++ b/js/test/Ice/optional/InitialI.js @@ -333,6 +333,11 @@ return false; } + supportsCppStringView(current) + { + return false; + } + supportsCsharpSerializable(current) { return false; diff --git a/js/test/Ice/optional/Server.js b/js/test/Ice/optional/Server.js new file mode 100644 index 00000000000..2442eaa3f09 --- /dev/null +++ b/js/test/Ice/optional/Server.js @@ -0,0 +1,48 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2017 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +(function(module, require, exports) +{ + var Ice = require("ice").Ice; + var Test = require("Test").Test; + var InitialI = require("InitialI").InitialI; + + var run = function(out, id, ready) + { + var communicator = Ice.initialize(id); + var adapter; + var echo = Test.EchoPrx.uncheckedCast(communicator.stringToProxy("__echo:default -p 12010")); + return Ice.Promise.try(() => + { + return communicator.createObjectAdapter(""); + } + ).then(adpt => + { + adapter = adpt; + adapter.add(new InitialI(), Ice.stringToIdentity("initial")); + return echo.setConnection(); + } + ).then(() => + { + echo.ice_getCachedConnection().setAdapter(adapter); + adapter.activate(); + ready.resolve(); + return communicator.waitForShutdown(); + } + ).then(() => + { + return echo.shutdown(); + } + ).finally(() => communicator.destroy()); + }; + exports._server = run; +} +(typeof(global) !== "undefined" && typeof(global.process) !== "undefined" ? module : undefined, + typeof(global) !== "undefined" && typeof(global.process) !== "undefined" ? require : this.Ice._require, + typeof(global) !== "undefined" && typeof(global.process) !== "undefined" ? exports : this)); diff --git a/js/test/Ice/optional/ServerAMD.js b/js/test/Ice/optional/ServerAMD.js new file mode 100644 index 00000000000..86779fd2d76 --- /dev/null +++ b/js/test/Ice/optional/ServerAMD.js @@ -0,0 +1,49 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2017 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +(function(module, require, exports) +{ + var Ice = require("ice").Ice; + var Test = require("Test").Test; + var AMDInitialI = require("AMDInitialI").AMDInitialI; + + + var run = function(out, id, ready) + { + var communicator = Ice.initialize(id); + var adapter; + var echo = Test.EchoPrx.uncheckedCast(communicator.stringToProxy("__echo:default -p 12010")); + return Ice.Promise.try(() => + { + return communicator.createObjectAdapter(""); + } + ).then(adpt => + { + adapter = adpt; + adapter.add(new AMDInitialI(), Ice.stringToIdentity("initial")); + return echo.setConnection(); + } + ).then(() => + { + echo.ice_getCachedConnection().setAdapter(adapter); + adapter.activate(); + ready.resolve(); + return communicator.waitForShutdown(); + } + ).then(() => + { + return echo.shutdown(); + } + ).finally(() => communicator.destroy()); + }; + exports._serveramd = run; +} +(typeof(global) !== "undefined" && typeof(global.process) !== "undefined" ? module : undefined, + typeof(global) !== "undefined" && typeof(global.process) !== "undefined" ? require : this.Ice._require, + typeof(global) !== "undefined" && typeof(global.process) !== "undefined" ? exports : this)); diff --git a/js/test/Ice/optional/Test.ice b/js/test/Ice/optional/Test.ice index 70262e8cd6f..4c206934991 100644 --- a/js/test/Ice/optional/Test.ice +++ b/js/test/Ice/optional/Test.ice @@ -189,6 +189,14 @@ class G G1 gg1; }; +class Recursive; +sequence<Recursive> RecursiveSeq; + +class Recursive +{ + optional(0) RecursiveSeq value; +}; + interface Initial { void shutdown(); @@ -298,11 +306,14 @@ interface Initial bool supportsCsharpSerializable(); + bool supportsCppStringView(); + bool supportsNullOptional(); }; interface Echo { + void setConnection(); void startBatch(); void flushBatch(); void shutdown(); diff --git a/objective-c/test/Ice/exceptions/AllTests.m b/objective-c/test/Ice/exceptions/AllTests.m index 1ca917c2439..c65792c71e3 100644 --- a/objective-c/test/Ice/exceptions/AllTests.m +++ b/objective-c/test/Ice/exceptions/AllTests.m @@ -376,31 +376,39 @@ exceptionsAllTests(id<ICECommunicator> communicator) @catch(ICEConnectionLostException *ex) { } + @catch(ICEUnknownLocalException *ex) + { + } @catch(NSException *ex) { test(false); } - id<TestExceptionsThrowerPrx> thrower2 = - [TestExceptionsThrowerPrx checkedCast:[communicator stringToProxy:@"thrower:default -p 12011"]]; - @try - { - [thrower2 throwMemoryLimitException:[NSMutableData dataWithLength:20 * 1024 * 1024]]; // 2MB (no limits) - } - @catch(ICEMemoryLimitException *ex) - { - } - id<TestExceptionsThrowerPrx> thrower3 = - [TestExceptionsThrowerPrx checkedCast:[communicator stringToProxy:@"thrower:default -p 12012"]]; @try { - [thrower3 throwMemoryLimitException:[NSMutableData dataWithLength:1024]]; // 1KB limit - test(NO); + id<TestExceptionsThrowerPrx> thrower2 = + [TestExceptionsThrowerPrx checkedCast:[communicator stringToProxy:@"thrower:default -p 12011"]]; + @try + { + [thrower2 throwMemoryLimitException:[NSMutableData dataWithLength:20 * 1024 * 1024]]; // 2MB (no limits) + } + @catch(ICEMemoryLimitException *ex) + { + } + id<TestExceptionsThrowerPrx> thrower3 = + [TestExceptionsThrowerPrx checkedCast:[communicator stringToProxy:@"thrower:default -p 12012"]]; + @try + { + [thrower3 throwMemoryLimitException:[NSMutableData dataWithLength:1024]]; // 1KB limit + test(NO); + } + @catch(ICEConnectionLostException *ex) + { + } } - @catch(ICEConnectionLostException *ex) + @catch(ICEConnectionRefusedException* ex) { } - tprintf("ok\n"); } diff --git a/objective-c/test/Ice/objects/AllTests.m b/objective-c/test/Ice/objects/AllTests.m index ae7ded112a1..cea5cc6e22a 100644 --- a/objective-c/test/Ice/objects/AllTests.m +++ b/objective-c/test/Ice/objects/AllTests.m @@ -242,6 +242,38 @@ objectsAllTests(id<ICECommunicator> communicator, BOOL collocated) [initial setI:h]; tprintf("ok\n"); + tprintf("testing recursive type... "); + TestObjectsRecursive* top = [TestObjectsRecursive recursive]; + TestObjectsRecursive* p = top; + int depth = 0; + @try + { + for(; depth <= 20000; ++depth) + { + p.v = [TestObjectsRecursive recursive]; + p = p.v; + if((depth < 10 && (depth % 10) == 0) || + (depth < 1000 && (depth % 100) == 0) || + (depth < 10000 && (depth % 1000) == 0) || + (depth % 10000) == 0) + { + [initial setRecursive:top]; + } + } + test(![initial supportsClassGraphDepthMax]); + } + @catch(ICEUnknownLocalException*) + { + // Expected marshal exception from the server (max class graph depth reached) + test(depth == 100); // The default is 100. + } + @catch(ICEUnknownException*) + { + // Expected stack overflow from the server (Java only) + } + [initial setRecursive:[TestObjectsRecursive recursive]]; + tprintf("ok\n"); + tprintf("testing sequences... "); TestObjectsMutableBaseSeq* inS = [TestObjectsMutableBaseSeq array]; TestObjectsMutableBaseSeq* outS; diff --git a/objective-c/test/Ice/objects/Collocated.m b/objective-c/test/Ice/objects/Collocated.m index 11c816f415f..855cf3bbd4a 100644 --- a/objective-c/test/Ice/objects/Collocated.m +++ b/objective-c/test/Ice/objects/Collocated.m @@ -133,6 +133,7 @@ main(int argc, char* argv[]) { ICEInitializationData* initData = [ICEInitializationData initializationData]; initData.properties = defaultServerProperties(&argc, argv); + [initData.properties setProperty:@"Ice.Warn.Dispatch" value:@"0"]; #if TARGET_OS_IPHONE initData.prefixTable_ = [NSDictionary dictionaryWithObjectsAndKeys: @"TestObjects", @"::Test", diff --git a/objective-c/test/Ice/objects/ObjectsTest.ice b/objective-c/test/Ice/objects/ObjectsTest.ice index dc903444902..4feb80d45e4 100644 --- a/objective-c/test/Ice/objects/ObjectsTest.ice +++ b/objective-c/test/Ice/objects/ObjectsTest.ice @@ -178,6 +178,11 @@ dictionary<string, Object*> ObjectPrxDict; // For Objective-C only dictionary<string, Base> BaseDict; // For Objective-C only dictionary<string, Base*> BasePrxDict; // For Objective-C only +class Recursive +{ + Recursive v; +}; + class Initial { void shutdown(); @@ -188,6 +193,9 @@ class Initial E getE(); F getF(); + void setRecursive(Recursive p); + bool supportsClassGraphDepthMax(); + ["marshaled-result"] B getMB(); ["amd", "marshaled-result"] B getAMDMB(); diff --git a/objective-c/test/Ice/objects/Server.m b/objective-c/test/Ice/objects/Server.m index 4f7dfd61703..5b4944e6ffd 100644 --- a/objective-c/test/Ice/objects/Server.m +++ b/objective-c/test/Ice/objects/Server.m @@ -81,6 +81,7 @@ main(int argc, char* argv[]) { ICEInitializationData* initData = [ICEInitializationData initializationData]; initData.properties = defaultServerProperties(&argc, argv); + [initData.properties setProperty:@"Ice.Warn.Dispatch" value:@"0"]; #if TARGET_OS_IPHONE initData.prefixTable_ = [NSDictionary dictionaryWithObjectsAndKeys: @"TestObjects", @"::Test", diff --git a/objective-c/test/Ice/objects/TestI.m b/objective-c/test/Ice/objects/TestI.m index cea50b4118c..75977e5d138 100644 --- a/objective-c/test/Ice/objects/TestI.m +++ b/objective-c/test/Ice/objects/TestI.m @@ -192,6 +192,15 @@ return _f; } +-(void) setRecursive:(TestObjectsRecursive*)recursive current:(ICECurrent*)current +{ +} + +-(BOOL) supportsClassGraphDepthMax:(ICECurrent*)current +{ + return YES; +} + -(TestObjectsB*) getMB:(ICECurrent*)current { return _b1; diff --git a/php/test/Ice/exceptions/Client.php b/php/test/Ice/exceptions/Client.php index 430c985a125..8732f7eaea8 100644 --- a/php/test/Ice/exceptions/Client.php +++ b/php/test/Ice/exceptions/Client.php @@ -297,7 +297,8 @@ function allTests($communicator) catch(Exception $ex) { $uue = $NS ? "Ice\\ConnectionLostException" : "Ice_ConnectionLostException"; - if(!($ex instanceof $uue)) + $ule = $NS ? "Ice\\UnknownLocalException" : "Ice_UnknownLocalException"; + if(!($ex instanceof $uue) && !($ex instanceof $ule)) { throw $ex; } @@ -432,7 +433,7 @@ function allTests($communicator) $initData = $NS ? eval("return new Ice\\InitializationData;") : eval("return new Ice_InitializationData;"); $initData->properties = $NS ? eval("return Ice\\getProperties();") : eval("return Ice_getProperties();"); $initData->properties->setProperty("Ice.MessageSizeMax", "10"); -$communicator = $NS ? eval("return Ice\\initialize(\$argv, \$initData);") : +$communicator = $NS ? eval("return Ice\\initialize(\$argv, \$initData);") : eval("return Ice_initialize(\$argv, \$initData);"); // This property is set by the test suite, howerver we need to override it for this test. diff --git a/php/test/Ice/objects/Client.php b/php/test/Ice/objects/Client.php index 40a454b92c7..64b4e824dd2 100644 --- a/php/test/Ice/objects/Client.php +++ b/php/test/Ice/objects/Client.php @@ -31,6 +31,7 @@ if($NS) abstract class Test_E extends Test\E {} abstract class Test_F extends Test\F {} class Test_H extends Test\H {} + class Test_Recursive extends Test\Recursive {} class Ice_Value extends Ice\Value {} class Ice_InterfaceByValue extends Ice\InterfaceByValue {} interface Ice_ObjectFactory extends Ice\ObjectFactory {} @@ -408,6 +409,48 @@ function allTests($communicator) test(count($retS) == 1 && count($outS) == 1); echo "ok\n"; + echo "testing recursive type... "; + flush(); + $top = new Test_Recursive(); + $p = $top; + $depth = 0; + try + { + while($depth <= 1000) + { + $p->v = new Test_Recursive(); + $p = $p->v; + if(($depth < 10 && ($depth % 10) == 0) || + ($depth < 1000 && ($depth % 100) == 0) || + ($depth < 10000 && ($depth % 1000) == 0) || + ($depth % 10000) == 0) + { + $initial->setRecursive($top); + } + $depth += 1; + } + test(!$initial->supportsClassGraphDepthMax()); + } + catch(Exception $ex) + { + $ule = $NS ? "Ice\\UnknownLocalException" : "Ice_UnknownLocalException"; + $ue = $NS ? "Ice\\UnknownException" : "Ice_UnknownException"; + if($ex instanceof $ule) + { + // Expected marshal exception from the server (max class graph depth reached) + } + else if($ex instanceof $ue) + { + // Expected stack overflow from the server (Java only) + } + else + { + throw $ex; + } + } + $initial->setRecursive(new Test_Recursive()); + echo "ok\n"; + echo "testing compact ID... "; flush(); try @@ -480,7 +523,7 @@ function allTests($communicator) return $initial; } -$communicator = $NS ? eval("return Ice\\initialize(\$argv);") : +$communicator = $NS ? eval("return Ice\\initialize(\$argv);") : eval("return Ice_initialize(\$argv);"); $factory = new MyValueFactory(); $communicator->getValueFactoryManager()->add($factory, "::Test::B"); diff --git a/php/test/Ice/objects/Test.ice b/php/test/Ice/objects/Test.ice index db1d3c67f50..05076845442 100644 --- a/php/test/Ice/objects/Test.ice +++ b/php/test/Ice/objects/Test.ice @@ -132,6 +132,11 @@ exception EDerived extends EBase A1 a4; }; +class Recursive +{ + Recursive v; +}; + interface Initial { void shutdown(); @@ -142,6 +147,9 @@ interface Initial E getE(); F getF(); + void setRecursive(Recursive p); + bool supportsClassGraphDepthMax(); + ["marshaled-result"] B getMB(); ["amd", "marshaled-result"] B getAMDMB(); diff --git a/python/test/Ice/exceptions/AllTests.py b/python/test/Ice/exceptions/AllTests.py index f876c844cae..fdfc2bddca6 100644 --- a/python/test/Ice/exceptions/AllTests.py +++ b/python/test/Ice/exceptions/AllTests.py @@ -483,6 +483,8 @@ def allTests(communicator): test(False) except Ice.ConnectionLostException: pass + except Ice.UnknownLocalException: + pass except: test(False) diff --git a/python/test/Ice/objects/AllTests.py b/python/test/Ice/objects/AllTests.py index 7578f850ecf..a280939fe94 100644 --- a/python/test/Ice/objects/AllTests.py +++ b/python/test/Ice/objects/AllTests.py @@ -213,6 +213,31 @@ def allTests(communicator): pass print("ok") + sys.stdout.write("testing recursive type... ") + sys.stdout.flush() + top = Test.Recursive() + p = top; + depth = 0; + try: + while depth <= 1000: + p.v = Test.Recursive() + p = p.v; + if (depth < 10 and (depth % 10) == 0) or \ + (depth < 1000 and (depth % 100) == 0) or \ + (depth < 10000 and (depth % 1000) == 0) or \ + (depth % 10000) == 0: + initial.setRecursive(top) + depth += 1 + test(not initial.supportsClassGraphDepthMax()) + except Ice.UnknownLocalException: + # Expected marshal exception from the server (max class graph depth reached) + pass + except Ice.UnknownException: + # Expected stack overflow from the server (Java only) + pass + initial.setRecursive(Test.Recursive()) + print("ok") + sys.stdout.write("testing compact ID... ") sys.stdout.flush() try: diff --git a/python/test/Ice/objects/Collocated.py b/python/test/Ice/objects/Collocated.py index 845d56c4cea..2ee0bade6dd 100755 --- a/python/test/Ice/objects/Collocated.py +++ b/python/test/Ice/objects/Collocated.py @@ -32,7 +32,10 @@ def run(args, communicator): return True try: - with Ice.initialize(sys.argv) as communicator: + initData = Ice.InitializationData() + initData.properties = Ice.createProperties(sys.argv) + initData.properties.setProperty("Ice.Warn.Dispatch", "0"); + with Ice.initialize(sys.argv, initData) as communicator: status = run(sys.argv, communicator) except: traceback.print_exc() diff --git a/python/test/Ice/objects/Server.py b/python/test/Ice/objects/Server.py index b4352d82b5d..40b9f273c1b 100755 --- a/python/test/Ice/objects/Server.py +++ b/python/test/Ice/objects/Server.py @@ -40,8 +40,11 @@ def run(args, communicator): return True try: - with Ice.initialize(sys.argv) as communicator: - status = run(sys.argv, communicator) + initData = Ice.InitializationData() + initData.properties = Ice.createProperties(sys.argv) + initData.properties.setProperty("Ice.Warn.Dispatch", "0"); + with Ice.initialize(sys.argv, initData) as communicator: + status = run(sys.argv, communicator) except: traceback.print_exc() status = False diff --git a/python/test/Ice/objects/Test.ice b/python/test/Ice/objects/Test.ice index e7464b00292..7d9cdba97c9 100644 --- a/python/test/Ice/objects/Test.ice +++ b/python/test/Ice/objects/Test.ice @@ -162,6 +162,11 @@ exception Ex }; +class Recursive +{ + Recursive v; +}; + interface Initial { void shutdown(); @@ -172,6 +177,9 @@ interface Initial E getE(); F getF(); + void setRecursive(Recursive p); + bool supportsClassGraphDepthMax(); + ["marshaled-result"] B getMB(); ["amd", "marshaled-result"] B getAMDMB(); diff --git a/python/test/Ice/objects/TestI.py b/python/test/Ice/objects/TestI.py index 44d70a90d4c..8ce0c271081 100644 --- a/python/test/Ice/objects/TestI.py +++ b/python/test/Ice/objects/TestI.py @@ -125,6 +125,12 @@ class InitialI(Test.Initial): def getF(self, current=None): return self._f + def setRecursive(self, r, current): + pass + + def supportsClassGraphDepthMax(self, current): + return True + def getMB(self, current): return self._b1 diff --git a/ruby/test/Ice/exceptions/AllTests.rb b/ruby/test/Ice/exceptions/AllTests.rb index 6fafd8367bc..3fc5166147b 100644 --- a/ruby/test/Ice/exceptions/AllTests.rb +++ b/ruby/test/Ice/exceptions/AllTests.rb @@ -278,6 +278,8 @@ def allTests(communicator) test(false) rescue Ice::ConnectionLostException # Expected + rescue Ice::UnknownLocalException + # Expected rescue print $!.backtrace.join("\n") test(false) diff --git a/ruby/test/Ice/objects/AllTests.rb b/ruby/test/Ice/objects/AllTests.rb index 84ac5d61363..a4d5d235ec8 100644 --- a/ruby/test/Ice/objects/AllTests.rb +++ b/ruby/test/Ice/objects/AllTests.rb @@ -258,6 +258,32 @@ def allTests(communicator) test(retS.length == 1 && outS.length == 1) puts "ok" + print "testing recursive type... " + STDOUT.flush + top = Test::Recursive.new + p = top; + depth = 0; + begin + while depth <= 1000 + p.v = Test::Recursive.new + p = p.v; + if (depth < 10 && (depth % 10) == 0) || \ + (depth < 1000 && (depth % 100) == 0) || \ + (depth < 10000 && (depth % 1000) == 0) || \ + (depth % 10000) == 0 + initial.setRecursive(top) + end + depth += 1 + end + test(!initial.supportsClassGraphDepthMax()) + rescue Ice::UnknownLocalException + # Expected marshal exception from the server (max class graph depth reached) + rescue Ice::UnknownException + # Expected stack overflow from the server (Java only) + end + initial.setRecursive(Test::Recursive.new) + puts "ok" + print "testing compact ID... " STDOUT.flush begin diff --git a/ruby/test/Ice/objects/Test.ice b/ruby/test/Ice/objects/Test.ice index 3708ae63297..571b20b2db4 100644 --- a/ruby/test/Ice/objects/Test.ice +++ b/ruby/test/Ice/objects/Test.ice @@ -132,6 +132,11 @@ exception EDerived extends EBase A1 a4; }; +class Recursive +{ + Recursive v; +}; + class Initial { void shutdown(); @@ -142,6 +147,9 @@ class Initial E getE(); F getF(); + void setRecursive(Recursive p); + bool supportsClassGraphDepthMax(); + ["marshaled-result"] B getMB(); ["amd", "marshaled-result"] B getAMDMB(); diff --git a/scripts/Controller.py b/scripts/Controller.py index 69eecfc54f6..2dce0d40dbf 100755 --- a/scripts/Controller.py +++ b/scripts/Controller.py @@ -130,7 +130,7 @@ class ControllerDriver(Driver): self.current.config.parsedOptions.append(a) setattr(self.current.config, a, v) - class ControllerI(getServantClass("Test.Common", "Controller")): + class ControllerI(Test.Common.Controller): def __init__(self, driver): self.driver = driver self.testcase = None diff --git a/scripts/LocalDriver.py b/scripts/LocalDriver.py index 8a6e4915c4b..71f8d4a4791 100644 --- a/scripts/LocalDriver.py +++ b/scripts/LocalDriver.py @@ -458,15 +458,16 @@ class LocalDriver(Driver): if self.allCross and cross == current.testcase.getMapping(): continue - # If the given mapping doesn't support server-side, skip this mapping. - if cross and cross != cross.getServerMapping(): - continue - - # Skip if the mapping doesn't provide the test case. + # Skip if the mapping doesn't provide the test case server = current.testcase.getServerTestCase(cross) if not server: continue + if cross and server.getMapping() != cross: + if not self.allCross: + current.writeln("skipped, no server available for `{0}' mapping".format(cross)) + continue + current.writeln("[ running {0} test ]".format(current.testcase)) if not self.all: current.config = current.config.cloneRunnable(current) diff --git a/scripts/Util.py b/scripts/Util.py index f2e60647a9c..878b4c8216c 100644 --- a/scripts/Util.py +++ b/scripts/Util.py @@ -763,21 +763,19 @@ class Mapping: # with the mapping return (self.getDefaultSource(f) in files) if m == self else m.hasSource(testId, f) except KeyError: - # Expected if the mapping doesn't support the process type (such as clientBidir) + # Expected if the mapping doesn't support the process type return False - checkClient = lambda f: checkFile(f, self.getClientMapping()) - checkServer = lambda f: checkFile(f, self.getServerMapping()) + checkClient = lambda f: checkFile(f, self.getClientMapping(testId)) + checkServer = lambda f: checkFile(f, self.getServerMapping(testId)) testcases = [] if checkClient("client") and checkServer("server"): testcases.append(ClientServerTestCase()) - if checkClient("client") and checkServer("serveramd") and self.getServerMapping() == self: + if checkClient("client") and checkServer("serveramd") and self.getServerMapping(testId) == self: testcases.append(ClientAMDServerTestCase()) if checkClient("client") and len(testcases) == 0: testcases.append(ClientTestCase()) - if checkClient("clientBidir") and self.getServerMapping().hasSource("Ice/echo", "server"): - testcases.append(ClientEchoServerTestCase()) if checkClient("collocated"): testcases.append(CollocatedTestCase()) if len(testcases) > 0: @@ -804,32 +802,32 @@ class Mapping: def getDefaultSource(self, processType): return processType - def getDefaultProcess(self, processType, testsuite): + def getDefaultProcesses(self, processType, testsuite): # # If no server or client is explicitly set with a testcase, getDefaultProcess is called # to figure out which process class to instantiate. Based on the processType and the testsuite # we instantiate the right default process class. # if processType is None: - return None + return [] elif testsuite.getId().startswith("IceUtil") or testsuite.getId().startswith("Slice"): - return SimpleClient() + return [SimpleClient()] elif testsuite.getId().startswith("IceGrid"): if processType in ["client", "collocated"]: - return IceGridClient() + return [IceGridClient()] if processType in ["server", "serveramd"]: - return IceGridServer() + return [IceGridServer()] else: - return Server() if processType in ["server", "serveramd"] else Client() + return [Server()] if processType in ["server", "serveramd"] else [Client()] def getDefaultExe(self, processType, config): return processType - def getClientMapping(self): + def getClientMapping(self, testId=None): # The client mapping is always the same as this mapping. return self - def getServerMapping(self): + def getServerMapping(self, testId=None): # Can be overridden for client-only mapping that relies on another mapping for servers return self @@ -1208,6 +1206,18 @@ class SliceTranslator(ProcessFromBinDir, SimpleClient): return translator +class EchoServer(Server): + + def __init__(self): + Server.__init__(self, mapping=Mapping.getByName("cpp"), quiet=True, waitForShutdown=False) + + def getCommandLine(self, current): + current.push(self.mapping.findTestSuite("Ice/echo").findTestCase("server")) + try: + return Server.getCommandLine(self, current) + finally: + current.pop() + # # A test case is composed of servers and clients. When run, all servers are started # sequentially. When the servers are ready, the clients are also ran sequentially. @@ -1263,16 +1273,14 @@ class TestCase(Runnable): # returns the type of client to instantiate (client, collocated, etc) # if not self.clients: - client = self.mapping.getDefaultProcess(self.getClientType(), testsuite) - self.clients = [client] if client else [] + self.clients = self.mapping.getDefaultProcesses(self.getClientType(), testsuite) # # If no servers are explicitly specified, we instantiate one if getServerType() # returns the type of server to instantiate (server, serveramd, etc) # if not self.servers: - server = self.mapping.getDefaultProcess(self.getServerType(), testsuite) - self.servers = [server] if server else [] + self.servers = self.mapping.getDefaultProcesses(self.getServerType(), testsuite) def getOptions(self, current): return self.options(current) if callable(self.options) else self.options @@ -1354,11 +1362,11 @@ class TestCase(Runnable): return None def getServerTestCase(self, cross=None): - testsuite = (cross or self.mapping.getServerMapping()).findTestSuite(self.testsuite) + testsuite = (cross or self.mapping).getServerMapping(self.testsuite.getId()).findTestSuite(self.testsuite) return testsuite.findTestCase(self) if testsuite else None def getClientTestCase(self): - testsuite = self.mapping.getClientMapping().findTestSuite(self.testsuite) + testsuite = self.mapping.getClientMapping(self.testsuite.getId()).findTestSuite(self.testsuite) return testsuite.findTestCase(self) if testsuite else None def _startServerSide(self, current): @@ -1459,20 +1467,6 @@ class ClientServerTestCase(ClientTestCase): def getServerType(self): return "server" -class ClientEchoServerTestCase(ClientServerTestCase): - - def __init__(self, name="client/echo server", *args, **kargs): - ClientServerTestCase.__init__(self, name, *args, **kargs) - - def getServerTestCase(self, cross=None): - ts = Mapping.getByName("cpp").findTestSuite("Ice/echo") - if ts: - return ts.findTestCase("server") - return None - - def getClientType(self): - return "clientBidir" - class CollocatedTestCase(ClientTestCase): def __init__(self, name="collocated", *args, **kargs): @@ -2079,6 +2073,7 @@ class BrowserProcessController(RemoteProcessController): def __init__(self, current): RemoteProcessController.__init__(self, current, "ws -h 127.0.0.1 -p 15002:wss -h 127.0.0.1 -p 15003") self.httpServer = None + self.testcase = None try: from selenium import webdriver if not hasattr(webdriver, current.config.browser): @@ -2105,7 +2100,7 @@ class BrowserProcessController(RemoteProcessController): self.driver = getattr(webdriver, current.config.browser)() cmd = "node -e \"require('./bin/HttpServer')()\""; - cwd = current.testsuite.getMapping().getPath() + cwd = current.testcase.getMapping().getPath() self.httpServer = Expect.Expect(cmd, cwd=cwd) self.httpServer.expect("listening on ports") except: @@ -2116,26 +2111,27 @@ class BrowserProcessController(RemoteProcessController): return str(self.driver) def getControllerIdentity(self, current): - # - # Load the controller page each time we're asked for the controller, the controller page - # will connect to the process controller registry to register itself with this script. + # Load the controller page each time we're asked for the controller and if we're running + # another testcase, the controller page will connect to the process controller registry + # to register itself with this script. # - testsuite = ("es5/" if current.config.es5 else "") + str(current.testsuite) - if current.config.protocol == "wss": - protocol = "https" - port = "9090" - cport = "15003" - else: - protocol = "http" - port = "8080" - cport = "15002" - - self.driver.get("{0}://127.0.0.1:{1}/test/{2}/controller.html?port={3}&worker={4}".format(protocol, - port, - testsuite, - cport, - current.config.worker)) + if self.testcase != current.testcase: + self.testcase = current.testcase + testsuite = ("es5/" if current.config.es5 else "") + str(current.testsuite) + if current.config.protocol == "wss": + protocol = "https" + port = "9090" + cport = "15003" + else: + protocol = "http" + port = "8080" + cport = "15002" + self.driver.get("{0}://127.0.0.1:{1}/test/{2}/controller.html?port={3}&worker={4}".format(protocol, + port, + testsuite, + cport, + current.config.worker)) return "Browser/ProcessController" def destroy(self, driver): @@ -2395,7 +2391,7 @@ class Driver: processController = LocalProcessController else: processController = UWPProcessController - elif isinstance(current.testcase.getMapping(), JavaScriptMapping) and current.config.browser: + elif process and isinstance(process.getMapping(current), JavaScriptMapping) and current.config.browser: processController = BrowserProcessController else: processController = LocalProcessController @@ -2764,7 +2760,7 @@ class CppBasedClientMapping(CppBasedMapping): Mapping.loadTestSuites(self, tests, config, filters, rfilters) self.getServerMapping().loadTestSuites(self.testsuites.keys(), config) - def getServerMapping(self): + def getServerMapping(self, testId=None): return Mapping.getByName("cpp") # By default, run clients against C++ mapping executables def getDefaultExe(self, processType, config): @@ -2861,8 +2857,16 @@ class JavaScriptMapping(Mapping): Mapping.loadTestSuites(self, tests, config, filters, rfilters) self.getServerMapping().loadTestSuites(list(self.testsuites.keys()) + ["Ice/echo"], config, filters, rfilters) - def getServerMapping(self): - return Mapping.getByName("cpp") # By default, run clients against C++ mapping executables + def getServerMapping(self, testId=None): + if testId and self.hasSource(testId, "server"): + return self + else: + return Mapping.getByName("cpp") # Run clients against C++ mapping servers if no JS server provided + + def getDefaultProcesses(self, processType, testsuite): + if processType in ["server", "serveramd"]: + return [EchoServer(), Server()] + return Mapping.getDefaultProcesses(self, processType, testsuite) def getCommandLine(self, current, process, exe): if current.config.es5: @@ -2871,7 +2875,7 @@ class JavaScriptMapping(Mapping): return "node {0}/test/Common/run.js {1}".format(self.path, exe) def getDefaultSource(self, processType): - return { "client" : "Client.js", "clientBidir" : "ClientBidir.js" }[processType] + return { "client" : "Client.js", "serveramd" : "ServerAMD.js", "server" : "Server.js" }[processType] def getDefaultExe(self, processType, config=None): return self.getDefaultSource(processType).replace(".js", "") @@ -2952,12 +2956,6 @@ def runTests(mappings=None, drivers=None): if not drivers: drivers = Driver.getAll() - # - # All mappings contains all the mappings necessary to run the tests from the given mappings. Some - # mappings depend on other mappings for running (e.g.: Ruby needs the C++ mapping). - # - allMappings = list(set([m.getClientMapping() for m in mappings] + [m.getServerMapping() for m in mappings])) - def usage(): print("Usage: " + sys.argv[0] + " [options] [tests]") print("") @@ -2969,7 +2967,7 @@ def runTests(mappings=None, drivers=None): driver.usage() Mapping.Config.commonUsage() - for mapping in allMappings: + for mapping in Mapping.getAll(): mapping.Config.usage() print("") @@ -3001,7 +2999,7 @@ def runTests(mappings=None, drivers=None): # python mapping because we might use the local IcePy build to initialize a communicator). # configs = {} - for mapping in allMappings + driver.getMappings() + [Mapping.getByName("python")]: + for mapping in Mapping.getAll(): if mapping not in configs: configs[mapping] = mapping.createConfig(opts[:]) diff --git a/scripts/tests/Ice/exceptions.py b/scripts/tests/Ice/exceptions.py index a4d2fc1a2a0..c0b5cabe5df 100644 --- a/scripts/tests/Ice/exceptions.py +++ b/scripts/tests/Ice/exceptions.py @@ -21,14 +21,6 @@ if Mapping.getByPath(__name__).hasSource("Ice/exceptions", "serveramd"): ClientAMDServerTestCase("client/amd server with 1.0 encoding", props={ "Ice.Default.EncodingVersion" : "1.0"}), ] -# If the mapping has bidir clients, also run with the bidir clients. -if Mapping.getByPath(__name__).getClientMapping().hasSource("Ice/exceptions", "clientBidir"): - testcases += [ - ClientEchoServerTestCase("client/echo server with compact format"), - ClientEchoServerTestCase("client/echo server with sliced format", props={"Ice.Default.SlicedFormat" : True}), - ClientEchoServerTestCase("client/echo server with 1.0 encoding", props={"Ice.Default.EncodingVersion" : "1.0"}), - ] - if Mapping.getByPath(__name__).hasSource("Ice/exceptions", "collocated"): testcases += [ CollocatedTestCase() ] diff --git a/scripts/tests/Ice/objects.py b/scripts/tests/Ice/objects.py index 3e77deee0a8..8f9460e3a27 100644 --- a/scripts/tests/Ice/objects.py +++ b/scripts/tests/Ice/objects.py @@ -7,10 +7,24 @@ # # ********************************************************************** +# +# Use a server stack size of 512KB, this is in particular important for Java +# servers which don't implement Ice.ClassGraphDepthMax and which could cause +# a client stack overflow if the client stack is too small compared to the +# Java server stack. +# +class ObjectClientServerTestCase(ClientServerTestCase): + + def getProps(self, process, current): + props = ClientServerTestCase.getProps(self, process, current) + if isinstance(process, Server) and not isinstance(process, EchoServer): + props["Ice.ThreadPool.Server.StackSize"] = 512 * 1024 + return props + testcases = [ - ClientServerTestCase("client/server with compact format"), - ClientServerTestCase("client/server with sliced format", props={ "Ice.Default.SlicedFormat" : True }), - ClientServerTestCase("client/server with 1.0 encoding", props={ "Ice.Default.EncodingVersion" : "1.0" }), + ObjectClientServerTestCase("client/server with compact format"), + ObjectClientServerTestCase("client/server with sliced format", props = {"Ice.Default.SlicedFormat" : True}), + ObjectClientServerTestCase("client/server with 1.0 encoding", props = {"Ice.Default.EncodingVersion" : "1.0"}), ] if Mapping.getByPath(__name__).hasSource("Ice/objects", "collocated"): diff --git a/scripts/tests/Ice/optional.py b/scripts/tests/Ice/optional.py index 02c0b7d73c0..2b1d1bb97a1 100644 --- a/scripts/tests/Ice/optional.py +++ b/scripts/tests/Ice/optional.py @@ -20,11 +20,4 @@ if Mapping.getByPath(__name__).hasSource("Ice/optional", "serveramd"): ClientAMDServerTestCase("client/amd server with sliced format", props={ "Ice.Default.SlicedFormat" : True }), ] -# If the mapping has bidir clients, also run with the bidir clients. -if Mapping.getByPath(__name__).getClientMapping().hasSource("Ice/optional", "clientBidir"): - testcases += [ - ClientEchoServerTestCase("client/echo server with compact format"), - ClientEchoServerTestCase("client/echo server with sliced format", props={ "Ice.Default.SlicedFormat" : True }), - ] - TestSuite(__name__, testcases)
\ No newline at end of file |