2009-06-12 Bill Holmes <billholmes54@gmail.com>
[mono.git] / mcs / class / System.ServiceModel / Test / System.ServiceModel.Description / ContractDescriptionTest.cs
1 //
2 // ContractDescriptionTest.cs
3 //
4 // Author:
5 //      Atsushi Enomoto <atsushi@ximian.com>
6 //
7 // Copyright (C) 2005 Novell, Inc.  http://www.novell.com
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 // 
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28 using System;
29 using System.Collections.ObjectModel;
30 using System.Net.Security;
31 using System.Reflection;
32 using System.ServiceModel;
33 using System.ServiceModel.Channels;
34 using System.ServiceModel.Description;
35 using NUnit.Framework;
36
37 namespace MonoTests.System.ServiceModel
38 {
39         [TestFixture]
40         public class ContractDescriptionTest
41         {
42                 [Test]
43                 [ExpectedException (typeof (InvalidOperationException))]
44                 public void GetNonContract ()
45                 {
46                         ContractDescription cd = ContractDescription.GetContract (
47                                 typeof (object));
48                 }
49
50                 [Test]
51                 public void GetContract ()
52                 {
53                         InternalTestGetContract (
54                                 ContractDescription.GetContract (typeof (IFoo)));
55                 }
56
57                 [Test]
58                 public void GetContractParamRenamed ()
59                 {
60                         ContractDescription cd = ContractDescription.GetContract (typeof (IFooMsgParams));
61
62                         Assert.AreEqual (1, cd.Operations.Count, "Operation count");
63
64                         // Operation #1
65                         OperationDescription od = cd.Operations [0];
66
67                         ServiceAssert.AssertOperationDescription (
68                                 "MyFoo", null, null, 
69                                 typeof (IFooMsgParams).GetMethod ("Foo"),
70                                 true, false, false,
71                                 od, "MyFoo");
72
73                         // Operation #1 -> Message #1
74                         MessageDescription md = od.Messages [0];
75
76                         ServiceAssert.AssertMessageAndBodyDescription (
77                                 "http://tempuri.org/IFooMsgParams/MyFoo",
78                                 MessageDirection.Input,
79                                 null, "MyFoo", "http://tempuri.org/", false,
80                                 md, "MyFoo");
81
82                         ServiceAssert.AssertMessagePartDescription (
83                                 "MyParam", "http://tempuri.org/", 0, false,
84                                 ProtectionLevel.None, typeof (string), md.Body.Parts [0], "MyFoo.msg");
85
86                         md = od.Messages [1];
87
88                         ServiceAssert.AssertMessageAndBodyDescription (
89                                 "http://tempuri.org/IFooMsgParams/MyFooResponse",
90                                 MessageDirection.Output,
91                                 null, "MyFooResponse",
92                                 "http://tempuri.org/", true,
93                                 md, "MyFoo");
94
95                         ServiceAssert.AssertMessagePartDescription (
96                                 "MyResult", "http://tempuri.org/", 0, false,
97                                 ProtectionLevel.None, typeof (string), md.Body.ReturnValue, "MyResult ReturnValue");
98                 }
99
100                 [Test]
101                 public void GetContractConfigName ()
102                 {
103                         ContractDescription cd = ContractDescription.GetContract (typeof (ICtorUseCase2));
104                         Assert.AreEqual("CtorUseCase2", cd.ConfigurationName);
105                         Assert.AreEqual("ICtorUseCase2", cd.Name);
106                         cd = ContractDescription.GetContract (typeof (ICtorUseCase1));
107                         Assert.AreEqual("MonoTests.System.ServiceModel.ICtorUseCase1", cd.ConfigurationName);
108                         Assert.AreEqual("ICtorUseCase1", cd.Name);
109                 }
110
111                 [Test]
112                 public void GetContract2 ()
113                 {
114                         InternalTestGetContract (
115                                 ContractDescription.GetContract (typeof (Foo)));
116                 }
117
118                 public void InternalTestGetContract (ContractDescription cd)
119                 {
120                         ServiceAssert.AssertContractDescription (
121                                 "IFoo", "http://tempuri.org/", SessionMode.Allowed, typeof (IFoo), null,
122                                 cd, "contract");
123
124                         Assert.AreEqual (2, cd.Operations.Count, "Operation count");
125
126                         // Operation #1
127                         OperationDescription od = cd.Operations [0];
128
129                         ServiceAssert.AssertOperationDescription (
130                                 "HeyDude", null, null, 
131                                 typeof (IFoo).GetMethod ("HeyDude"),
132                                 true, false, false,
133                                 od, "HeyDude");
134
135                         // Operation #1 -> Message #1
136                         MessageDescription md = od.Messages [0];
137
138                         ServiceAssert.AssertMessageAndBodyDescription (
139                                 "http://tempuri.org/IFoo/HeyDude",
140                                 MessageDirection.Input,
141                                 null, "HeyDude", "http://tempuri.org/", false,
142                                 md, "HeyDude");
143
144                         ServiceAssert.AssertMessagePartDescription (
145                                 "msg", "http://tempuri.org/", 0, false,
146                                 ProtectionLevel.None, typeof (string), md.Body.Parts [0], "HeyDude.msg");
147                         ServiceAssert.AssertMessagePartDescription (
148                                 "msg2", "http://tempuri.org/", 1, false,
149                                 ProtectionLevel.None, typeof (string), md.Body.Parts [1], "HeyDude.msg");
150
151                         // Operation #1 -> Message #2
152                         md = od.Messages [1];
153
154                         ServiceAssert.AssertMessageAndBodyDescription (
155                                 "http://tempuri.org/IFoo/HeyDudeResponse",
156                                 MessageDirection.Output,
157                                 null, "HeyDudeResponse",
158                                 "http://tempuri.org/", true,
159                                 md, "HeyDude");
160
161                         ServiceAssert.AssertMessagePartDescription (
162                                 "HeyDudeResult", "http://tempuri.org/", 0, false,
163                                 ProtectionLevel.None, typeof (string), md.Body.ReturnValue, "HeyDudeResponse ReturnValue");
164
165                         // Operation #2
166                         od = cd.Operations [1];
167
168                         ServiceAssert.AssertOperationDescription (
169                                 "HeyHey", null, null,
170                                 typeof (IFoo).GetMethod ("HeyHey"),
171                                 true, false, false,
172                                 od, "HeyHey");
173
174                         // Operation #2 -> Message #1
175                         md = od.Messages [0];
176
177                         ServiceAssert.AssertMessageAndBodyDescription (
178                                 "http://tempuri.org/IFoo/HeyHey",
179                                 MessageDirection.Input,
180                                 null, "HeyHey", "http://tempuri.org/", false,
181                                 md, "HeyHey");
182
183                         ServiceAssert.AssertMessagePartDescription (
184                                 "ref1", "http://tempuri.org/", 0, false,
185                                 ProtectionLevel.None, typeof (string), md.Body.Parts [0], "HeyHey.ref1");
186
187                         // Operation #2 -> Message #2
188                         md = od.Messages [1];
189
190                         ServiceAssert.AssertMessageAndBodyDescription (
191                                 "http://tempuri.org/IFoo/HeyHeyResponse",
192                                 MessageDirection.Output,
193                                 null, "HeyHeyResponse",
194                                 "http://tempuri.org/", true,
195                                 md, "HeyHey");
196
197                         ServiceAssert.AssertMessagePartDescription (
198                                 "HeyHeyResult", "http://tempuri.org/", 0, false,
199                                 ProtectionLevel.None, typeof (void), md.Body.ReturnValue, "HeyHeyResponse ReturnValue");
200
201                         ServiceAssert.AssertMessagePartDescription (
202                                 "out1", "http://tempuri.org/", 0, false,
203                                 ProtectionLevel.None, typeof (string), md.Body.Parts [0], "HeyHey.out1");
204                         ServiceAssert.AssertMessagePartDescription (
205                                 "ref1", "http://tempuri.org/", 1, false,
206                                 ProtectionLevel.None, typeof (string), md.Body.Parts [1], "HeyHey.ref1");
207                 }
208
209                 [Test]
210                 public void GetContractInherit ()
211                 {
212                         ContractDescription.GetContract (typeof (Foo));
213                 }
214
215                 [Test]
216                 [ExpectedException (typeof (InvalidOperationException))]
217                 public void GetMultipleServiceContract ()
218                 {
219                         ContractDescription.GetContract (typeof (FooBar));
220                 }
221
222                 [Test]
223                 // [ExpectedException (typeof (InvalidOperationException))]
224                 public void GetContractNoOperation ()
225                 {
226                         ContractDescription.GetContract (typeof (INoOperation));
227                 }
228
229                 [Test]
230                 [Category ("NotWorking")]
231                 public void GetContractMessageParameter ()
232                 {
233                         ContractDescription cd = ContractDescription.GetContract (typeof (IMessageParameter));
234
235                         ServiceAssert.AssertContractDescription (
236                                 "IMessageParameter", "http://tempuri.org/", 
237                                 SessionMode.Allowed, typeof (IMessageParameter), null,
238                                 cd, "contract");
239
240                         OperationDescription od = cd.Operations [0];
241
242                         ServiceAssert.AssertOperationDescription (
243                                 "ReturnMessage", null, null, 
244                                 typeof (IMessageParameter).GetMethod ("ReturnMessage"),
245                                 true, false, false,
246                                 od, "operation");
247
248                         MessageDescription md = od.Messages [0];
249
250                         ServiceAssert.AssertMessageAndBodyDescription (
251                                 "http://tempuri.org/IMessageParameter/ReturnMessage",
252                                 MessageDirection.Input,
253                                 // Body.WrapperName is null
254                                 null, null, null, false,
255                                 md, "ReturnMessage");
256
257                         ServiceAssert.AssertMessagePartDescription (
258                                 "arg", "http://tempuri.org/", 0, false,
259                                 ProtectionLevel.None, typeof (Message), md.Body.Parts [0], "ReturnMessage input");
260                 }
261
262                 [Test]
263                 [ExpectedException (typeof (InvalidOperationException))]
264                 public void GetContractInvalidAsync ()
265                 {
266                         ContractDescription.GetContract (typeof (IInvalidAsync));
267                 }
268
269                 [Test]
270                 // IMetadataExchange contains async patterns.
271                 public void GetContractIMetadataExchange ()
272                 {
273                         ContractDescription cd = ContractDescription.GetContract (typeof (IMetadataExchange));
274                         OperationDescription od = cd.Operations [0];
275                         Assert.AreEqual (2, od.Messages.Count, "premise: message count");
276                         foreach (MessageDescription md in od.Messages) {
277                                 if (md.Direction == MessageDirection.Input) {
278                                         Assert.AreEqual ("http://schemas.xmlsoap.org/ws/2004/09/transfer/Get", md.Action, "#1-1");
279                                         Assert.AreEqual (1, md.Body.Parts.Count, "#1-2");
280                                         Assert.IsNull (md.Body.ReturnValue, "#1-3");
281                                         Assert.AreEqual (typeof (Message), md.Body.Parts [0].Type, "#1-4");
282                                 } else {
283                                         Assert.AreEqual ("http://schemas.xmlsoap.org/ws/2004/09/transfer/GetResponse", md.Action, "#2-1");
284                                         Assert.AreEqual (0, md.Body.Parts.Count, "#2-2");
285                                         Assert.IsNotNull (md.Body.ReturnValue, "#2-3");
286                                         Assert.AreEqual (typeof (Message), md.Body.ReturnValue.Type, "#2-4");
287                                 }
288                         }
289                 }
290
291                 [Test]
292                 // enable it if we want to become a compatibility kid. It has
293                 // no ServiceContract, thus it should not be accepted. But
294                 // there is an abuse of ChannelFactory<IRequestChannel> in
295                 // MSDN documentations and probably examples.
296                 [Category ("NotWorking")]
297                 public void GetContractIRequestChannel ()
298                 {
299                         ContractDescription cd = ContractDescription.GetContract (typeof (IRequestChannel));
300                         Assert.AreEqual (typeof (IRequestChannel), cd.ContractType, "#_1");
301                         Assert.AreEqual ("IRequestChannel", cd.Name, "#_2");
302                         Assert.AreEqual ("http://schemas.microsoft.com/2005/07/ServiceModel", cd.Namespace, "#_3");
303                         Assert.AreEqual (false, cd.HasProtectionLevel, "#_4");
304                         Assert.AreEqual (SessionMode.NotAllowed, cd.SessionMode, "#_5");
305                         Assert.AreEqual (0, cd.Behaviors.Count, "#_6");
306                         Assert.AreEqual (1, cd.Operations.Count, "#_7");
307                         OperationDescription od = cd.Operations [0];
308                         Assert.IsNull (od.SyncMethod, "#_8");
309                         Assert.IsNull (od.BeginMethod, "#_9");
310                         Assert.IsNull (od.EndMethod, "#_10");
311                         Assert.AreEqual (false, od.IsOneWay, "#_11");
312                         Assert.AreEqual (false, od.HasProtectionLevel, "#_12");
313                         Assert.AreEqual ("Request", od.Name, "#_13");
314                         Assert.AreEqual (true, od.IsInitiating, "#_14");
315                         Assert.AreEqual (0, od.Behaviors.Count, "#_15");
316                         Assert.AreEqual (2, od.Messages.Count, "#_16");
317                         foreach (MessageDescription md in od.Messages) {
318                                 if (md.Direction == MessageDirection.Output) {
319                                         Assert.AreEqual ("*", md.Action, "#_17");
320                                         Assert.AreEqual (false, md.HasProtectionLevel, "#_18");
321                                         Assert.AreEqual (0, md.Headers.Count, "#_19");
322                                         Assert.AreEqual (0, md.Properties.Count, "#_20");
323                                         Assert.IsNull (md.MessageType, "#_21");
324                                         MessageBodyDescription mb = md.Body;
325                                         Assert.AreEqual (null, mb.WrapperName, "#_22");
326                                         Assert.AreEqual (null, mb.WrapperNamespace, "#_23");
327                                         Assert.IsNull (mb.ReturnValue, "#_24");
328                                         Assert.AreEqual (0, mb.Parts.Count, "#_25");
329                                 } else {
330                                         Assert.AreEqual ("*", md.Action, "#_17_");
331                                         Assert.AreEqual (false, md.HasProtectionLevel, "#_18_");
332                                         Assert.AreEqual (0, md.Headers.Count, "#_19_");
333                                         Assert.AreEqual (0, md.Properties.Count, "#_20_");
334                                         Assert.IsNull (md.MessageType, "#_21_");
335                                         MessageBodyDescription mb = md.Body;
336                                         Assert.AreEqual (null, mb.WrapperName, "#_22_");
337                                         Assert.AreEqual (null, mb.WrapperNamespace, "#_23_");
338                                         Assert.IsNull (mb.ReturnValue, "#_24_");
339                                         Assert.AreEqual (0, mb.Parts.Count, "#_25_");
340                                 }
341                         }
342                 }
343
344                 [Test]
345                 [ExpectedException (typeof (InvalidOperationException))]
346                 public void WrongAsyncEndContract ()
347                 {
348                         ContractDescription.GetContract (typeof (IWrongAsyncEndContract));
349                 }
350
351                 [Test]
352                 public void AsyncContract1 ()
353                 {
354                         ContractDescription cd =
355                                 ContractDescription.GetContract (typeof (IAsyncContract1));
356                         Assert.AreEqual (1, cd.Operations.Count);
357                         OperationDescription od = cd.Operations [0];
358                         Assert.AreEqual ("Sum", od.Name, "#1");
359                         Assert.IsNotNull (od.BeginMethod, "#2");
360                         Assert.IsNotNull (od.EndMethod, "#3");
361                 }
362
363                 [Test]
364                 [ExpectedException (typeof (InvalidOperationException))]
365                 public void DuplicateOperationNames ()
366                 {
367                         ContractDescription.GetContract (typeof (IDuplicateOperationNames));
368                 }
369
370                 [Test]
371                 [ExpectedException (typeof (InvalidOperationException))]
372                 public void AsyncMethodNameDoesNotStartWithBegin ()
373                 {
374                         ContractDescription.GetContract (typeof (IAsyncMethodNameDoesNotStartWithBegin));
375                 }
376
377                 [Test]
378                 [ExpectedException (typeof (InvalidOperationException))]
379                 public void AsyncNameDoesNotStartWithBeginButExplicitName ()
380                 {
381                         // it is still invalid ...
382                         ContractDescription.GetContract (typeof (IAsyncNameDoesNotStartWithBeginButExplicitName));
383                 }
384
385                 [Test]
386                 public void MessageBodyMemberIsNotInferred ()
387                 {
388                         ContractDescription cd = ContractDescription.GetContract (typeof (MessageBodyMemberIsNotInferredService));
389                         OperationDescription od = cd.Operations [0];
390                         MessageDescription md = od.Messages [0];
391                         Assert.AreEqual (0, md.Body.Parts.Count);
392                 }
393
394                 [Test]
395                 public void TestContractFromObject () {
396                         ContractDescription cd = ContractDescription.GetContract (typeof (Foo));
397                         ServiceAssert.AssertContractDescription (typeof (IFoo).Name, "http://tempuri.org/", SessionMode.Allowed, typeof (IFoo), null, cd, "#1");
398                         Assert.AreEqual (cd.Operations.Count, 2);
399                         OperationBehaviorAttribute op = cd.Operations.Find ("HeyHey").Behaviors.Find<OperationBehaviorAttribute> ();
400                         Assert.IsNotNull (op);
401                         Assert.AreEqual (
402                                 op.ReleaseInstanceMode,
403                                 ReleaseInstanceMode.None, "#2");
404
405                         cd = ContractDescription.GetContract (typeof (IFoo), typeof (Foo));
406                         ServiceAssert.AssertContractDescription (typeof (IFoo).Name, "http://tempuri.org/", SessionMode.Allowed, typeof (IFoo), null, cd, "#3");
407                         Assert.AreEqual (cd.Operations.Count, 2, "#4");
408                         Assert.AreEqual (
409                                 cd.Operations.Find ("HeyHey").Behaviors.Find<OperationBehaviorAttribute> ().ReleaseInstanceMode,
410                                 ReleaseInstanceMode.AfterCall, "#5");
411                 }
412
413                 // It is for testing attribute search in interfaces.
414                 public class Foo : IFoo
415                 {
416                         public string HeyDude (string msg, string msg2)
417                         {
418                                 return null;
419                         }
420
421                         [OperationBehavior (ReleaseInstanceMode = ReleaseInstanceMode.AfterCall)]
422                         public void HeyHey (out string out1, ref string ref1)
423                         {
424                                 out1 = null;
425                         }
426                 }
427
428                 // It inherits both IFoo and IBar, thus cannot be a contract.
429                 public class FooBar : IFoo, IBar
430                 {
431                         public string HeyDude (string msg, string msg2)
432                         {
433                                 return null;
434                         }
435                         
436                         public void HeyHey (out string out1, ref string ref1)
437                         {
438                                 out1 = null;
439                         }
440
441                         public void OpenBar () {}
442                 }
443
444                 [ServiceContract]
445                 public interface IFoo
446                 {
447                         [OperationContract]
448                         string HeyDude (string msg, string msg2);
449
450                         [OperationContract]
451                         void HeyHey (out string out1, ref string ref1);
452                 }
453
454                 [ServiceContract]
455                 public interface IFoo2
456                 {
457                         // FIXME: it does not pass yet
458                         [OperationContract]
459                         OregoMessage Nanoda (OregoMessage msg);
460
461                         // FIXME: it does not pass yet
462                         [OperationContract]
463                         OregoMessage Nanoda2 (OregoMessage msg1, OregoMessage msg2);
464
465                         // FIXME: it does not pass yet
466                         [OperationContract]
467                         Mona NewMona (Mona source);
468                 }
469
470                 [ServiceContract]
471                 public interface IBar
472                 {
473                         [OperationContract]
474                         void OpenBar ();
475                 }
476
477                 [MessageContract]
478                 public class OregoMessage
479                 {
480                         [MessageBodyMember]
481                         public string Neutral;
482                         [MessageBodyMember]
483                         public Assembly Huh;
484                         [MessageBodyMember] // it should be ignored ...
485                         public string Setter { set { } }
486                         public string NonMember;
487                 }
488
489                 public class Mona
490                 {
491                         public string OmaeMona;
492                         public string OreMona;
493                 }
494
495                 [ServiceContract]
496                 public interface INoOperation
497                 {
498                 }
499
500                 [ServiceContract]
501                 public interface IMessageParameter
502                 {
503                         [OperationContract]
504                         Message ReturnMessage (Message arg);
505                 }
506
507                 [ServiceContract]
508                 public interface IInvalidAsync
509                 {
510                         [OperationContract]
511                         Message ReturnMessage (Message arg);
512
513                         [OperationContract (AsyncPattern = true)]
514                         IAsyncResult BeginReturnMessage (Message arg, AsyncCallback callback, object state);
515
516                         // and no EndReturnMessage().
517                 }
518
519                 [ServiceContract]
520                 public interface IWrongAsyncEndContract
521                 {
522                         [OperationContract]
523                         int Sum (int a, int b);
524
525                         [OperationContract (AsyncPattern = true)]
526                         IAsyncResult BeginSum (int a, int b, AsyncCallback cb, object state);
527
528                         // this OperationContractAttribute is not allowed.
529                         [OperationContract (AsyncPattern = true)]
530                         int EndSum (IAsyncResult result);
531                 }
532
533                 [ServiceContract]
534                 public interface IAsyncContract1
535                 {
536                         [OperationContract]
537                         int Sum (int a, int b);
538
539                         [OperationContract (AsyncPattern = true)]
540                         IAsyncResult BeginSum (int a, int b, AsyncCallback cb, object state);
541
542                         int EndSum (IAsyncResult result);
543                 }
544
545                 [ServiceContract]
546                 public interface IAsyncMethodNameDoesNotStartWithBegin
547                 {
548                         [OperationContract]
549                         int Sum (int a, int b);
550
551                         [OperationContract (AsyncPattern = true)]
552                         IAsyncResult StartSum (int a, int b, AsyncCallback cb, object state);
553
554                         int EndSum (IAsyncResult result);
555                 }
556
557                 [ServiceContract]
558                 public interface IAsyncNameDoesNotStartWithBeginButExplicitName
559                 {
560                         [OperationContract]
561                         int Sum (int a, int b);
562
563                         [OperationContract (Name = "Sum", AsyncPattern = true)]
564                         IAsyncResult StartSum (int a, int b, AsyncCallback cb, object state);
565
566                         int EndSum (IAsyncResult result);
567                 }
568
569                 [ServiceContract]
570                 public interface IDuplicateOperationNames
571                 {
572                         [OperationContract]
573                         string Echo (string s);
574
575                         [OperationContract]
576                         string Echo (string s1, string s2);
577                 }
578
579                 [ServiceContract]
580                 public interface IFooMsgParams
581                 {
582                         [OperationContract (Name = "MyFoo")]
583                         [return: MessageParameter (Name = "MyResult")]
584                         string Foo ([MessageParameter (Name = "MyParam")] string param);
585                 }
586
587                 [ServiceContract]
588                 public class MessageBodyMemberIsNotInferredService
589                 {
590                         [OperationContract]
591                         public void Echo (MessageBodyMemberIsNotInferredContract msg)
592                         {
593                         }
594                 }
595
596                 [MessageContract]
597                 public class MessageBodyMemberIsNotInferredContract
598                 {
599                         string foo = "foo";
600                         public string Foo {
601                                 get { return foo; }
602                                 set { foo = value; }
603                         }
604                 }
605         }
606 }