b85b9f02f4cabc7f0e9893114b241ac472fe3dd0
[mono.git] / mcs / class / System.ServiceModel / Test / MetadataTests / BindingTestAssertions.cs
1 //
2 // BindingTestAssertions.cs
3 //
4 // Author:
5 //       Martin Baulig <martin.baulig@xamarin.com>
6 //
7 // Copyright (c) 2012 Xamarin Inc. (http://www.xamarin.com)
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining a copy
10 // of this software and associated documentation files (the "Software"), to deal
11 // in the Software without restriction, including without limitation the rights
12 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 // copies of the Software, and to permit persons to whom the Software is
14 // furnished to do so, subject to the following conditions:
15 //
16 // The above copyright notice and this permission notice shall be included in
17 // all copies or substantial portions of the Software.
18 //
19 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 // THE SOFTWARE.
26
27 using System;
28 using System.Net;
29 using System.Net.Security;
30 using System.Xml;
31 using System.Xml.XPath;
32 using System.Text;
33 using System.Collections.Generic;
34 using System.ServiceModel;
35 using System.ServiceModel.Security;
36 using System.ServiceModel.Channels;
37 using System.ServiceModel.Description;
38 using NUnit.Framework;
39 using NUnit.Framework.Constraints;
40 using NUnit.Framework.SyntaxHelpers;
41
42 using QName = System.Xml.XmlQualifiedName;
43 using WS = System.Web.Services.Description;
44
45 namespace MonoTests.System.ServiceModel.MetadataTests {
46
47         public static class BindingTestAssertions {
48
49                 const string WspNamespace = "http://schemas.xmlsoap.org/ws/2004/09/policy";
50                 const string WsuNamespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd";
51                 const string MsbNamespace = "http://schemas.microsoft.com/ws/06/2004/mspolicy/netbinary1";
52                 const string WsawNamespace = "http://www.w3.org/2006/05/addressing/wsdl";
53                 const string MsfNamespace = "http://schemas.microsoft.com/ws/2006/05/framing/policy";
54                 const string SpNamespace = "http://schemas.xmlsoap.org/ws/2005/07/securitypolicy";
55                 const string WsrmNamespace = "http://schemas.xmlsoap.org/ws/2005/02/rm/policy";
56                 const string HttpNamespace = "http://schemas.microsoft.com/ws/06/2004/policy/http";
57                 const string WsomaNamespace = "http://schemas.xmlsoap.org/ws/2004/09/policy/optimizedmimeserialization";
58                 const string Wsa10Namespace = "http://www.w3.org/2005/08/addressing";
59
60                 static readonly QName BinaryEncodingQName = new QName ("BinaryEncoding", MsbNamespace);
61                 static readonly QName UsingAddressingQName = new QName ("UsingAddressing", WsawNamespace);
62                 static readonly QName StreamedTransferQName = new QName ("Streamed", MsfNamespace);
63                 static readonly QName ReliableSessionQName = new QName ("RMAssertion", WsrmNamespace);
64                 static readonly QName TransportBindingQName = new QName ("TransportBinding", SpNamespace);
65                 static readonly QName AsymmetricBindingQName = new QName ("AsymmetricBinding", SpNamespace);
66                 static readonly QName SymmetricBindingQName = new QName ("SymmetricBinding", SpNamespace);
67                 static readonly QName EndorsingSupportingQName = new QName ("EndorsingSupportingTokens", SpNamespace);
68                 static readonly QName SignedSupportingQName = new QName ("SignedSupportingTokens", SpNamespace);
69                 static readonly QName Wss10QName = new QName ("Wss10", SpNamespace);
70                 static readonly QName Wss11QName = new QName ("Wss11", SpNamespace);
71                 static readonly QName Trust10QName = new QName ("Trust10", SpNamespace);
72                 static readonly QName NtlmAuthenticationQName = new QName ("NtlmAuthentication", HttpNamespace);
73                 static readonly QName MtomEncodingQName = new QName ("OptimizedMimeSerialization", WsomaNamespace);
74
75                 public static void CheckImportErrors (WsdlImporter importer, TestLabel label)
76                 {
77                         bool foundErrors = false;
78                         foreach (var error in importer.Errors) {
79                                 if (error.IsWarning)
80                                         Console.WriteLine ("WARNING ({0}): {1}", label, error.Message);
81                                 else {
82                                         Console.WriteLine ("ERROR ({0}): {1}", label, error.Message);
83                                         foundErrors = true;
84                                 }
85                         }
86
87                         if (foundErrors)
88                                 Assert.Fail ("Found import errors", label);
89                 }
90
91                 static void CheckSoapBinding (object extension, string transport, TestLabel label)
92                 {
93                         label.EnterScope ("soap");
94                         Assert.That (extension, Is.InstanceOfType (typeof (WS.SoapBinding)), label.Get ());
95                         var soap = (WS.SoapBinding)extension;
96                         Assert.That (soap.Style, Is.EqualTo (WS.SoapBindingStyle.Document), label.Get ());
97                         Assert.That (soap.Transport, Is.EqualTo (transport), label.Get ());
98                         Assert.That (soap.Required, Is.False, label.Get ());
99                         label.LeaveScope ();
100                 }
101
102                 public static void CheckBasicHttpBinding (
103                         Binding binding, string scheme, BasicHttpSecurityMode security,
104                         WSMessageEncoding encoding, HttpClientCredentialType clientCred,
105                         AuthenticationSchemes authScheme, TestLabel label)
106                 {
107                         label.EnterScope ("http");
108
109                         if (security == BasicHttpSecurityMode.Message) {
110                                 Assert.That (binding, Is.InstanceOfType (typeof(CustomBinding)), label.Get ());
111                         } else {
112                                 Assert.That (binding, Is.InstanceOfType (typeof(BasicHttpBinding)), label.Get ());
113                                 var basicHttp = (BasicHttpBinding)binding;
114                                 Assert.That (basicHttp.EnvelopeVersion, Is.EqualTo (EnvelopeVersion.Soap11), label.Get ());
115                                 Assert.That (basicHttp.MessageVersion, Is.EqualTo (MessageVersion.Soap11), label.Get ());
116                                 Assert.That (basicHttp.Scheme, Is.EqualTo (scheme), label.Get ());
117                                 Assert.That (basicHttp.TransferMode, Is.EqualTo (TransferMode.Buffered), label.Get ());
118                                 Assert.That (basicHttp.MessageEncoding, Is.EqualTo (encoding), label.Get ());
119                                 Assert.That (basicHttp.Security, Is.Not.Null, label.Get ());
120                                 Assert.That (basicHttp.Security.Mode, Is.EqualTo (security), label.Get ());
121                                 Assert.That (basicHttp.Security.Transport.ClientCredentialType, Is.EqualTo (clientCred), label.Get ());
122                                 Assert.That (basicHttp.Security.Message.AlgorithmSuite, Is.EqualTo (SecurityAlgorithmSuite.Basic256), label.Get ());
123                         }
124
125                         label.EnterScope ("elements");
126
127                         var elements = binding.CreateBindingElements ();
128                         Assert.That (elements, Is.Not.Null, label.Get ());
129                         if ((security == BasicHttpSecurityMode.Message) ||
130                                 (security == BasicHttpSecurityMode.TransportWithMessageCredential))
131                                 Assert.That (elements.Count, Is.EqualTo (3), label.Get ());
132                         else
133                                 Assert.That (elements.Count, Is.EqualTo (2), label.Get ());
134                         
135                         TextMessageEncodingBindingElement textElement = null;
136                         TransportSecurityBindingElement securityElement = null;
137                         HttpTransportBindingElement transportElement = null;
138                         AsymmetricSecurityBindingElement asymmSecurityElement = null;
139                         MtomMessageEncodingBindingElement mtomElement = null;
140                         
141                         foreach (var element in elements) {
142                                 if (element is TextMessageEncodingBindingElement)
143                                         textElement = (TextMessageEncodingBindingElement)element;
144                                 else if (element is HttpTransportBindingElement)
145                                         transportElement = (HttpTransportBindingElement)element;
146                                 else if (element is TransportSecurityBindingElement)
147                                         securityElement = (TransportSecurityBindingElement)element;
148                                 else if (element is AsymmetricSecurityBindingElement)
149                                         asymmSecurityElement = (AsymmetricSecurityBindingElement)element;
150                                 else if (element is MtomMessageEncodingBindingElement)
151                                         mtomElement = (MtomMessageEncodingBindingElement)element;
152                                 else
153                                         Assert.Fail (string.Format (
154                                                 "Unknown element: {0}", element.GetType ()), label.Get ());
155                         }
156
157                         label.EnterScope ("text");
158                         if (encoding == WSMessageEncoding.Text) {
159                                 Assert.That (textElement, Is.Not.Null, label.Get ());
160                                 Assert.That (textElement.WriteEncoding, Is.InstanceOfType (typeof(UTF8Encoding)), label.Get ());
161                         } else {
162                                 Assert.That (textElement, Is.Null, label.Get ());
163                         }
164                         label.LeaveScope ();
165
166                         label.EnterScope ("mtom");
167                         if (encoding == WSMessageEncoding.Mtom) {
168                                 Assert.That (mtomElement, Is.Not.Null, label.Get ());
169                         } else {
170                                 Assert.That (mtomElement, Is.Null, label.Get ());
171                         }
172                         label.LeaveScope ();
173
174                         label.EnterScope ("security");
175                         if (security == BasicHttpSecurityMode.TransportWithMessageCredential) {
176                                 Assert.That (securityElement, Is.Not.Null, label.Get ());
177                                 Assert.That (securityElement.SecurityHeaderLayout,
178                                              Is.EqualTo (SecurityHeaderLayout.Lax), label.Get ());
179                         } else {
180                                 Assert.That (securityElement, Is.Null, label.Get ());
181                         }
182                         label.LeaveScope ();
183
184                         label.EnterScope ("asymmetric");
185                         if (security == BasicHttpSecurityMode.Message) {
186                                 Assert.That (asymmSecurityElement, Is.Not.Null, label.Get ());
187                         } else {
188                                 Assert.That (asymmSecurityElement, Is.Null, label.Get ());
189                         }
190                         label.LeaveScope ();
191
192                         label.EnterScope ("transport");
193                         Assert.That (transportElement, Is.Not.Null, label.Get ());
194                         
195                         Assert.That (transportElement.Realm, Is.Empty, label.Get ());
196                         Assert.That (transportElement.Scheme, Is.EqualTo (scheme), label.Get ());
197                         Assert.That (transportElement.TransferMode, Is.EqualTo (TransferMode.Buffered), label.Get ());
198
199                         label.EnterScope ("auth");
200                         Assert.That (transportElement.AuthenticationScheme, Is.EqualTo (authScheme), label.Get ());
201                         label.LeaveScope (); // auth
202                         label.LeaveScope (); // transport
203                         label.LeaveScope (); // elements
204                         label.LeaveScope (); // http
205                 }
206
207                 static void CheckEndpoint (ServiceEndpoint endpoint, string uri, TestLabel label)
208                 {
209                         label.EnterScope ("endpoint");
210                         Assert.That (endpoint.ListenUri, Is.EqualTo (new Uri (uri)), label.Get ());
211                         Assert.That (endpoint.ListenUriMode, Is.EqualTo (ListenUriMode.Explicit), label.Get ());
212                         Assert.That (endpoint.Contract, Is.Not.Null, label.Get ());
213                         Assert.That (endpoint.Contract.Name, Is.EqualTo ("MyContract"), label.Get ());
214                         Assert.That (endpoint.Address, Is.Not.Null, label.Get ());
215                         Assert.That (endpoint.Address.Uri, Is.EqualTo (new Uri (uri)), label.Get ());
216                         Assert.That (endpoint.Address.Identity, Is.Null, label.Get ());
217                         Assert.That (endpoint.Address.Headers, Is.Not.Null, label.Get ());
218                         Assert.That (endpoint.Address.Headers.Count, Is.EqualTo (0), label.Get ());
219                         label.LeaveScope ();
220                 }
221
222                 public static void BasicHttpBinding (
223                         TestContext context, MetadataSet doc, WSMessageEncoding encoding, TestLabel label)
224                 {
225                         BasicHttpBinding (
226                                 context, doc, BasicHttpSecurityMode.None, encoding,
227                                 HttpClientCredentialType.None, AuthenticationSchemes.Anonymous,
228                                 label);
229                 }
230
231                 public static void BasicHttpBinding (
232                         TestContext context, MetadataSet doc, BasicHttpSecurityMode security, TestLabel label)
233                 {
234                         BasicHttpBinding (
235                                 context, doc, security, WSMessageEncoding.Text,
236                                 HttpClientCredentialType.None, AuthenticationSchemes.Anonymous,
237                                 label);
238                 }
239                 
240                 public static void BasicHttpBinding (
241                         TestContext context, MetadataSet doc, BasicHttpSecurityMode security,
242                         WSMessageEncoding encoding, HttpClientCredentialType clientCred,
243                         AuthenticationSchemes authScheme, TestLabel label)
244                 {
245                         label.EnterScope ("basicHttpBinding");
246                         BasicHttpBinding_inner (
247                                 context, doc, security, encoding, clientCred,
248                                 authScheme, false, label);
249                         label.LeaveScope ();
250                 }
251
252                 public static void BasicHttpsBinding (
253                         TestContext context, MetadataSet doc, BasicHttpSecurityMode security,
254                         WSMessageEncoding encoding, HttpClientCredentialType clientCred,
255                         AuthenticationSchemes authScheme, TestLabel label)
256                 {
257                         label.EnterScope ("basicHttpsBinding");
258                         BasicHttpBinding_inner (
259                                 context, doc, security, encoding, clientCred,
260                                 authScheme, true, label);
261                         label.LeaveScope ();
262                 }
263                 
264                 static void BasicHttpBinding_inner (
265                         TestContext context, MetadataSet doc, BasicHttpSecurityMode security,
266                         WSMessageEncoding encoding, HttpClientCredentialType clientCred,
267                         AuthenticationSchemes authScheme, bool isHttps, TestLabel label)
268                 {
269                         var sd = (WS.ServiceDescription)doc.MetadataSections [0].Metadata;
270
271                         label.EnterScope ("wsdl");
272                         label.EnterScope ("bindings");
273                         Assert.That (sd.Bindings.Count, Is.EqualTo (1), label.Get ());
274
275                         var binding = sd.Bindings [0];
276                         Assert.That (binding.ExtensibleAttributes, Is.Null, label.Get ());
277                         Assert.That (binding.Extensions, Is.Not.Null, label.Get ());
278
279                         bool hasPolicyXml;
280
281                         switch (security) {
282                         case BasicHttpSecurityMode.None:
283                                 if (isHttps)
284                                         throw new InvalidOperationException ();
285                                 hasPolicyXml = encoding == WSMessageEncoding.Mtom;
286                                 break;
287                         case BasicHttpSecurityMode.Message:
288                         case BasicHttpSecurityMode.Transport:
289                         case BasicHttpSecurityMode.TransportWithMessageCredential:
290                                 if (encoding == WSMessageEncoding.Mtom)
291                                         throw new InvalidOperationException ();
292                                 hasPolicyXml = true;
293                                 break;
294                         case BasicHttpSecurityMode.TransportCredentialOnly:
295                                 if (isHttps)
296                                         throw new InvalidOperationException ();
297                                 hasPolicyXml = true;
298                                 break;
299                         default:
300                                 throw new InvalidOperationException ();
301                         }
302                         label.LeaveScope ();
303
304                         WS.SoapBinding soap = null;
305                         XmlElement xml = null;
306
307                         foreach (var ext in binding.Extensions) {
308                                 if (ext is WS.SoapBinding)
309                                         soap = (WS.SoapBinding)ext;
310                                 else if (ext is XmlElement)
311                                         xml = (XmlElement)ext;
312                         }
313
314                         CheckSoapBinding (soap, WS.SoapBinding.HttpTransport, label);
315                         label.LeaveScope ();
316
317                         label.EnterScope ("policy-xml");
318                         if (!hasPolicyXml)
319                                 Assert.That (xml, Is.Null, label.Get ());
320                         else {
321                                 Assert.That (xml, Is.Not.Null, label.Get ());
322                                 var assertions = AssertPolicy (sd, xml, label);
323                                 Assert.That (assertions, Is.Not.Null, label.Get ());
324                                 if (clientCred == HttpClientCredentialType.Ntlm)
325                                         AssertPolicy (assertions, NtlmAuthenticationQName, label);
326                                 if (encoding == WSMessageEncoding.Mtom)
327                                         AssertPolicy (assertions, MtomEncodingQName, label);
328                                 switch (security) {
329                                 case BasicHttpSecurityMode.Message:
330                                         AssertPolicy (assertions, AsymmetricBindingQName, label);
331                                         AssertPolicy (assertions, Wss10QName, label);
332                                         break;
333                                 case BasicHttpSecurityMode.Transport:
334                                         AssertPolicy (assertions, TransportBindingQName, label);
335                                         break;
336                                 case BasicHttpSecurityMode.TransportWithMessageCredential:
337                                         AssertPolicy (assertions, SignedSupportingQName, label);
338                                         AssertPolicy (assertions, TransportBindingQName, label);
339                                         AssertPolicy (assertions, Wss10QName, label);
340                                         break;
341                                 default:
342                                         break;
343                                 }
344                                 Assert.That (assertions.Count, Is.EqualTo (0), label.Get ());
345                         }
346                         label.LeaveScope ();
347
348                         label.EnterScope ("services");
349                         Assert.That (sd.Services, Is.Not.Null, label.Get ());
350                         Assert.That (sd.Services.Count, Is.EqualTo (1), label.Get ());
351                         var service = sd.Services [0];
352                         Assert.That (service.Ports, Is.Not.Null, label.Get ());
353                         Assert.That (service.Ports.Count, Is.EqualTo (1), label.Get ());
354                         var port = service.Ports [0];
355                         
356                         label.EnterScope ("port");
357                         Assert.That (port.Extensions, Is.Not.Null, label.Get ());
358                         Assert.That (port.Extensions.Count, Is.EqualTo (1), label.Get ());
359                         
360                         WS.SoapAddressBinding soap_addr_binding = null;
361                         foreach (var extension in port.Extensions) {
362                                 if (extension is WS.SoapAddressBinding)
363                                         soap_addr_binding = (WS.SoapAddressBinding)extension;
364                                 else
365                                         Assert.Fail (label.Get ());
366                         }
367                         Assert.That (soap_addr_binding, Is.Not.Null, label.Get ());
368                         label.LeaveScope ();
369
370                         label.LeaveScope (); // wsdl
371
372                         var importer = new WsdlImporter (doc);
373
374                         label.EnterScope ("bindings");
375                         var bindings = importer.ImportAllBindings ();
376                         CheckImportErrors (importer, label);
377
378                         Assert.That (bindings, Is.Not.Null, label.Get ());
379                         Assert.That (bindings.Count, Is.EqualTo (1), label.Get ());
380
381                         string scheme;
382                         if ((security == BasicHttpSecurityMode.Transport) ||
383                             (security == BasicHttpSecurityMode.TransportWithMessageCredential))
384                                 scheme = "https";
385                         else
386                                 scheme = "http";
387
388                         CheckBasicHttpBinding (
389                                 bindings [0], scheme, security, encoding, clientCred,
390                                 authScheme, label);
391                         label.LeaveScope ();
392
393                         label.EnterScope ("endpoints");
394                         var endpoints = importer.ImportAllEndpoints ();
395                         CheckImportErrors (importer, label);
396
397                         Assert.That (endpoints, Is.Not.Null, label.Get ());
398                         Assert.That (endpoints.Count, Is.EqualTo (1), label.Get ());
399
400                         var uri = isHttps ? MetadataSamples.HttpsUri : MetadataSamples.HttpUri;
401
402                         CheckEndpoint (endpoints [0], uri, label);
403                         label.LeaveScope ();
404                 }
405
406                 public static void CheckNetTcpBinding (
407                         Binding binding, SecurityMode security, bool reliableSession,
408                         TransferMode transferMode, TestLabel label)
409                 {
410                         label.EnterScope ("net-tcp");
411                         if (security == SecurityMode.Message) {
412                                 Assert.That (binding, Is.InstanceOfType (typeof(CustomBinding)), label.Get ());
413                         } else {
414                                 Assert.That (binding, Is.InstanceOfType (typeof(NetTcpBinding)), label.Get ());
415                                 var netTcp = (NetTcpBinding)binding;
416                                 Assert.That (netTcp.EnvelopeVersion, Is.EqualTo (EnvelopeVersion.Soap12), label.Get ());
417                                 Assert.That (netTcp.MessageVersion, Is.EqualTo (MessageVersion.Soap12WSAddressing10), label.Get ());
418                                 Assert.That (netTcp.Scheme, Is.EqualTo ("net.tcp"), label.Get ());
419                                 Assert.That (netTcp.TransferMode, Is.EqualTo (transferMode), label.Get ());
420
421                                 label.EnterScope ("security");
422                                 Assert.That (netTcp.Security, Is.Not.Null, label.Get ());
423                                 Assert.That (netTcp.Security.Mode, Is.EqualTo (security), label.Get ());
424
425                                 Assert.That (netTcp.Security.Transport, Is.Not.Null, label.Get ());
426                                 Assert.That (netTcp.Security.Transport.ProtectionLevel, Is.EqualTo (ProtectionLevel.EncryptAndSign), label.Get ());
427                                 Assert.That (netTcp.Security.Transport.ClientCredentialType, Is.EqualTo (TcpClientCredentialType.Windows), label.Get ());
428                                 label.LeaveScope ();
429                         }
430
431                         label.EnterScope ("elements");
432                         
433                         var elements = binding.CreateBindingElements ();
434                         Assert.That (elements, Is.Not.Null, label.Get ());
435
436                         TcpTransportBindingElement transportElement = null;
437                         TransactionFlowBindingElement transactionFlowElement = null;
438                         BinaryMessageEncodingBindingElement encodingElement = null;
439                         WindowsStreamSecurityBindingElement windowsStreamElement = null;
440                         ReliableSessionBindingElement reliableSessionElement = null;
441                         TransportSecurityBindingElement transportSecurityElement = null;
442                         SslStreamSecurityBindingElement sslStreamElement = null;
443                         SymmetricSecurityBindingElement symmSecurityElement = null;
444                         
445                         foreach (var element in elements) {
446                                 if (element is TcpTransportBindingElement)
447                                         transportElement = (TcpTransportBindingElement)element;
448                                 else if (element is TransactionFlowBindingElement)
449                                         transactionFlowElement = (TransactionFlowBindingElement)element;
450                                 else if (element is BinaryMessageEncodingBindingElement)
451                                         encodingElement = (BinaryMessageEncodingBindingElement)element;
452                                 else if (element is WindowsStreamSecurityBindingElement)
453                                         windowsStreamElement = (WindowsStreamSecurityBindingElement)element;
454                                 else if (element is ReliableSessionBindingElement)
455                                         reliableSessionElement = (ReliableSessionBindingElement)element;
456                                 else if (element is TransportSecurityBindingElement)
457                                         transportSecurityElement = (TransportSecurityBindingElement)element;
458                                 else if (element is SslStreamSecurityBindingElement)
459                                         sslStreamElement = (SslStreamSecurityBindingElement)element;
460                                 else if (element is SymmetricSecurityBindingElement)
461                                         symmSecurityElement = (SymmetricSecurityBindingElement)element;
462                                 else
463                                         Assert.Fail (string.Format (
464                                                 "Unknown element `{0}'.", element.GetType ()), label.Get ());
465                         }
466
467                         label.EnterScope ("windows-stream");
468                         if (security == SecurityMode.Transport) {
469                                 Assert.That (windowsStreamElement, Is.Not.Null, label.Get ());
470                                 Assert.That (windowsStreamElement.ProtectionLevel, Is.EqualTo (ProtectionLevel.EncryptAndSign), label.Get ());
471                         } else {
472                                 Assert.That (windowsStreamElement, Is.Null, label.Get ());
473                         }
474                         label.LeaveScope ();
475
476                         label.EnterScope ("reliable-session");
477                         if (reliableSession) {
478                                 Assert.That (reliableSessionElement, Is.Not.Null, label.Get ());
479                         } else {
480                                 Assert.That (reliableSessionElement, Is.Null, label.Get ());
481                         }
482                         label.LeaveScope ();
483
484                         label.EnterScope ("encoding");
485                         Assert.That (encodingElement, Is.Not.Null, label.Get ());
486                         label.LeaveScope ();
487
488                         label.EnterScope ("transaction");
489                         if (security == SecurityMode.Message) {
490                                 Assert.That (transactionFlowElement, Is.Null, label.Get ());
491                         } else {
492                                 Assert.That (transactionFlowElement, Is.Not.Null, label.Get ());
493                         }
494                         label.LeaveScope ();
495
496                         label.EnterScope ("transport");
497                         Assert.That (transportElement, Is.Not.Null, label.Get ());
498
499                         Assert.That (transportElement.Scheme, Is.EqualTo ("net.tcp"), label.Get ());
500                         Assert.That (transportElement.TransferMode, Is.EqualTo (transferMode), label.Get ());
501                         label.LeaveScope (); // transport
502
503                         label.EnterScope ("security");
504                         switch (security) {
505                         case SecurityMode.None:
506                         case SecurityMode.Transport:
507                                 Assert.That (transportSecurityElement, Is.Null, label.Get ());
508                                 Assert.That (sslStreamElement, Is.Null, label.Get ());
509                                 Assert.That (symmSecurityElement, Is.Null, label.Get ());
510                                 break;
511                         case SecurityMode.TransportWithMessageCredential:
512                                 Assert.That (transportSecurityElement, Is.Not.Null, label.Get ());
513                                 Assert.That (sslStreamElement, Is.Not.Null, label.Get ());
514                                 Assert.That (symmSecurityElement, Is.Null, label.Get ());
515                                 break;
516                         case SecurityMode.Message:
517                                 Assert.That (transportSecurityElement, Is.Null, label.Get ());
518                                 Assert.That (sslStreamElement, Is.Null, label.Get ());
519                                 Assert.That (symmSecurityElement, Is.Not.Null, label.Get ());
520                                 break;
521                         default:
522                                 throw new InvalidOperationException ();
523                         }
524                         label.LeaveScope ();
525
526                         label.LeaveScope (); // elements
527                         label.LeaveScope (); // net-tcp
528                 }
529
530                 public static void NetTcpBinding (
531                         TestContext context, MetadataSet doc, SecurityMode security,
532                         bool reliableSession, TransferMode transferMode, TestLabel label)
533                 {
534                         label.EnterScope ("netTcpBinding");
535
536                         var sd = (WS.ServiceDescription)doc.MetadataSections [0].Metadata;
537
538                         label.EnterScope ("wsdl");
539
540                         label.EnterScope ("bindings");
541                         Assert.That (sd.Bindings.Count, Is.EqualTo (1), label.Get ());
542                         var binding = sd.Bindings [0];
543                         Assert.That (binding.ExtensibleAttributes, Is.Null, label.Get ());
544                         Assert.That (binding.Extensions, Is.Not.Null, label.Get ());
545
546                         WS.Soap12Binding soap = null;
547                         XmlElement xml = null;
548                         
549                         foreach (var ext in binding.Extensions) {
550                                 if (ext is WS.Soap12Binding)
551                                         soap = (WS.Soap12Binding)ext;
552                                 else if (ext is XmlElement)
553                                         xml = (XmlElement)ext;
554                         }
555                         
556                         CheckSoapBinding (soap, "http://schemas.microsoft.com/soap/tcp", label);
557
558                         label.EnterScope ("policy-xml");
559                         Assert.That (xml, Is.Not.Null, label.Get ());
560                         var assertions = AssertPolicy (sd, xml, label);
561                         Assert.That (assertions, Is.Not.Null, label.Get ());
562                         AssertPolicy (assertions, BinaryEncodingQName, label);
563                         AssertPolicy (assertions, UsingAddressingQName, label);
564                         if (transferMode == TransferMode.Streamed)
565                                 AssertPolicy (assertions, StreamedTransferQName, label);
566                         switch (security) {
567                         case SecurityMode.Message:
568                                 AssertPolicy (assertions, SymmetricBindingQName, label);
569                                 AssertPolicy (assertions, Wss11QName, label);
570                                 AssertPolicy (assertions, Trust10QName, label);
571                                 break;
572                         case SecurityMode.Transport:
573                                 AssertPolicy (assertions, TransportBindingQName, label);
574                                 break;
575                         case SecurityMode.TransportWithMessageCredential:
576                                 AssertPolicy (assertions, TransportBindingQName, label);
577                                 AssertPolicy (assertions, EndorsingSupportingQName, label);
578                                 AssertPolicy (assertions, Wss11QName, label);
579                                 AssertPolicy (assertions, Trust10QName, label);
580                                 break;
581                         default:
582                                 break;
583                         }
584                         if (reliableSession)
585                                 AssertPolicy (assertions, ReliableSessionQName, label);
586                         Assert.That (assertions.Count, Is.EqualTo (0), label.Get ());
587                         label.LeaveScope ();
588
589                         label.EnterScope ("services");
590                         Assert.That (sd.Services, Is.Not.Null, label.Get ());
591                         Assert.That (sd.Services.Count, Is.EqualTo (1), label.Get ());
592                         var service = sd.Services [0];
593                         Assert.That (service.Ports, Is.Not.Null, label.Get ());
594                         Assert.That (service.Ports.Count, Is.EqualTo (1), label.Get ());
595                         var port = service.Ports [0];
596
597                         label.EnterScope ("port");
598                         Assert.That (port.Extensions, Is.Not.Null, label.Get ());
599                         Assert.That (port.Extensions.Count, Is.EqualTo (2), label.Get ());
600
601                         WS.Soap12AddressBinding soap_addr_binding = null;
602                         XmlElement port_xml = null;
603                         foreach (var extension in port.Extensions) {
604                                 if (extension is WS.Soap12AddressBinding)
605                                         soap_addr_binding = (WS.Soap12AddressBinding)extension;
606                                 else if (extension is XmlElement)
607                                         port_xml = (XmlElement)extension;
608                                 else
609                                         Assert.Fail (label.Get ());
610                         }
611                         Assert.That (soap_addr_binding, Is.Not.Null, label.Get ());
612                         Assert.That (port_xml, Is.Not.Null, label.Get ());
613                         Assert.That (port_xml.NamespaceURI, Is.EqualTo (Wsa10Namespace), label.Get ());
614                         Assert.That (port_xml.LocalName, Is.EqualTo ("EndpointReference"), label.Get ());
615                         label.LeaveScope ();
616                         label.LeaveScope ();
617
618                         label.LeaveScope (); // wsdl
619
620                         var importer = new WsdlImporter (doc);
621
622                         label.EnterScope ("bindings");
623                         var bindings = importer.ImportAllBindings ();
624                         CheckImportErrors (importer, label);
625                         Assert.That (bindings, Is.Not.Null, label.Get ());
626                         Assert.That (bindings.Count, Is.EqualTo (1), label.Get ());
627                         
628                         CheckNetTcpBinding (
629                                 bindings [0], security, reliableSession,
630                                 transferMode, label);
631                         label.LeaveScope ();
632
633                         label.EnterScope ("endpoints");
634                         var endpoints = importer.ImportAllEndpoints ();
635                         CheckImportErrors (importer, label);
636                         Assert.That (endpoints, Is.Not.Null, label.Get ());
637                         Assert.That (endpoints.Count, Is.EqualTo (1), label.Get ());
638                         
639                         CheckEndpoint (endpoints [0], MetadataSamples.NetTcpUri, label);
640                         label.LeaveScope ();
641
642                         label.LeaveScope ();
643                 }
644
645                 public static void Dump (PolicyAssertionCollection assertions)
646                 {
647                         foreach (var assertion in assertions)
648                                 Console.WriteLine ("ASSERTION: {0}", assertion.OuterXml);
649                 }
650
651                 public static void AssertPolicy (
652                         PolicyAssertionCollection assertions, QName qname, TestLabel label)
653                 {
654                         var assertion = assertions.Find (qname.Name, qname.Namespace);
655                         label.EnterScope (qname.Name);
656                         Assert.That (assertion, Is.Not.Null, label.ToString ());
657                         assertions.Remove (assertion);
658                         label.LeaveScope ();
659                 }
660
661                 static XmlElement ResolvePolicy (WS.ServiceDescription sd, XmlElement policy)
662                 {
663                         if (policy.LocalName.Equals ("Policy"))
664                                 return policy;
665
666                         var uri = policy.GetAttribute ("URI");
667                         if (!uri.StartsWith ("#"))
668                                 return null;
669                         
670                         foreach (var sext in sd.Extensions) {
671                                 var sxml = sext as XmlElement;
672                                 if (sxml == null)
673                                         continue;
674                                 if (!sxml.NamespaceURI.Equals (WspNamespace))
675                                         continue;
676                                 if (!sxml.LocalName.Equals ("Policy"))
677                                         continue;
678                                 var id = sxml.GetAttribute ("Id", WsuNamespace);
679                                 if (uri.Substring (1).Equals (id))
680                                         return sxml;
681                         }
682
683                         return null;
684                 }
685
686                 public static PolicyAssertionCollection AssertPolicy (
687                         WS.Binding binding, TestLabel label)
688                 {
689                         label.EnterScope ("FindPolicy");
690                         XmlElement policy = null;
691                 
692                         foreach (var extension in binding.Extensions) {
693                                 var xml = extension as XmlElement;
694                                 if (xml == null)
695                                         continue;
696                                 Assert.That (policy, Is.Null, label.Get ());
697                                 policy = xml;
698                         }
699                         Assert.That (policy, Is.Not.Null, label.Get ());
700                         try {
701                                 return AssertPolicy (binding.ServiceDescription, policy, label);
702                         } finally {
703                                 label.LeaveScope ();
704                         }
705                 }
706
707                 static XmlElement AssertExactlyOneChildElement (XmlElement element)
708                 {
709                         XmlElement found = null;
710                         foreach (var node in element.ChildNodes) {
711                                 if (node is XmlWhitespace)
712                                         continue;
713                                 var e = node as XmlElement;
714                                 if (e == null)
715                                         return null;
716                                 if (found != null)
717                                         return null;
718                                 found = e;
719                         }
720
721                         return found;
722                 }
723                 
724                 public static PolicyAssertionCollection AssertPolicy (
725                         WS.ServiceDescription sd, XmlElement element, TestLabel label)
726                 {
727                         label.EnterScope ("wsp:Policy");
728                         Assert.That (element.NamespaceURI, Is.EqualTo (WspNamespace), label.Get ());
729                         Assert.That (element.LocalName, Is.EqualTo ("Policy") | Is.EqualTo ("PolicyReference"), label.Get ());
730
731                         var policy = ResolvePolicy (sd, element);
732                         Assert.That (policy, Is.Not.Null, label.Get ());
733
734                         label.EnterScope ("wsp:ExactlyOne");
735                         var exactlyOne = AssertExactlyOneChildElement (policy);
736                         Assert.That (exactlyOne, Is.Not.Null, label.Get ());
737                         Assert.That (exactlyOne.NamespaceURI, Is.EqualTo (WspNamespace), label.Get ());
738                         Assert.That (exactlyOne.LocalName, Is.EqualTo ("ExactlyOne"), label.Get ());
739                         label.LeaveScope ();
740
741                         label.EnterScope ("wsp:Any");
742                         var all = AssertExactlyOneChildElement (exactlyOne);
743                         Assert.That (all, Is.Not.Null, label.Get ());
744                         Assert.That (all.NamespaceURI, Is.EqualTo (WspNamespace), label.Get ());
745                         Assert.That (all.LocalName, Is.EqualTo ("All"), label.Get ());
746                         label.LeaveScope ();
747
748                         var collection = new PolicyAssertionCollection ();
749
750                         label.EnterScope ("assertions");
751                         foreach (var node in all.ChildNodes) {
752                                 if (node is XmlWhitespace)
753                                         continue;
754                                 Assert.That (node, Is.InstanceOfType (typeof (XmlElement)), label.ToString ());
755                                 collection.Add ((XmlElement)node);
756                         }
757                         label.LeaveScope ();
758
759                         label.LeaveScope ();
760
761                         return collection;
762                 }
763
764                 public static void TestOperation (MetadataSet metadata, bool soap12, TestLabel label)
765                 {
766                         label.EnterScope ("TestOperation");
767
768                         label.EnterScope ("metadata");
769                         WS.ServiceDescription sd = null;
770                         foreach (var ms in metadata.MetadataSections) {
771                                 if (!ms.Dialect.Equals ("http://schemas.xmlsoap.org/wsdl/"))
772                                         continue;
773                                 sd = ms.Metadata as WS.ServiceDescription;
774                         }
775                         Assert.That (sd, Is.Not.Null, label.Get ());
776                         Assert.That (sd.Bindings, Is.Not.Null, label.Get ());
777                         Assert.That (sd.Bindings.Count, Is.EqualTo (1), label.Get ());
778                         var binding = sd.Bindings [0];
779                         label.LeaveScope ();
780
781                         label.EnterScope ("operation");
782                         Assert.That (binding.Operations, Is.Not.Null, label.Get ());
783                         Assert.That (binding.Operations.Count, Is.EqualTo (1), label.Get ());
784                         var op = binding.Operations [0];
785
786                         Assert.That (op.Name, Is.EqualTo ("Hello"), label.Get ());
787                         Assert.That (op.ExtensibleAttributes, Is.Null, label.Get ());
788
789                         label.EnterScope ("extensions");
790                         Assert.That (op.Extensions, Is.Not.Null, label.Get ());
791                         Assert.That (op.Extensions.Count, Is.EqualTo (1), label.Get ());
792                         Assert.That (op.Extensions [0], Is.InstanceOfType (typeof (WS.SoapOperationBinding)), label.Get ());
793                         var soap = (WS.SoapOperationBinding)op.Extensions [0];
794                         TestSoap (soap, soap12, label);
795                         label.LeaveScope ();
796
797                         TestSoapMessage (op.Input, soap12, label);
798                         TestSoapMessage (op.Output, soap12, label);
799                         label.LeaveScope (); // operation
800
801                         label.LeaveScope ();
802                 }
803
804                 static void TestSoap (WS.SoapOperationBinding soap, bool soap12, TestLabel label)
805                 {
806                         label.EnterScope ("soap");
807                         var type = soap12 ? typeof (WS.Soap12OperationBinding) : typeof (WS.SoapOperationBinding);
808                         Assert.That (soap.GetType (), Is.EqualTo (type), label.Get ());
809                         Assert.That (soap.Style, Is.EqualTo (WS.SoapBindingStyle.Document), label.Get ());
810                         Assert.That (soap.SoapAction, Is.EqualTo ("http://tempuri.org/IMyContract/Hello"), label.Get ());
811                         Assert.That (soap.Required, Is.False, label.Get ());
812                         label.LeaveScope ();
813                 }
814
815                 static void TestSoapMessage (WS.MessageBinding binding, bool soap12, TestLabel label)
816                 {
817                         label.EnterScope (binding is WS.InputBinding ? "input" : "output");
818
819                         Assert.That (binding, Is.Not.Null, label.Get ());
820                         Assert.That (binding.Name, Is.Null, label.Get ());
821                         Assert.That (binding.ExtensibleAttributes, Is.Null, label.Get ());
822                         Assert.That (binding.Extensions, Is.Not.Null, label.Get ());
823                         Assert.That (binding.Extensions.Count, Is.EqualTo (1), label.Get ());
824                         Assert.That (binding.Extensions [0], Is.InstanceOfType (typeof (WS.SoapBodyBinding)), label.Get ());
825                         var body = (WS.SoapBodyBinding)binding.Extensions [0];
826                         TestSoapBody (body, soap12, label);
827                         label.LeaveScope ();
828                 }
829
830                 static void TestSoapBody (WS.SoapBodyBinding soap, bool soap12, TestLabel label)
831                 {
832                         label.EnterScope ("soap-body");
833                         var type = soap12 ? typeof (WS.Soap12BodyBinding) : typeof (WS.SoapBodyBinding);
834                         Assert.That (soap.GetType (), Is.EqualTo (type), label.Get ());
835                         Assert.That (soap.Encoding, Is.Empty, label.Get ());
836                         Assert.That (soap.Namespace, Is.Empty, label.Get ());
837                         Assert.That (soap.Parts, Is.Null, label.Get ());
838                         Assert.That (soap.Use, Is.EqualTo (WS.SoapBindingUse.Literal), label.Get ());
839                         label.LeaveScope ();
840                 }
841
842                 public static void AssertConfig (MetadataSet metadata, XmlDocument xml, TestLabel label)
843                 {
844                         label.EnterScope ("import");
845                         var importer = new WsdlImporter (metadata);
846                         var endpoints = importer.ImportAllEndpoints ();
847                         CheckImportErrors (importer, label);
848                         Assert.That (endpoints.Count, Is.AtLeast (1), label.Get ());
849                         label.LeaveScope ();
850
851                         var nav = xml.CreateNavigator ();
852
853                         // FIXME: Check endpoints.
854
855                         label.EnterScope ("endpoints");
856                         var endpointIter = nav.Select ("/configuration/system.serviceModel/client/endpoint");
857                         Assert.That (endpointIter.Count, Is.EqualTo (endpoints.Count), label.Get ());
858                         
859                         label.LeaveScope ();
860                 }
861         }
862 }