1 //
2 // Copyright (c) ZeroC, Inc. All rights reserved.
3 //
4 
5 #include <Ice/Ice.h>
6 #include <TestHelper.h>
7 #include <InstrumentationI.h>
8 #include <Test.h>
9 
10 using namespace std;
11 using namespace Test;
12 
13 namespace
14 {
15 
16 class Callback : public IceUtil::Shared, private IceUtil::Monitor<IceUtil::Mutex>
17 {
18 public:
19 
Callback()20     Callback() : _wait(true)
21     {
22     }
23 
response()24     void response()
25     {
26         Lock sync(*this);
27         _wait = false;
28         notify();
29     }
30 
exception(const Ice::Exception &)31     void exception(const Ice::Exception&)
32     {
33         response();
34     }
35 
36     void
waitForResponse()37     waitForResponse()
38     {
39         Lock sync(*this);
40         while(_wait)
41         {
42             wait();
43         }
44         _wait = true;
45     }
46 
47 private:
48 
49     bool _wait;
50 };
51 typedef IceUtil::Handle<Callback> CallbackPtr;
52 
53 string
getPort(const Ice::PropertiesAdminPrxPtr & p)54 getPort(const Ice::PropertiesAdminPrxPtr& p)
55 {
56     ostringstream os;
57     os << TestHelper::getTestPort(p->ice_getCommunicator()->getProperties(), 0);
58     return os.str();
59 }
60 
61 Ice::PropertyDict
getClientProps(const Ice::PropertiesAdminPrxPtr & pa,const Ice::PropertyDict & orig,const string & m=string ())62 getClientProps(const Ice::PropertiesAdminPrxPtr& pa, const Ice::PropertyDict& orig, const string& m = string())
63 {
64     Ice::PropertyDict props = pa->getPropertiesForPrefix("IceMX.Metrics");
65     for(Ice::PropertyDict::iterator p = props.begin(); p != props.end(); ++p)
66     {
67         p->second = "";
68     }
69     for(Ice::PropertyDict::const_iterator p = orig.begin(); p != orig.end(); ++p)
70     {
71         props[p->first] = p->second;
72     }
73     string map;
74     if(!m.empty())
75     {
76         map += "Map." + m + '.';
77     }
78     props["IceMX.Metrics.View." + map + "Reject.parent"] = "Ice\\.Admin";
79     props["IceMX.Metrics.View." + map + "Accept.endpointPort"] = getPort(pa);
80     props["IceMX.Metrics.View." + map + "Reject.identity"] = ".*/admin|controller";
81     return props;
82 }
83 
84 Ice::PropertyDict
getServerProps(const Ice::PropertiesAdminPrxPtr & pa,const Ice::PropertyDict & orig,const string & m=string ())85 getServerProps(const Ice::PropertiesAdminPrxPtr& pa, const Ice::PropertyDict& orig, const string& m = string())
86 {
87     Ice::PropertyDict props = pa->getPropertiesForPrefix("IceMX.Metrics");
88     for(Ice::PropertyDict::iterator p = props.begin(); p != props.end(); ++p)
89     {
90         p->second = "";
91     }
92     for(Ice::PropertyDict::const_iterator p = orig.begin(); p != orig.end(); ++p)
93     {
94         props[p->first] = p->second;
95     }
96     string map;
97     if(!m.empty())
98     {
99         map += "Map." + m + '.';
100     }
101     props["IceMX.Metrics.View." + map + "Reject.parent"] = "Ice\\.Admin|Controller";
102     props["IceMX.Metrics.View." + map + "Accept.endpointPort"] = getPort(pa);
103     return props;
104 }
105 
106 IceMX::ConnectionMetricsPtr
getServerConnectionMetrics(const IceMX::MetricsAdminPrxPtr & metrics,Ice::Long expected)107 getServerConnectionMetrics(const IceMX::MetricsAdminPrxPtr& metrics, Ice::Long expected)
108 {
109     IceMX::ConnectionMetricsPtr s;
110     int nRetry = 30;
111     Ice::Long timestamp;
112     s = ICE_DYNAMIC_CAST(IceMX::ConnectionMetrics, metrics->getMetricsView("View", timestamp)["Connection"][0]);
113     while(s->sentBytes != expected && nRetry-- > 0)
114     {
115         // On some platforms, it's necessary to wait a little before obtaining the server metrics
116         // to get an accurate sentBytes metric. The sentBytes metric is updated before the response
117         // to the operation is sent and getMetricsView can be dispatched before the metric is really
118         // updated.
119         IceUtil::ThreadControl::sleep(IceUtil::Time::milliSeconds(100));
120         s = ICE_DYNAMIC_CAST(IceMX::ConnectionMetrics, metrics->getMetricsView("View", timestamp)["Connection"][0]);
121     }
122     return s;
123 }
124 
125 class UpdateCallbackI :
126 #ifndef ICE_CPP11_MAPPING
127         public Ice::PropertiesAdminUpdateCallback,
128 #endif
129 private IceUtil::Monitor<IceUtil::Mutex>
130 {
131 public:
132 
UpdateCallbackI(const Ice::PropertiesAdminPrxPtr & serverProps)133     UpdateCallbackI(const Ice::PropertiesAdminPrxPtr& serverProps) : _updated(false), _serverProps(serverProps)
134     {
135     }
136 
137     void
waitForUpdate()138     waitForUpdate()
139     {
140         {
141             Lock sync(*this);
142             while(!_updated)
143             {
144                 wait();
145             }
146         }
147 
148         // Ensure that the previous updates were committed, the setProperties call returns before
149         // notifying the callbacks so to ensure all the update callbacks have be notified we call
150         // a second time, this will block until all the notifications from the first update have
151         // completed.
152         _serverProps->setProperties(Ice::PropertyDict());
153 
154         Lock sync(*this);
155         _updated = false;
156     }
157 
158     void
updated(const Ice::PropertyDict &)159     updated(const Ice::PropertyDict&)
160     {
161         Lock sync(*this);
162         _updated = true;
163         notify();
164     }
165 
166 private:
167 
168     bool _updated;
169     Ice::PropertiesAdminPrxPtr _serverProps;
170 };
171 ICE_DEFINE_PTR(UpdateCallbackIPtr, UpdateCallbackI);
172 
173 void
waitForCurrent(const IceMX::MetricsAdminPrxPtr & metrics,const string & viewName,const string & map,int value)174 waitForCurrent(const IceMX::MetricsAdminPrxPtr& metrics, const string& viewName, const string& map, int value)
175 {
176     while(true)
177     {
178         Ice::Long timestamp;
179         IceMX::MetricsView view = metrics->getMetricsView(viewName, timestamp);
180         test(view.find(map) != view.end());
181         bool ok = true;
182         for(IceMX::MetricsMap::const_iterator m = view[map].begin(); m != view[map].end(); ++m)
183         {
184             if((*m)->current != value)
185             {
186                 ok = false;
187                 break;
188             }
189         }
190         if(ok)
191         {
192             break;
193         }
194         IceUtil::ThreadControl::sleep(IceUtil::Time::milliSeconds(50));
195     }
196 }
197 
198 void
waitForCurrent(const ObserverIPtr & observer,int value)199 waitForCurrent(const ObserverIPtr& observer, int value)
200 {
201     for(int i = 0; i < 10; ++i)
202     {
203         if(observer->getCurrent() != value)
204         {
205             IceUtil::ThreadControl::sleep(IceUtil::Time::milliSeconds(50));
206         }
207         else
208         {
209             break;
210         }
211     }
212 };
213 
214 template<typename T> void
testAttribute(const IceMX::MetricsAdminPrxPtr & metrics,const Ice::PropertiesAdminPrxPtr & props,UpdateCallbackI * update,const string & map,const string & attr,const string & value,const T & func)215 testAttribute(const IceMX::MetricsAdminPrxPtr& metrics,
216               const Ice::PropertiesAdminPrxPtr& props,
217               UpdateCallbackI* update,
218               const string& map,
219               const string& attr,
220               const string& value,
221               const T& func)
222 {
223     Ice::PropertyDict dict;
224     dict["IceMX.Metrics.View.Map." + map + ".GroupBy"] = attr;
225     if(props->ice_getIdentity().category == "client")
226     {
227         props->setProperties(getClientProps(props, dict, map));
228         update->waitForUpdate();
229     }
230     else
231     {
232         props->setProperties(getServerProps(props, dict, map));
233         props->setProperties(Ice::PropertyDict());
234     }
235 
236     func();
237     Ice::Long timestamp;
238     IceMX::MetricsView view = metrics->getMetricsView("View", timestamp);
239     if(view.find(map) == view.end() || view[map].empty())
240     {
241         if(!value.empty())
242         {
243             cerr << "no map `" << map << "' for group by = `" << attr << "'" << endl;
244             test(false);
245         }
246     }
247     else if(view[map].size() != 1 || view[map][0]->id != value)
248     {
249         cerr << "invalid attribute value: " << attr << " = " << value << " got " << view[map][0]->id << endl;
250         test(false);
251     }
252 
253     dict.clear();
254     if(props->ice_getIdentity().category == "client")
255     {
256         props->setProperties(getClientProps(props, dict, map));
257         update->waitForUpdate();
258     }
259     else
260     {
261         props->setProperties(getServerProps(props, dict, map));
262         props->setProperties(Ice::PropertyDict());
263     }
264 }
265 
266 struct Void
267 {
268     void
operator ()__anonce9b06120111::Void269     operator()() const
270     {
271     }
272 };
273 
274 struct Connect
275 {
Connect__anonce9b06120111::Connect276     Connect(const Ice::ObjectPrxPtr& proxyP) : proxy(proxyP)
277     {
278     }
279 
280     void
operator ()__anonce9b06120111::Connect281     operator()() const
282     {
283         if(proxy->ice_getCachedConnection())
284         {
285             proxy->ice_getCachedConnection()->close(Ice::ICE_SCOPED_ENUM(ConnectionClose, GracefullyWithWait));
286         }
287         try
288         {
289             proxy->ice_ping();
290         }
291         catch(const Ice::LocalException&)
292         {
293         }
294         if(proxy->ice_getCachedConnection())
295         {
296             proxy->ice_getCachedConnection()->close(Ice::ICE_SCOPED_ENUM(ConnectionClose, GracefullyWithWait));
297         }
298     }
299 
300     Ice::ObjectPrxPtr proxy;
301 };
302 
303 struct InvokeOp
304 {
InvokeOp__anonce9b06120111::InvokeOp305     InvokeOp(const Test::MetricsPrxPtr& proxyP) : proxy(proxyP)
306     {
307     }
308 
309     void
operator ()__anonce9b06120111::InvokeOp310     operator()() const
311     {
312         Ice::Context ctx;
313         ctx["entry1"] = "test";
314         ctx["entry2"] = "";
315         proxy->op(ctx);
316     }
317 
318     Test::MetricsPrxPtr proxy;
319 };
320 
321 void
testAttribute(const IceMX::MetricsAdminPrxPtr & metrics,const Ice::PropertiesAdminPrxPtr & props,UpdateCallbackI * update,const string & map,const string & attr,const string & value)322 testAttribute(const IceMX::MetricsAdminPrxPtr& metrics,
323               const Ice::PropertiesAdminPrxPtr& props,
324               UpdateCallbackI* update,
325               const string& map,
326               const string& attr,
327               const string& value)
328 {
329     testAttribute(metrics, props, update, map, attr, value, Void());
330 }
331 
332 void
updateProps(const Ice::PropertiesAdminPrxPtr & cprops,const Ice::PropertiesAdminPrxPtr & sprops,UpdateCallbackI * callback,const Ice::PropertyDict & props,const string & map=string ())333 updateProps(const Ice::PropertiesAdminPrxPtr& cprops,
334             const Ice::PropertiesAdminPrxPtr& sprops,
335             UpdateCallbackI* callback,
336             const Ice::PropertyDict& props,
337             const string& map = string())
338 {
339     if(sprops->ice_getConnection())
340     {
341         cprops->setProperties(getClientProps(cprops, props, map));
342         sprops->setProperties(getServerProps(sprops, props, map));
343     }
344     else
345     {
346         Ice::PropertyDict clientProps = getClientProps(cprops, props, map);
347         Ice::PropertyDict serverProps = getClientProps(cprops, props, map);
348         serverProps.insert(clientProps.begin(), clientProps.end());
349         cprops->setProperties(serverProps);
350     }
351 
352     callback->waitForUpdate();
353 }
354 
355 void
clearView(const Ice::PropertiesAdminPrxPtr & cprops,const Ice::PropertiesAdminPrxPtr & sprops,UpdateCallbackI * callback)356 clearView(const Ice::PropertiesAdminPrxPtr& cprops, const Ice::PropertiesAdminPrxPtr& sprops, UpdateCallbackI* callback)
357 {
358     Ice::PropertyDict dict;
359 
360     dict = cprops->getPropertiesForPrefix("IceMX.Metrics");
361     dict["IceMX.Metrics.View.Disabled"] = "1";
362     cprops->setProperties(dict);
363 
364     dict = sprops->getPropertiesForPrefix("IceMX.Metrics");
365     dict["IceMX.Metrics.View.Disabled"] = "1";
366     sprops->setProperties(dict);
367 
368     callback->waitForUpdate();
369 
370     dict = cprops->getPropertiesForPrefix("IceMX.Metrics");
371     dict["IceMX.Metrics.View.Disabled"] = "";
372     cprops->setProperties(dict);
373 
374     dict = sprops->getPropertiesForPrefix("IceMX.Metrics");
375     dict["IceMX.Metrics.View.Disabled"] = "";
376     sprops->setProperties(dict);
377 
378     callback->waitForUpdate();
379 }
380 
381 void
checkFailure(const IceMX::MetricsAdminPrxPtr & m,const string & map,const string & id,const string & failure,int count=0)382 checkFailure(const IceMX::MetricsAdminPrxPtr& m, const string& map, const string& id, const string& failure,
383              int count = 0)
384 {
385     IceMX::MetricsFailures f = m->getMetricsFailures("View", map, id);
386     if(f.failures.find(failure) == f.failures.end())
387     {
388         cerr << "couldn't find failure `" << failure << "' for `" << id << "'" << endl;
389         test(false);
390     }
391     if(count > 0 && f.failures[failure] != count)
392     {
393         cerr << "count for failure `" << failure << "' of `" << id << "' is different from expected: ";
394         cerr << count << " != " << f.failures[failure] << endl;
395         test(false);
396     }
397 }
398 
399 map<string, IceMX::MetricsPtr>
toMap(const IceMX::MetricsMap & mmap)400 toMap(const IceMX::MetricsMap& mmap)
401 {
402     map<string, IceMX::MetricsPtr> m;
403     for(IceMX::MetricsMap::const_iterator p = mmap.begin(); p != mmap.end(); ++p)
404     {
405         m.insert(make_pair((*p)->id, *p));
406     }
407     return m;
408 }
409 
410 }
411 
412 MetricsPrxPtr
allTests(Test::TestHelper * helper,const CommunicatorObserverIPtr & obsv)413 allTests(Test::TestHelper* helper, const CommunicatorObserverIPtr& obsv)
414 {
415     Ice::CommunicatorPtr communicator = helper->communicator();
416     string host = helper->getTestHost();
417     string port;
418     {
419         ostringstream os;
420         os << helper->getTestPort();
421         port = os.str();
422     }
423     string hostAndPort = host + ":" + port;
424     string protocol = helper->getTestProtocol();
425     string endpoint;
426     {
427         ostringstream os;
428         os << protocol << " -h " << host << " -p " << port;
429         endpoint = os.str();
430     }
431 
432     MetricsPrxPtr metrics = ICE_CHECKED_CAST(MetricsPrx, communicator->stringToProxy("metrics:" + endpoint));
433     bool collocated = !metrics->ice_getConnection();
434 
435     cout << "testing metrics admin facet checkedCast... " << flush;
436     Ice::ObjectPrxPtr admin = communicator->getAdmin();
437 
438     Ice::PropertiesAdminPrxPtr clientProps =  ICE_CHECKED_CAST(Ice::PropertiesAdminPrx, admin, "Properties");
439     IceMX::MetricsAdminPrxPtr clientMetrics = ICE_CHECKED_CAST(IceMX::MetricsAdminPrx, admin, "Metrics");
440     test(clientProps && clientMetrics);
441 
442     admin = metrics->getAdmin();
443     Ice::PropertiesAdminPrxPtr serverProps = ICE_CHECKED_CAST(Ice::PropertiesAdminPrx, admin, "Properties");
444     IceMX::MetricsAdminPrxPtr serverMetrics = ICE_CHECKED_CAST(IceMX::MetricsAdminPrx, admin, "Metrics");
445     test(serverProps && serverMetrics);
446 
447     UpdateCallbackIPtr update = ICE_MAKE_SHARED(UpdateCallbackI, serverProps);
448 
449     ICE_DYNAMIC_CAST(Ice::NativePropertiesAdmin, communicator->findAdminFacet("Properties"))->addUpdateCallback(
450 #ifdef ICE_CPP11_MAPPING
451         [update](const Ice::PropertyDict& changes) { update->updated(changes); }
452 #else
453         update
454 #endif
455         );
456 
457     cout << "ok" << endl;
458 
459     Ice::PropertyDict props;
460 
461     cout << "testing group by none..." << flush;
462 
463     props["IceMX.Metrics.View.GroupBy"] = "none";
464     updateProps(clientProps, serverProps, update.get(), props);
465 
466 #ifndef ICE_OS_UWP
467     int threadCount = 4;
468 #else
469     int threadCount = 3; // No endpoint host resolver thread with UWP.
470 #endif
471 
472     Ice::Long timestamp;
473     IceMX::MetricsView view = clientMetrics->getMetricsView("View", timestamp);
474     if(!collocated)
475     {
476         test(view["Connection"].size() == 1 && view["Connection"][0]->current == 1 &&
477              view["Connection"][0]->total == 1);
478     }
479 
480     test(view["Thread"].size() == 1 && view["Thread"][0]->current == threadCount &&
481          view["Thread"][0]->total == threadCount);
482     cout << "ok" << endl;
483 
484     cout << "testing group by id..." << flush;
485 
486     props["IceMX.Metrics.View.GroupBy"] = "id";
487     updateProps(clientProps, serverProps, update.get(), props);
488 
489     metrics->ice_ping();
490     metrics->ice_ping();
491     metrics->ice_connectionId("Con1")->ice_ping();
492     metrics->ice_connectionId("Con1")->ice_ping();
493     metrics->ice_connectionId("Con1")->ice_ping();
494 
495     waitForCurrent(clientMetrics, "View", "Invocation", 0);
496     waitForCurrent(serverMetrics, "View", "Dispatch", 0);
497 
498     view = clientMetrics->getMetricsView("View", timestamp);
499     if(!collocated)
500     {
501         test(view["Connection"].size() == 2);
502     }
503 
504     test(static_cast<int>(view["Thread"].size()) == threadCount);
505     test(view["Invocation"].size() == 1);
506 
507     IceMX::InvocationMetricsPtr invoke = ICE_DYNAMIC_CAST(IceMX::InvocationMetrics, view["Invocation"][0]);
508     test(invoke->id.find("[ice_ping]") > 0 && invoke->current == 0 && invoke->total == 5);
509 
510     if(!collocated)
511     {
512         test(invoke->remotes.size() == 2);
513         test(invoke->remotes[0]->total == 2);
514         test(invoke->remotes[1]->total == 3);
515     }
516     else
517     {
518         test(invoke->collocated.size() == 1);
519         test(invoke->collocated[0]->total == 5);
520     }
521 
522     view = serverMetrics->getMetricsView("View", timestamp);
523     if(serverMetrics->ice_getConnection())
524     {
525         test(static_cast<int>(view["Thread"].size()) > threadCount);
526         test(view["Connection"].size() == 2);
527     }
528     test(view["Dispatch"].size() == 1);
529     test(view["Dispatch"][0]->current == 0 && view["Dispatch"][0]->total == 5);
530     test(view["Dispatch"][0]->id.find("[ice_ping]") > 0);
531 
532     if(!collocated)
533     {
534         metrics->ice_getConnection()->close(Ice::ICE_SCOPED_ENUM(ConnectionClose, GracefullyWithWait));
535         metrics->ice_connectionId("Con1")->ice_getConnection()->close(
536             Ice::ICE_SCOPED_ENUM(ConnectionClose, GracefullyWithWait));
537 
538         waitForCurrent(clientMetrics, "View", "Connection", 0);
539         waitForCurrent(serverMetrics, "View", "Connection", 0);
540     }
541 
542     clearView(clientProps, serverProps, update.get());
543 
544     cout << "ok" << endl;
545 
546     map<string, IceMX::MetricsPtr> map;
547 
548     string type;
549     string isSecure;
550     if(!collocated)
551     {
552         Ice::EndpointInfoPtr endpointInfo = metrics->ice_getConnection()->getEndpoint()->getInfo();
553         {
554             ostringstream os;
555             os << endpointInfo->type();
556             type = os.str();
557         }
558         isSecure = endpointInfo->secure() ? "true": "false";
559     }
560     if(!collocated)
561     {
562         cout << "testing connection metrics... " << flush;
563 
564         props["IceMX.Metrics.View.Map.Connection.GroupBy"] = "none";
565         updateProps(clientProps, serverProps, update.get(), props, "Connection");
566 
567         test(clientMetrics->getMetricsView("View", timestamp)["Connection"].empty());
568         test(serverMetrics->getMetricsView("View", timestamp)["Connection"].empty());
569 
570         metrics->ice_ping();
571 
572         IceMX::ConnectionMetricsPtr cm1, sm1, cm2, sm2;
573         cm1 = ICE_DYNAMIC_CAST(IceMX::ConnectionMetrics, clientMetrics->getMetricsView("View", timestamp)["Connection"][0]);
574         sm1 = ICE_DYNAMIC_CAST(IceMX::ConnectionMetrics, serverMetrics->getMetricsView("View", timestamp)["Connection"][0]);
575         sm1 = getServerConnectionMetrics(serverMetrics, 25);
576         test(cm1->total == 1 && sm1->total == 1);
577 
578         metrics->ice_ping();
579 
580         cm2 = ICE_DYNAMIC_CAST(IceMX::ConnectionMetrics, clientMetrics->getMetricsView("View", timestamp)["Connection"][0]);
581         sm2 = getServerConnectionMetrics(serverMetrics, 50);
582 
583         test(cm2->sentBytes - cm1->sentBytes == 45); // 45 for ice_ping request
584         test(cm2->receivedBytes - cm1->receivedBytes == 25); // 25 bytes for ice_ping response
585         test(sm2->receivedBytes - sm1->receivedBytes == 45);
586         test(sm2->sentBytes - sm1->sentBytes == 25);
587 
588         cm1 = cm2;
589         sm1 = sm2;
590 
591         Test::ByteSeq bs;
592         metrics->opByteS(bs);
593 
594         cm2 = ICE_DYNAMIC_CAST(IceMX::ConnectionMetrics, clientMetrics->getMetricsView("View", timestamp)["Connection"][0]);
595         sm2 = getServerConnectionMetrics(serverMetrics, sm1->sentBytes + cm2->receivedBytes - cm1->receivedBytes);
596         Ice::Long requestSz = cm2->sentBytes - cm1->sentBytes;
597         Ice::Long replySz = cm2->receivedBytes - cm1->receivedBytes;
598 
599         cm1 = cm2;
600         sm1 = sm2;
601 
602         bs.resize(456);
603         metrics->opByteS(bs);
604 
605         cm2 = ICE_DYNAMIC_CAST(IceMX::ConnectionMetrics, clientMetrics->getMetricsView("View", timestamp)["Connection"][0]);
606         sm2 = getServerConnectionMetrics(serverMetrics, sm1->sentBytes + replySz);
607 
608         // 4 is for the seq variable size
609         test(cm2->sentBytes - cm1->sentBytes == requestSz + static_cast<int>(bs.size()) + 4);
610         test(cm2->receivedBytes - cm1->receivedBytes == replySz);
611         test(sm2->receivedBytes - sm1->receivedBytes == requestSz + static_cast<int>(bs.size()) + 4);
612         test(sm2->sentBytes - sm1->sentBytes == replySz);
613 
614         cm1 = cm2;
615         sm1 = sm2;
616 
617         bs.resize(1024 * 1024 * 10); // Try with large amount of data which should be sent in several chunks
618         metrics->opByteS(bs);
619 
620         cm2 = ICE_DYNAMIC_CAST(IceMX::ConnectionMetrics, clientMetrics->getMetricsView("View", timestamp)["Connection"][0]);
621         sm2 = getServerConnectionMetrics(serverMetrics, sm1->sentBytes + replySz);
622 
623         // 4 is for the seq variable size
624         test(cm2->sentBytes - cm1->sentBytes == requestSz + static_cast<int>(bs.size()) + 4);
625         test(cm2->receivedBytes - cm1->receivedBytes == replySz);
626         test(sm2->receivedBytes - sm1->receivedBytes == requestSz + static_cast<int>(bs.size()) + 4);
627         test(sm2->sentBytes - sm1->sentBytes == replySz);
628 
629         props["IceMX.Metrics.View.Map.Connection.GroupBy"] = "state";
630         updateProps(clientProps, serverProps, update.get(), props, "Connection");
631 
632         map = toMap(serverMetrics->getMetricsView("View", timestamp)["Connection"]);
633         test(map["active"]->current == 1);
634         map = toMap(clientMetrics->getMetricsView("View", timestamp)["Connection"]);
635         test(map["active"]->current == 1);
636 
637         Ice::ObjectPrxPtr cprx = communicator->stringToProxy("controller:" + helper->getTestEndpoint(1));
638         ControllerPrxPtr controller = ICE_CHECKED_CAST(ControllerPrx, cprx);
639         controller->hold();
640 
641         map = toMap(clientMetrics->getMetricsView("View", timestamp)["Connection"]);
642         test(map["active"]->current == 1);
643         map = toMap(serverMetrics->getMetricsView("View", timestamp)["Connection"]);
644         test(map["holding"]->current == 1);
645 
646         metrics->ice_getConnection()->close(Ice::ICE_SCOPED_ENUM(ConnectionClose, GracefullyWithWait));
647 
648         map = toMap(clientMetrics->getMetricsView("View", timestamp)["Connection"]);
649         test(map["closing"]->current == 1);
650         map = toMap(serverMetrics->getMetricsView("View", timestamp)["Connection"]);
651         test(map["holding"]->current == 1);
652 
653         controller->resume();
654 
655         map = toMap(serverMetrics->getMetricsView("View", timestamp)["Connection"]);
656         test(map["holding"]->current == 0);
657 
658         props["IceMX.Metrics.View.Map.Connection.GroupBy"] = "none";
659         updateProps(clientProps, serverProps, update.get(), props, "Connection");
660 
661         metrics->ice_getConnection()->close(Ice::ICE_SCOPED_ENUM(ConnectionClose, GracefullyWithWait));
662 
663         metrics->ice_timeout(500)->ice_ping();
664         controller->hold();
665         try
666         {
667             Ice::ByteSeq seq;
668             seq.resize(10000000);
669             metrics->ice_timeout(500)->opByteS(seq);
670             test(false);
671         }
672         catch(const Ice::TimeoutException&)
673         {
674         }
675         controller->resume();
676 
677         cm1 = ICE_DYNAMIC_CAST(IceMX::ConnectionMetrics, clientMetrics->getMetricsView("View", timestamp)["Connection"][0]);
678         while(true)
679         {
680             sm1 = ICE_DYNAMIC_CAST(IceMX::ConnectionMetrics,
681                                    serverMetrics->getMetricsView("View", timestamp)["Connection"][0]);
682             if(sm1->failures >= 2)
683             {
684                 break;
685             }
686             IceUtil::ThreadControl::sleep(IceUtil::Time::milliSeconds(10));
687         }
688         test(cm1->failures == 2 && sm1->failures >= 2);
689 
690         checkFailure(clientMetrics, "Connection", cm1->id, "::Ice::TimeoutException", 1);
691         checkFailure(clientMetrics, "Connection", cm1->id, "::Ice::ConnectTimeoutException", 1);
692         checkFailure(serverMetrics, "Connection", sm1->id, "::Ice::ConnectionLostException");
693 
694         MetricsPrxPtr m = metrics->ice_timeout(500)->ice_connectionId("Con1");
695         m->ice_ping();
696 
697         testAttribute(clientMetrics, clientProps, update.get(), "Connection", "parent", "Communicator");
698         //testAttribute(clientMetrics, clientProps, update.get(), "Connection", "id", "");
699         testAttribute(clientMetrics, clientProps, update.get(), "Connection", "endpoint", endpoint + " -t 500");
700         testAttribute(clientMetrics, clientProps, update.get(), "Connection", "endpointType", type);
701         testAttribute(clientMetrics, clientProps, update.get(), "Connection", "endpointIsDatagram", "false");
702         testAttribute(clientMetrics, clientProps, update.get(), "Connection", "endpointIsSecure", isSecure);
703         testAttribute(clientMetrics, clientProps, update.get(), "Connection", "endpointTimeout", "500");
704         testAttribute(clientMetrics, clientProps, update.get(), "Connection", "endpointCompress", "false");
705         testAttribute(clientMetrics, clientProps, update.get(), "Connection", "endpointHost", host);
706         testAttribute(clientMetrics, clientProps, update.get(), "Connection", "endpointPort", port);
707 
708         testAttribute(clientMetrics, clientProps, update.get(), "Connection", "incoming", "false");
709         testAttribute(clientMetrics, clientProps, update.get(), "Connection", "adapterName", "");
710         testAttribute(clientMetrics, clientProps, update.get(), "Connection", "connectionId", "Con1");
711         if (!inFreeBSDJail())
712         {
713             testAttribute(clientMetrics, clientProps, update.get(), "Connection", "localHost", host);
714             //testAttribute(clientMetrics, clientProps, update.get(), "Connection", "localPort", "");
715             testAttribute(clientMetrics, clientProps, update.get(), "Connection", "remoteHost", host);
716         }
717         testAttribute(clientMetrics, clientProps, update.get(), "Connection", "remotePort", port);
718         testAttribute(clientMetrics, clientProps, update.get(), "Connection", "mcastHost", "");
719         testAttribute(clientMetrics, clientProps, update.get(), "Connection", "mcastPort", "");
720 
721         m->ice_getConnection()->close(Ice::ICE_SCOPED_ENUM(ConnectionClose, GracefullyWithWait));
722 
723         waitForCurrent(clientMetrics, "View", "Connection", 0);
724         waitForCurrent(serverMetrics, "View", "Connection", 0);
725 
726         cout << "ok" << endl;
727 
728         cout << "testing connection establishment metrics... " << flush;
729 
730         props["IceMX.Metrics.View.Map.ConnectionEstablishment.GroupBy"] = "id";
731         updateProps(clientProps, serverProps, update.get(), props, "ConnectionEstablishment");
732         test(clientMetrics->getMetricsView("View", timestamp)["ConnectionEstablishment"].empty());
733 
734         metrics->ice_ping();
735 
736         test(clientMetrics->getMetricsView("View", timestamp)["ConnectionEstablishment"].size() == 1);
737         IceMX::MetricsPtr m1 = clientMetrics->getMetricsView("View", timestamp)["ConnectionEstablishment"][0];
738         test(m1->current == 0 && m1->total == 1 && m1->id == hostAndPort);
739 
740         metrics->ice_getConnection()->close(Ice::ICE_SCOPED_ENUM(ConnectionClose, GracefullyWithWait));
741         controller->hold();
742         try
743         {
744             communicator->stringToProxy("test:" + endpoint)->ice_timeout(10)->ice_ping();
745             test(false);
746         }
747         catch(const Ice::ConnectTimeoutException&)
748         {
749         }
750         catch(const Ice::LocalException&)
751         {
752             test(false);
753         }
754         controller->resume();
755         test(clientMetrics->getMetricsView("View", timestamp)["ConnectionEstablishment"].size() == 1);
756         m1 = clientMetrics->getMetricsView("View", timestamp)["ConnectionEstablishment"][0];
757         test(m1->id == hostAndPort && m1->total == 3 && m1->failures == 2);
758 
759         checkFailure(clientMetrics, "ConnectionEstablishment", m1->id, "::Ice::ConnectTimeoutException", 2);
760 
761         Connect c(metrics);
762         testAttribute(clientMetrics, clientProps, update.get(), "ConnectionEstablishment", "parent", "Communicator", c);
763         testAttribute(clientMetrics, clientProps, update.get(), "ConnectionEstablishment", "id", hostAndPort, c);
764         testAttribute(clientMetrics, clientProps, update.get(), "ConnectionEstablishment", "endpoint",
765                       endpoint + " -t 60000", c);
766 
767         testAttribute(clientMetrics, clientProps, update.get(), "ConnectionEstablishment", "endpointType", type, c);
768         testAttribute(clientMetrics, clientProps, update.get(), "ConnectionEstablishment", "endpointIsDatagram", "false", c);
769         testAttribute(clientMetrics, clientProps, update.get(), "ConnectionEstablishment", "endpointIsSecure", isSecure, c);
770         testAttribute(clientMetrics, clientProps, update.get(), "ConnectionEstablishment", "endpointTimeout", "60000", c);
771         testAttribute(clientMetrics, clientProps, update.get(), "ConnectionEstablishment", "endpointCompress", "false", c);
772         testAttribute(clientMetrics, clientProps, update.get(), "ConnectionEstablishment", "endpointHost", host, c);
773         testAttribute(clientMetrics, clientProps, update.get(), "ConnectionEstablishment", "endpointPort", port, c);
774 
775         cout << "ok" << endl;
776 
777         //
778         // Ice doesn't do any endpoint lookup with UWP, the UWP
779         // runtime takes care of if.
780         //
781 #if !defined(ICE_OS_UWP) && TARGET_OS_IPHONE==0
782         cout << "testing endpoint lookup metrics... " << flush;
783 
784         props["IceMX.Metrics.View.Map.EndpointLookup.GroupBy"] = "id";
785         updateProps(clientProps, serverProps, update.get(), props, "EndpointLookup");
786         test(clientMetrics->getMetricsView("View", timestamp)["EndpointLookup"].empty());
787 
788         Ice::ObjectPrxPtr prx = communicator->stringToProxy("metrics:" + protocol + " -h localhost -t 500 -p " + port);
789         try
790         {
791             prx->ice_ping();
792             prx->ice_getConnection()->close(Ice::ICE_SCOPED_ENUM(ConnectionClose, GracefullyWithWait));
793         }
794         catch(const Ice::LocalException&)
795         {
796         }
797 
798         test(clientMetrics->getMetricsView("View", timestamp)["EndpointLookup"].size() == 1);
799         m1 = clientMetrics->getMetricsView("View", timestamp)["EndpointLookup"][0];
800         test(m1->current <= 1 && (m1->total == 1 || m1->total == 2));
801 
802         bool dnsException = false;
803         try
804         {
805             communicator->stringToProxy("test:tcp -t 500 -h unknownhost9999.example.org -p " + port)->ice_ping();
806             test(false);
807         }
808         catch(const Ice::DNSException&)
809         {
810             dnsException = true;
811         }
812         catch(const Ice::LocalException&)
813         {
814             // Some DNS servers don't fail on unknown DNS names.
815         }
816         test(clientMetrics->getMetricsView("View", timestamp)["EndpointLookup"].size() == 2);
817         m1 = clientMetrics->getMetricsView("View", timestamp)["EndpointLookup"][1];
818         test(m1->id == "tcp -h unknownhost9999.example.org -p " + port + " -t 500" && m1->total == 2 &&
819              (!dnsException || m1->failures == 2));
820         if(dnsException)
821         {
822             checkFailure(clientMetrics, "EndpointLookup", m1->id, "::Ice::DNSException", 2);
823         }
824 
825         c = Connect(prx);
826 
827         testAttribute(clientMetrics, clientProps, update.get(), "EndpointLookup", "parent", "Communicator", c);
828         testAttribute(clientMetrics, clientProps, update.get(), "EndpointLookup", "id",
829                       prx->ice_getConnection()->getEndpoint()->toString(), c);
830         testAttribute(clientMetrics, clientProps, update.get(), "EndpointLookup", "endpoint",
831                       prx->ice_getConnection()->getEndpoint()->toString(), c);
832 
833         testAttribute(clientMetrics, clientProps, update.get(), "EndpointLookup", "endpointType", type, c);
834         testAttribute(clientMetrics, clientProps, update.get(), "EndpointLookup", "endpointIsDatagram", "false", c);
835         testAttribute(clientMetrics, clientProps, update.get(), "EndpointLookup", "endpointIsSecure", isSecure, c);
836         testAttribute(clientMetrics, clientProps, update.get(), "EndpointLookup", "endpointTimeout", "500", c);
837         testAttribute(clientMetrics, clientProps, update.get(), "EndpointLookup", "endpointCompress", "false", c);
838         testAttribute(clientMetrics, clientProps, update.get(), "EndpointLookup", "endpointHost", "localhost", c);
839         testAttribute(clientMetrics, clientProps, update.get(), "EndpointLookup", "endpointPort", port, c);
840 
841         cout << "ok" << endl;
842 #endif
843     }
844 
845     cout << "testing dispatch metrics... " << flush;
846 
847     props["IceMX.Metrics.View.Map.Dispatch.GroupBy"] = "operation";
848     updateProps(clientProps, serverProps, update.get(), props, "Dispatch");
849     test(serverMetrics->getMetricsView("View", timestamp)["Dispatch"].empty());
850 
851     metrics->op();
852     try
853     {
854         metrics->opWithUserException();
855         test(false);
856     }
857     catch(const Test::UserEx&)
858     {
859     }
860     try
861     {
862         metrics->opWithRequestFailedException();
863         test(false);
864     }
865     catch(const Ice::RequestFailedException&)
866     {
867     }
868     try
869     {
870         metrics->opWithLocalException();
871         test(false);
872     }
873     catch(const Ice::LocalException&)
874     {
875     }
876     try
877     {
878         metrics->opWithUnknownException();
879         test(false);
880     }
881     catch(const Ice::UnknownException&)
882     {
883     }
884     if(!collocated)
885     {
886         try
887         {
888             metrics->fail();
889             test(false);
890         }
891         catch(const Ice::ConnectionLostException&)
892         {
893         }
894     }
895 
896     map = toMap(serverMetrics->getMetricsView("View", timestamp)["Dispatch"]);
897     if(!collocated)
898     {
899         test(map.size() == 6);
900     }
901     else
902     {
903         test(map.size() == 5);
904     }
905 
906     IceMX::DispatchMetricsPtr dm1 = ICE_DYNAMIC_CAST(IceMX::DispatchMetrics, map["op"]);
907     test(dm1->current <= 1 && dm1->total == 1 && dm1->failures == 0 && dm1->userException == 0);
908     test(dm1->size == 21 && dm1->replySize == 7);
909 
910     dm1 = ICE_DYNAMIC_CAST(IceMX::DispatchMetrics, map["opWithUserException"]);
911     test(dm1->current <= 1 && dm1->total == 1 && dm1->failures == 0 && dm1->userException == 1);
912     test(dm1->size == 38 && dm1->replySize == 23);
913 
914     dm1 = ICE_DYNAMIC_CAST(IceMX::DispatchMetrics, map["opWithLocalException"]);
915     test(dm1->current <= 1 && dm1->total == 1 && dm1->failures == 1 && dm1->userException == 0);
916     checkFailure(serverMetrics, "Dispatch", dm1->id, "::Ice::SyscallException", 1);
917     test(dm1->size == 39 && dm1->replySize > 7); // Reply contains the exception stack depending on the OS.
918 
919     dm1 = ICE_DYNAMIC_CAST(IceMX::DispatchMetrics, map["opWithRequestFailedException"]);
920     test(dm1->current <= 1 && dm1->total == 1 && dm1->failures == 1 && dm1->userException == 0);
921     checkFailure(serverMetrics, "Dispatch", dm1->id, "::Ice::ObjectNotExistException", 1);
922     test(dm1->size == 47 && dm1->replySize == 40);
923 
924     dm1 = ICE_DYNAMIC_CAST(IceMX::DispatchMetrics, map["opWithUnknownException"]);
925     test(dm1->current <= 1 && dm1->total == 1 && dm1->failures == 1 && dm1->userException == 0);
926     checkFailure(serverMetrics, "Dispatch", dm1->id, "unknown", 1);
927     test(dm1->size == 41 && dm1->replySize == 23);
928 
929     InvokeOp op(metrics);
930 
931     testAttribute(serverMetrics, serverProps, update.get(), "Dispatch", "parent", "TestAdapter", op);
932     testAttribute(serverMetrics, serverProps, update.get(), "Dispatch", "id", "metrics [op]", op);
933     if(!collocated)
934     {
935         testAttribute(serverMetrics, serverProps, update.get(), "Dispatch", "endpoint", endpoint + " -t 60000", op);
936         //testAttribute(serverMetrics, serverProps, update.get(), "Dispatch", "connection", "", op);
937 
938         testAttribute(serverMetrics, serverProps, update.get(), "Dispatch", "endpointType", type, op);
939         testAttribute(serverMetrics, serverProps, update.get(), "Dispatch", "endpointIsDatagram", "false", op);
940         testAttribute(serverMetrics, serverProps, update.get(), "Dispatch", "endpointIsSecure", isSecure, op);
941         testAttribute(serverMetrics, serverProps, update.get(), "Dispatch", "endpointTimeout", "60000", op);
942         testAttribute(serverMetrics, serverProps, update.get(), "Dispatch", "endpointCompress", "false", op);
943         testAttribute(serverMetrics, serverProps, update.get(), "Dispatch", "endpointHost", host, op);
944         testAttribute(serverMetrics, serverProps, update.get(), "Dispatch", "endpointPort", port, op);
945 
946         testAttribute(serverMetrics, serverProps, update.get(), "Dispatch", "incoming", "true", op);
947         testAttribute(serverMetrics, serverProps, update.get(), "Dispatch", "adapterName", "TestAdapter", op);
948         testAttribute(serverMetrics, serverProps, update.get(), "Dispatch", "connectionId", "", op);
949         if (!inFreeBSDJail())
950             testAttribute(serverMetrics, serverProps, update.get(), "Dispatch", "localHost", host, op);
951         testAttribute(serverMetrics, serverProps, update.get(), "Dispatch", "localPort", port, op);
952         if (!inFreeBSDJail())
953             testAttribute(serverMetrics, serverProps, update.get(), "Dispatch", "remoteHost", host, op);
954         //testAttribute(serverMetrics, serverProps, update.get(), "Dispatch", "remotePort", port, op);
955         testAttribute(serverMetrics, serverProps, update.get(), "Dispatch", "mcastHost", "", op);
956         testAttribute(serverMetrics, serverProps, update.get(), "Dispatch", "mcastPort", "", op);
957     }
958 
959     testAttribute(serverMetrics, serverProps, update.get(), "Dispatch", "operation", "op", op);
960     testAttribute(serverMetrics, serverProps, update.get(), "Dispatch", "identity", "metrics", op);
961     testAttribute(serverMetrics, serverProps, update.get(), "Dispatch", "facet", "", op);
962     testAttribute(serverMetrics, serverProps, update.get(), "Dispatch", "mode", "twoway", op);
963 
964     testAttribute(serverMetrics, serverProps, update.get(), "Dispatch", "context.entry1", "test", op);
965     testAttribute(serverMetrics, serverProps, update.get(), "Dispatch", "context.entry2", "", op);
966     testAttribute(serverMetrics, serverProps, update.get(), "Dispatch", "context.entry3", "", op);
967 
968     cout << "ok" << endl;
969 
970     cout << "testing invocation metrics... " << flush;
971 
972     props["IceMX.Metrics.View.Map.Invocation.GroupBy"] = "operation";
973     props["IceMX.Metrics.View.Map.Invocation.Map.Remote.GroupBy"] = "localPort";
974     props["IceMX.Metrics.View.Map.Invocation.Map.Collocated.GroupBy"] = "parent";
975     updateProps(clientProps, serverProps, update.get(), props, "Invocation");
976     test(serverMetrics->getMetricsView("View", timestamp)["Invocation"].empty());
977 
978     CallbackPtr cb = new Callback();
979     metrics->op();
980 #ifdef ICE_CPP11_MAPPING
981     try
982     {
983         metrics->opAsync().get();
984     }
985     catch(const Ice::Exception&)
986     {
987     }
988 
989     metrics->opAsync(
990         [cb]()
991         {
992             cb->response();
993         },
994         [cb](exception_ptr e)
995         {
996             try
997             {
998                 rethrow_exception(e);
999             }
1000             catch(const Ice::Exception& ex)
1001             {
1002                 cb->exception(ex);
1003             }
1004             catch(...)
1005             {
1006                 test(false);
1007             }
1008         });
1009 #else
1010     metrics->end_op(metrics->begin_op());
1011     metrics->begin_op(newCallback_Metrics_op(cb, &Callback::response, &Callback::exception));
1012 #endif
1013     cb->waitForResponse();
1014 
1015     // User exception
1016     try
1017     {
1018         metrics->opWithUserException();
1019         test(false);
1020     }
1021     catch(const Test::UserEx&)
1022     {
1023     }
1024 
1025 #ifdef ICE_CPP11_MAPPING
1026     try
1027     {
1028         metrics->opWithUserExceptionAsync().get();
1029         test(false);
1030     }
1031     catch(const Test::UserEx&)
1032     {
1033     }
1034     catch(...)
1035     {
1036         test(false);
1037     }
1038     metrics->opWithUserExceptionAsync(
1039         [cb]()
1040         {
1041             cb->response();
1042         },
1043         [cb](exception_ptr e)
1044         {
1045             try
1046             {
1047                 rethrow_exception(e);
1048             }
1049             catch(const Test::UserEx& ex)
1050             {
1051                 cb->exception(ex);
1052             }
1053             catch(...)
1054             {
1055                 test(false);
1056             }
1057         });
1058 #else
1059     try
1060     {
1061         metrics->end_opWithUserException(metrics->begin_opWithUserException());
1062         test(false);
1063     }
1064     catch(const Test::UserEx&)
1065     {
1066     }
1067     metrics->begin_opWithUserException(newCallback_Metrics_opWithUserException(
1068                                            cb, &Callback::response, &Callback::exception));
1069 #endif
1070     cb->waitForResponse();
1071 
1072     // Request failed exception
1073     try
1074     {
1075         metrics->opWithRequestFailedException();
1076         test(false);
1077     }
1078     catch(const Ice::RequestFailedException&)
1079     {
1080     }
1081 
1082 #ifdef ICE_CPP11_MAPPING
1083     try
1084     {
1085         metrics->opWithRequestFailedExceptionAsync().get();
1086         test(false);
1087     }
1088     catch(const Ice::RequestFailedException&)
1089     {
1090     }
1091     metrics->opWithRequestFailedExceptionAsync(
1092         [cb]()
1093         {
1094             cb->response();
1095         },
1096         [cb](exception_ptr e)
1097         {
1098             try
1099             {
1100                 rethrow_exception(e);
1101             }
1102             catch(const Ice::RequestFailedException& ex)
1103             {
1104                 cb->exception(ex);
1105             }
1106             catch(...)
1107             {
1108                 test(false);
1109             }
1110         });
1111 #else
1112     try
1113     {
1114         metrics->end_opWithRequestFailedException(metrics->begin_opWithRequestFailedException());
1115         test(false);
1116     }
1117     catch(const Ice::RequestFailedException&)
1118     {
1119     }
1120     metrics->begin_opWithRequestFailedException(newCallback_Metrics_opWithRequestFailedException(
1121                                                     cb, &Callback::response, &Callback::exception));
1122 #endif
1123     cb->waitForResponse();
1124 
1125     // Local exception
1126     try
1127     {
1128         metrics->opWithLocalException();
1129         test(false);
1130     }
1131     catch(const Ice::LocalException&)
1132     {
1133     }
1134 
1135 #ifdef ICE_CPP11_MAPPING
1136     try
1137     {
1138         metrics->opWithLocalExceptionAsync().get();
1139         test(false);
1140     }
1141     catch(const Ice::LocalException&)
1142     {
1143     }
1144     metrics->opWithLocalExceptionAsync(
1145         [cb]()
1146         {
1147             cb->response();
1148         },
1149         [cb](exception_ptr e)
1150         {
1151             try
1152             {
1153                 rethrow_exception(e);
1154             }
1155             catch(const Ice::LocalException& ex)
1156             {
1157                 cb->exception(ex);
1158             }
1159             catch(...)
1160             {
1161                 test(false);
1162             }
1163         });
1164 #else
1165     try
1166     {
1167         metrics->end_opWithLocalException(metrics->begin_opWithLocalException());
1168         test(false);
1169     }
1170     catch(const Ice::LocalException&)
1171     {
1172     }
1173     metrics->begin_opWithLocalException(newCallback_Metrics_opWithLocalException(
1174                                             cb, &Callback::response, &Callback::exception));
1175 #endif
1176     cb->waitForResponse();
1177 
1178     // Unknown exception
1179     try
1180     {
1181         metrics->opWithUnknownException();
1182         test(false);
1183     }
1184     catch(const Ice::UnknownException&)
1185     {
1186     }
1187 
1188 #ifdef ICE_CPP11_MAPPING
1189     try
1190     {
1191         metrics->opWithUnknownExceptionAsync().get();
1192         test(false);
1193     }
1194     catch(const Ice::UnknownException&)
1195     {
1196     }
1197     metrics->opWithUnknownExceptionAsync(
1198         [cb]()
1199         {
1200             cb->response();
1201         },
1202         [cb](exception_ptr e)
1203         {
1204             try
1205             {
1206                 rethrow_exception(e);
1207             }
1208             catch(const Ice::UnknownException& ex)
1209             {
1210                 cb->exception(ex);
1211             }
1212             catch(...)
1213             {
1214                 test(false);
1215             }
1216         });
1217 #else
1218     try
1219     {
1220         metrics->end_opWithUnknownException(metrics->begin_opWithUnknownException());
1221         test(false);
1222     }
1223     catch(const Ice::UnknownException&)
1224     {
1225     }
1226     metrics->begin_opWithUnknownException(newCallback_Metrics_opWithUnknownException(
1227                                               cb, &Callback::response, &Callback::exception));
1228 #endif
1229     cb->waitForResponse();
1230 
1231     // Fail
1232     if(!collocated)
1233     {
1234         try
1235         {
1236             metrics->fail();
1237             test(false);
1238         }
1239         catch(const Ice::ConnectionLostException&)
1240         {
1241         }
1242 #ifdef ICE_CPP11_MAPPING
1243         try
1244         {
1245             metrics->failAsync().get();
1246             test(false);
1247         }
1248         catch(const Ice::ConnectionLostException&)
1249         {
1250         }
1251         metrics->failAsync(
1252             [cb]()
1253             {
1254                 cb->response();
1255             },
1256             [cb](exception_ptr e)
1257             {
1258                 try
1259                 {
1260                     rethrow_exception(e);
1261                 }
1262                 catch(const Ice::ConnectionLostException& ex)
1263                 {
1264                     cb->exception(ex);
1265                 }
1266                 catch(...)
1267                 {
1268                     test(false);
1269                 }
1270             });
1271 #else
1272         try
1273         {
1274             metrics->end_fail(metrics->begin_fail());
1275             test(false);
1276         }
1277         catch(const Ice::ConnectionLostException&)
1278         {
1279         }
1280         metrics->begin_fail(newCallback_Metrics_fail(cb, &Callback::response, &Callback::exception));
1281 #endif
1282         cb->waitForResponse();
1283     }
1284     map = toMap(clientMetrics->getMetricsView("View", timestamp)["Invocation"]);
1285     test(collocated ? (map.size() == 5) : (map.size() == 6));
1286 
1287     IceMX::InvocationMetricsPtr im1;
1288     IceMX::ChildInvocationMetricsPtr rim1;
1289     im1 = ICE_DYNAMIC_CAST(IceMX::InvocationMetrics, map["op"]);
1290     test(im1->current <= 1 && im1->total == 3 && im1->failures == 0 && im1->retry == 0);
1291     test(collocated ? (im1->collocated.size() == 1) : (im1->remotes.size() == 1));
1292     rim1 = ICE_DYNAMIC_CAST(IceMX::ChildInvocationMetrics, collocated ? im1->collocated[0] : im1->remotes[0]);
1293     test(rim1->current == 0 && rim1->total == 3 && rim1->failures == 0);
1294     test(rim1->size == 63 && rim1->replySize == 21);
1295 
1296     im1 = ICE_DYNAMIC_CAST(IceMX::InvocationMetrics, map["opWithUserException"]);
1297     test(im1->current <= 1 && im1->total == 3 && im1->failures == 0 && im1->retry == 0);
1298     test(collocated ? (im1->collocated.size() == 1) : (im1->remotes.size() == 1));
1299     rim1 = ICE_DYNAMIC_CAST(IceMX::ChildInvocationMetrics, collocated ? im1->collocated[0] : im1->remotes[0]);
1300     test(rim1->current == 0 && rim1->total == 3 && rim1->failures == 0);
1301     test(rim1->size == 114 && rim1->replySize == 69);
1302     test(im1->userException == 3);
1303 
1304     im1 = ICE_DYNAMIC_CAST(IceMX::InvocationMetrics, map["opWithLocalException"]);
1305     test(im1->current <= 1 && im1->total == 3 && im1->failures == 3 && im1->retry == 0);
1306     test(collocated ? (im1->collocated.size() == 1) : (im1->remotes.size() == 1));
1307     rim1 = ICE_DYNAMIC_CAST(IceMX::ChildInvocationMetrics, collocated ? im1->collocated[0] : im1->remotes[0]);
1308     test(rim1->current == 0 && rim1->total == 3 && rim1->failures == 0);
1309     test(rim1->size == 117 && rim1->replySize > 7);
1310     checkFailure(clientMetrics, "Invocation", im1->id, "::Ice::UnknownLocalException", 3);
1311 
1312     im1 = ICE_DYNAMIC_CAST(IceMX::InvocationMetrics, map["opWithRequestFailedException"]);
1313     test(im1->current <= 1 && im1->total == 3 && im1->failures == 3 && im1->retry == 0);
1314     test(collocated ? (im1->collocated.size() == 1) : (im1->remotes.size() == 1));
1315     rim1 = ICE_DYNAMIC_CAST(IceMX::ChildInvocationMetrics, collocated ? im1->collocated[0] : im1->remotes[0]);
1316     test(rim1->current == 0 && rim1->total == 3 && rim1->failures == 0);
1317     test(rim1->size == 141 && rim1->replySize == 120);
1318     checkFailure(clientMetrics, "Invocation", im1->id, "::Ice::ObjectNotExistException", 3);
1319 
1320     im1 = ICE_DYNAMIC_CAST(IceMX::InvocationMetrics, map["opWithUnknownException"]);
1321     test(im1->current <= 1 && im1->total == 3 && im1->failures == 3 && im1->retry == 0);
1322     test(collocated ? (im1->collocated.size() == 1) : (im1->remotes.size() == 1));
1323     rim1 = ICE_DYNAMIC_CAST(IceMX::ChildInvocationMetrics, collocated ? im1->collocated[0] : im1->remotes[0]);
1324     test(rim1->current == 0 && rim1->total == 3 && rim1->failures == 0);
1325     test(rim1->size == 123 && rim1->replySize == 69);
1326     checkFailure(clientMetrics, "Invocation", im1->id, "::Ice::UnknownException", 3);
1327 
1328     if(!collocated)
1329     {
1330         im1 = ICE_DYNAMIC_CAST(IceMX::InvocationMetrics, map["fail"]);
1331         test(im1->current <= 1 && im1->total == 3 && im1->failures == 3 && im1->retry == 3 && im1->remotes.size() == 6);
1332         test(im1->remotes[0]->current == 0 && im1->remotes[0]->total == 1 && im1->remotes[0]->failures == 1);
1333         test(im1->remotes[1]->current == 0 && im1->remotes[1]->total == 1 && im1->remotes[1]->failures == 1);
1334         test(im1->remotes[2]->current == 0 && im1->remotes[2]->total == 1 && im1->remotes[2]->failures == 1);
1335         test(im1->remotes[3]->current == 0 && im1->remotes[3]->total == 1 && im1->remotes[3]->failures == 1);
1336         test(im1->remotes[4]->current == 0 && im1->remotes[4]->total == 1 && im1->remotes[4]->failures == 1);
1337         test(im1->remotes[5]->current == 0 && im1->remotes[5]->total == 1 && im1->remotes[5]->failures == 1);
1338         checkFailure(clientMetrics, "Invocation", im1->id, "::Ice::ConnectionLostException", 3);
1339     }
1340 
1341     testAttribute(clientMetrics, clientProps, update.get(), "Invocation", "parent", "Communicator", op);
1342     testAttribute(clientMetrics, clientProps, update.get(), "Invocation", "id", "metrics -t -e 1.1 [op]", op);
1343 
1344     testAttribute(clientMetrics, clientProps, update.get(), "Invocation", "operation", "op", op);
1345     testAttribute(clientMetrics, clientProps, update.get(), "Invocation", "identity", "metrics", op);
1346     testAttribute(clientMetrics, clientProps, update.get(), "Invocation", "facet", "", op);
1347     testAttribute(clientMetrics, clientProps, update.get(), "Invocation", "encoding", "1.1", op);
1348     testAttribute(clientMetrics, clientProps, update.get(), "Invocation", "mode", "twoway", op);
1349     testAttribute(clientMetrics, clientProps, update.get(), "Invocation", "proxy",
1350                   "metrics -t -e 1.1:" + endpoint + " -t 60000", op);
1351     testAttribute(clientMetrics, clientProps, update.get(), "Invocation", "context.entry1", "test", op);
1352     testAttribute(clientMetrics, clientProps, update.get(), "Invocation", "context.entry2", "", op);
1353     testAttribute(clientMetrics, clientProps, update.get(), "Invocation", "context.entry3", "", op);
1354 
1355     //
1356     // Tests with oneway
1357     //
1358     props["IceMX.Metrics.View.Map.Invocation.GroupBy"] = "operation";
1359     props["IceMX.Metrics.View.Map.Invocation.Map.Remote.GroupBy"] = "localPort";
1360     updateProps(clientProps, serverProps, update.get(), props, "Invocation");
1361 
1362     MetricsPrxPtr metricsOneway = metrics->ice_oneway();
1363     metricsOneway->op();
1364 #ifdef ICE_CPP11_MAPPING
1365     metricsOneway->opAsync().get();
1366     metricsOneway->opAsync(
1367         [cb]()
1368         {
1369             cb->response();
1370         },
1371         [cb](exception_ptr e)
1372         {
1373             try
1374             {
1375                 rethrow_exception(e);
1376             }
1377             catch(const Ice::Exception& ex)
1378             {
1379                 cb->exception(ex);
1380             }
1381             catch(...)
1382             {
1383                 test(false);
1384             }
1385         });
1386 #else
1387     metricsOneway->end_op(metricsOneway->begin_op());
1388     metricsOneway->begin_op(newCallback_Metrics_op(cb, &Callback::response, &Callback::exception));
1389 #endif
1390     map = toMap(clientMetrics->getMetricsView("View", timestamp)["Invocation"]);
1391     test(map.size() == 1);
1392 
1393     im1 = ICE_DYNAMIC_CAST(IceMX::InvocationMetrics, map["op"]);
1394     test(im1->current <= 1 && im1->total == 3 && im1->failures == 0 && im1->retry == 0);
1395     test(collocated ? (im1->collocated.size() == 1) : (im1->remotes.size() == 1));
1396     rim1 = ICE_DYNAMIC_CAST(IceMX::ChildInvocationMetrics, collocated ? im1->collocated[0] : im1->remotes[0]);
1397     test(rim1->current <= 1 && rim1->total == 3 && rim1->failures == 0);
1398     test(rim1->size == 63 && rim1->replySize == 0);
1399 
1400     testAttribute(clientMetrics, clientProps, update.get(), "Invocation", "mode", "oneway", InvokeOp(metricsOneway));
1401 
1402     //
1403     // Tests with batch oneway
1404     //
1405     props["IceMX.Metrics.View.Map.Invocation.GroupBy"] = "operation";
1406     props["IceMX.Metrics.View.Map.Invocation.Map.Remote.GroupBy"] = "localPort";
1407     updateProps(clientProps, serverProps, update.get(), props, "Invocation");
1408 
1409     MetricsPrxPtr metricsBatchOneway = metrics->ice_batchOneway();
1410     metricsBatchOneway->op();
1411 #ifdef ICE_CPP11_MAPPING
1412     metricsBatchOneway->opAsync().get();
1413     metricsBatchOneway->opAsync([cb]() {}, [cb](exception_ptr) {});
1414 #else
1415     metricsBatchOneway->end_op(metricsBatchOneway->begin_op());
1416     metricsBatchOneway->begin_op(newCallback_Metrics_op(cb, &Callback::response, &Callback::exception))->waitForCompleted();
1417 #endif
1418 
1419     map = toMap(clientMetrics->getMetricsView("View", timestamp)["Invocation"]);
1420     test(map.size() == 1);
1421 
1422     im1 = ICE_DYNAMIC_CAST(IceMX::InvocationMetrics, map["op"]);
1423     test(im1->current == 0 && im1->total == 3 && im1->failures == 0 && im1->retry == 0);
1424     test(im1->remotes.size() == 0);
1425 
1426     testAttribute(clientMetrics, clientProps, update.get(), "Invocation", "mode", "batch-oneway",
1427                   InvokeOp(metricsBatchOneway));
1428 
1429     //
1430     // Tests flushBatchRequests
1431     //
1432     props["IceMX.Metrics.View.Map.Invocation.GroupBy"] = "operation";
1433     props["IceMX.Metrics.View.Map.Invocation.Map.Remote.GroupBy"] = "localPort";
1434     updateProps(clientProps, serverProps, update.get(), props, "Invocation");
1435 
1436     metricsBatchOneway = metrics->ice_batchOneway();
1437     metricsBatchOneway->op();
1438 
1439     metricsBatchOneway->ice_flushBatchRequests();
1440 #ifdef ICE_CPP11_MAPPING
1441     metricsBatchOneway->ice_flushBatchRequestsAsync().get();
1442     metricsBatchOneway->ice_flushBatchRequestsAsync([cb](exception_ptr) {});
1443 #else
1444     metricsBatchOneway->end_ice_flushBatchRequests(metricsBatchOneway->begin_ice_flushBatchRequests());
1445     metricsBatchOneway->begin_ice_flushBatchRequests(
1446                     Ice::newCallback_Object_ice_flushBatchRequests(cb, &Callback::exception))->waitForCompleted();
1447 #endif
1448 
1449     map = toMap(clientMetrics->getMetricsView("View", timestamp)["Invocation"]);
1450     test(map.size() == 2);
1451 
1452     im1 = ICE_DYNAMIC_CAST(IceMX::InvocationMetrics, map["ice_flushBatchRequests"]);
1453     test(im1->current <= 1 && im1->total == 3 && im1->failures == 0 && im1->retry == 0);
1454     if(!collocated)
1455     {
1456         test(im1->remotes.size() == 1); // The first operation got sent over a connection
1457     }
1458 
1459     if(!collocated)
1460     {
1461         clearView(clientProps, serverProps, update.get());
1462 
1463         Ice::ConnectionPtr con = metricsBatchOneway->ice_getConnection();
1464 
1465         metricsBatchOneway = metricsBatchOneway->ice_fixed(con);
1466         metricsBatchOneway->op();
1467 
1468         con->flushBatchRequests(ICE_SCOPED_ENUM(Ice::CompressBatch, No));
1469 #ifdef ICE_CPP11_MAPPING
1470         con->flushBatchRequestsAsync(ICE_SCOPED_ENUM(Ice::CompressBatch, No)).get();
1471         con->flushBatchRequestsAsync(ICE_SCOPED_ENUM(Ice::CompressBatch, No), [cb](exception_ptr) {});
1472 #else
1473         con->end_flushBatchRequests(con->begin_flushBatchRequests(ICE_SCOPED_ENUM(Ice::CompressBatch, No)));
1474         con->begin_flushBatchRequests(ICE_SCOPED_ENUM(Ice::CompressBatch, No),
1475             Ice::newCallback_Connection_flushBatchRequests(cb, &Callback::exception))->waitForCompleted();
1476 #endif
1477         map = toMap(clientMetrics->getMetricsView("View", timestamp)["Invocation"]);
1478         test(map.size() == 3);
1479 
1480         im1 = ICE_DYNAMIC_CAST(IceMX::InvocationMetrics, map["flushBatchRequests"]);
1481         test(im1->current == 0 && im1->total == 3 && im1->failures == 0 && im1->retry == 0);
1482         test(im1->remotes.size() == 1); // The first operation got sent over a connection
1483 
1484         clearView(clientProps, serverProps, update.get());
1485         metricsBatchOneway->op();
1486 
1487         communicator->flushBatchRequests(ICE_SCOPED_ENUM(Ice::CompressBatch, No));
1488 #ifdef ICE_CPP11_MAPPING
1489         communicator->flushBatchRequestsAsync(ICE_SCOPED_ENUM(Ice::CompressBatch, No)).get();
1490         communicator->flushBatchRequestsAsync(ICE_SCOPED_ENUM(Ice::CompressBatch, No),
1491                                               [cb](exception_ptr) {});
1492 #else
1493         communicator->end_flushBatchRequests(
1494             communicator->begin_flushBatchRequests(ICE_SCOPED_ENUM(Ice::CompressBatch, No)));
1495         communicator->begin_flushBatchRequests(ICE_SCOPED_ENUM(Ice::CompressBatch, No),
1496             Ice::newCallback_Communicator_flushBatchRequests(cb, &Callback::exception))->waitForCompleted();
1497 #endif
1498         map = toMap(clientMetrics->getMetricsView("View", timestamp)["Invocation"]);
1499         test(map.size() == 2);
1500 
1501         im1 = ICE_DYNAMIC_CAST(IceMX::InvocationMetrics, map["flushBatchRequests"]);
1502         test(im1->current <= 1 && im1->total == 3 && im1->failures == 0 && im1->retry == 0);
1503         test(im1->remotes.size() == 1); // The first operation got sent over a connection
1504     }
1505     cout << "ok" << endl;
1506 
1507     cout << "testing metrics view enable/disable..." << flush;
1508 
1509     Ice::StringSeq disabledViews;
1510     props["IceMX.Metrics.View.GroupBy"] = "none";
1511     props["IceMX.Metrics.View.Disabled"] = "0";
1512     updateProps(clientProps, serverProps, update.get(), props, "Thread");
1513     test(!clientMetrics->getMetricsView("View", timestamp)["Thread"].empty());
1514     test(clientMetrics->getMetricsViewNames(disabledViews).size() == 1 && disabledViews.empty());
1515 
1516     props["IceMX.Metrics.View.Disabled"] = "1";
1517     updateProps(clientProps, serverProps, update.get(), props, "Thread");
1518     test(clientMetrics->getMetricsView("View", timestamp)["Thread"].empty());
1519     test(clientMetrics->getMetricsViewNames(disabledViews).empty() && disabledViews.size() == 1);
1520 
1521     clientMetrics->enableMetricsView("View");
1522     test(!clientMetrics->getMetricsView("View", timestamp)["Thread"].empty());
1523     test(clientMetrics->getMetricsViewNames(disabledViews).size() == 1 && disabledViews.empty());
1524 
1525     clientMetrics->disableMetricsView("View");
1526     test(clientMetrics->getMetricsView("View", timestamp)["Thread"].empty());
1527     test(clientMetrics->getMetricsViewNames(disabledViews).empty() && disabledViews.size() == 1);
1528 
1529     try
1530     {
1531         clientMetrics->enableMetricsView("UnknownView");
1532     }
1533     catch(const IceMX::UnknownMetricsView&)
1534     {
1535     }
1536 
1537     cout << "ok" << endl;
1538 
1539     cout << "testing instrumentation observer delegate... " << flush;
1540 
1541     test(obsv->threadObserver->getTotal() > 0);
1542     if(!collocated)
1543     {
1544         test(obsv->connectionObserver->getTotal() > 0);
1545         test(obsv->connectionEstablishmentObserver->getTotal() > 0);
1546 #if !defined(ICE_OS_UWP) && TARGET_OS_IPHONE==0
1547         test(obsv->endpointLookupObserver->getTotal() > 0);
1548 #endif
1549         test(obsv->invocationObserver->remoteObserver->getTotal() > 0);
1550     }
1551     else
1552     {
1553         test(obsv->invocationObserver->collocatedObserver->getTotal() > 0);
1554     }
1555     test(obsv->dispatchObserver->getTotal() > 0);
1556     test(obsv->invocationObserver->getTotal() > 0);
1557 
1558     test(obsv->threadObserver->getCurrent() > 0);
1559     if(!collocated)
1560     {
1561         test(obsv->connectionObserver->getCurrent() > 0);
1562         test(obsv->connectionEstablishmentObserver->getCurrent() == 0);
1563 #if !defined(ICE_OS_UWP) && TARGET_OS_IPHONE==0
1564         test(obsv->endpointLookupObserver->getCurrent() == 0);
1565 #endif
1566         waitForCurrent(obsv->invocationObserver->remoteObserver, 0);
1567         test(obsv->invocationObserver->remoteObserver->getCurrent() == 0);
1568     }
1569     else
1570     {
1571         waitForCurrent(obsv->invocationObserver->collocatedObserver, 0);
1572         test(obsv->invocationObserver->collocatedObserver->getCurrent() == 0);
1573     }
1574 
1575     waitForCurrent(obsv->dispatchObserver, 0);
1576     test(obsv->dispatchObserver->getCurrent() == 0);
1577 
1578     waitForCurrent(obsv->invocationObserver, 0);
1579     test(obsv->invocationObserver->getCurrent() == 0);
1580 
1581     test(obsv->threadObserver->getFailedCount() == 0);
1582     if(!collocated)
1583     {
1584         test(obsv->connectionObserver->getFailedCount() > 0);
1585         test(obsv->connectionEstablishmentObserver->getFailedCount() > 0);
1586 #if !defined(ICE_OS_UWP) && TARGET_OS_IPHONE==0
1587         test(obsv->endpointLookupObserver->getFailedCount() > 0);
1588 #endif
1589     }
1590     //test(obsv->dispatchObserver->getFailedCount() > 0);
1591     test(obsv->invocationObserver->getFailedCount() > 0);
1592     if(!collocated)
1593     {
1594         test(obsv->invocationObserver->remoteObserver->getFailedCount() > 0);
1595         test(obsv->threadObserver->states > 0);
1596     }
1597     if(!collocated)
1598     {
1599         test(obsv->connectionObserver->received > 0 && obsv->connectionObserver->sent > 0);
1600     }
1601     //test(obsv->dispatchObserver->userExceptionCount > 0);
1602     test(obsv->invocationObserver->userExceptionCount > 0);
1603     if(!collocated)
1604     {
1605         test(obsv->invocationObserver->retriedCount > 0);
1606         test(obsv->invocationObserver->remoteObserver->replySize > 0);
1607     }
1608     else
1609     {
1610         test(obsv->invocationObserver->collocatedObserver->replySize > 0);
1611     }
1612     cout << "ok" << endl;
1613 
1614     return metrics;
1615 }
1616