Added tests for Task.WhenAll w/ empty list
[mono.git] / mcs / class / System.ServiceModel.Web / Test / System.ServiceModel.Dispatcher / WebHttpDispatchOperationSelectorTest.cs
1 //
2 // WebHttpDispatchOperationSelectorTest.cs
3 //
4 // Author:
5 //      Atsushi Enomoto  <atsushi@ximian.com>
6 //
7 // Copyright (C) 2008 Novell, Inc (http://www.novell.com)
8 // Copyright 2011 Xamarin Inc (http://www.xamarin.com).
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 // 
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 // 
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 //
29 using System;
30 using System.Globalization;
31 using System.Runtime.Serialization;
32 using System.ServiceModel;
33 using System.ServiceModel.Channels;
34 using System.ServiceModel.Description;
35 using System.ServiceModel.Dispatcher;
36 using System.ServiceModel.Web;
37 using System.Text;
38 using System.Xml;
39 using NUnit.Framework;
40
41 namespace MonoTests.System.ServiceModel.Dispatcher
42 {
43         [TestFixture]
44         public class WebHttpDispatchOperationSelectorTest
45         {
46                 [Test]
47                 [ExpectedException (typeof (ArgumentNullException))]
48                 public void ConstructorNullEndpoint ()
49                 {
50                         new WebHttpDispatchOperationSelector (null);
51                 }
52
53                 [Test]
54                 [ExpectedException (typeof (InvalidOperationException))]
55                 public void ConstructorEndpointNullAddress ()
56                 {
57                         ServiceEndpoint se = new ServiceEndpoint (ContractDescription.GetContract (typeof (MyService)));
58                         new WebHttpDispatchOperationSelector (se);
59                 }
60
61                 #region SelectOperation
62
63                 [Test]
64                 public void SelectOperation ()
65                 {
66                         SelectOperationCore (Create ());
67                 }
68
69                 [Test]
70                 public void SelectOperation2 ()
71                 {
72                         SelectOperationCore (Create2 ());
73                 }
74
75                 [Test]
76                 public void SelectOperation3 ()
77                 {
78                         ContractDescription cd = ContractDescription.GetContract (typeof (MyService2));
79                         Assert.IsNotNull (cd.Operations [0].Behaviors.Find<WebGetAttribute> (), "#1");
80
81                         cd = ContractDescription.GetContract (typeof (MyService));
82                         Assert.IsNull (cd.Operations [0].Behaviors.Find<WebGetAttribute> (), "#2");
83                 }
84
85                 void SelectOperationCore (MySelector d)
86                 {
87                         string name;
88                         var msg = Message.CreateMessage (MessageVersion.Soap12, "http://temuri.org/MyService/Echo"); // looks like Version is not checked
89                         Assert.IsNull (msg.Headers.To, "#1-0");
90                         Assert.IsFalse (d.SelectOperation (ref msg, out name), "#1");
91                         Assert.AreEqual ("", name, "#1-2");
92                         Assert.IsNull (msg.Headers.To, "#1-3"); // no overwrite
93                         Assert.IsFalse (msg.Properties.ContainsKey ("UriMatched"), "#1-4");
94
95                         msg = Message.CreateMessage (MessageVersion.None, "http://temuri.org/MyService/Echo");
96                         Assert.IsFalse (d.SelectOperation (ref msg, out name), "#2");
97                         Assert.IsFalse (msg.Properties.ContainsKey ("UriMatched"), "#2-2");
98
99                         msg = Message.CreateMessage (MessageVersion.None, "http://foobar.org/MyService/NonExistent");
100                         Assert.IsFalse (d.SelectOperation (ref msg, out name), "#3");
101                         Assert.AreEqual ("", name, "#3-2");
102                         Assert.IsFalse (msg.Properties.ContainsKey ("UriMatched"), "#3-3");
103
104                         // version and action do not matter
105                         msg = Message.CreateMessage (MessageVersion.Soap12, "http://nonexistent.org/");
106                         var http = new HttpRequestMessageProperty ();
107                         // this mismatch is allowed. Lack of this value is OK.
108 //                      http.Method = "POST";
109                         // this mismatch is allowed. Lack of this value is OK.
110 //                      http.QueryString = "foo=bar";
111                         // this mismatch is allowed. Lack of this value is OK.
112 //                      http.Headers.Add ("Content-Type", "application/json");
113                         // so, the http property can be empty, but is required.
114                         msg.Properties.Add (HttpRequestMessageProperty.Name, http);
115                         msg.Headers.To = new Uri ("http://localhost:8080/Echo?input=hoge");
116                         Assert.IsTrue (d.SelectOperation (ref msg, out name), "#4");
117                         // FIXME: hmm... isn'y "Echo" expected?
118                         // Assert.AreEqual ("", name, "#4-2");
119                 }
120
121                 [Test]
122                 [Category ("NotWorking")]
123                 public void SelectOperationOnlyMessage ()
124                 {
125                         // This test shows strange result ... it adds UriMatched property while it does not really match the URI.
126
127                         var d = Create ();
128                         var msg = Message.CreateMessage (MessageVersion.None, "http://temuri.org/MyService/Echo"); // looks like Version is not checked
129                         Assert.AreEqual ("", d.SelectOperation (ref msg), "#1");
130                         Assert.IsTrue (msg.Properties.ContainsKey ("UriMatched"), "#1-2");
131
132                         msg = Message.CreateMessage (MessageVersion.None, "http://foobar.org/MyService/NonExistent");
133                         Assert.AreEqual ("", d.SelectOperation (ref msg), "#2");
134                         Assert.IsNotNull (msg.Properties ["UriMatched"], "#2-2");
135                 }
136
137                 [Test]
138                 [ExpectedException (typeof (ArgumentException))]
139                 public void SelectOperationCheckExistingProperty ()
140                 {
141                         var d = Create ();
142                         var msg = Message.CreateMessage (MessageVersion.None, "http://temuri.org/MyService/Echo"); // heh, I mistyped it and turned to prove that Action does not matter.
143                         msg.Headers.To = new Uri ("http://localhost:8080/Echo");
144
145                         // LAMESPEC: .NET does returns String.Empty, while we return the name of the operation (as IOperationSelector.SelectOperation is expected to do!)
146                         // Assert.AreEqual (String.Empty, d.SelectOperation (ref msg), "#1");
147                         d.SelectOperation (ref msg);
148
149                         // The second invocation should raise the expected exception
150                         d.SelectOperation (ref msg);
151                 }
152
153                 // Types
154
155                 class MySelector : WebHttpDispatchOperationSelector
156                 {
157                         public MySelector (ServiceEndpoint se)
158                                 : base (se)
159                         {
160                         }
161
162                         public bool SelectOperation (ref Message msg, out string name)
163                         {
164                                 bool ret;
165                                 name = SelectOperation (ref msg, out ret);
166                                 return ret;
167                         }
168                 }
169
170                 class MyBehavior : WebHttpBehavior
171                 {
172                         public WebHttpDispatchOperationSelector GetPublicOperationSelector (ServiceEndpoint se)
173                         {
174                                 return GetOperationSelector (se);
175                         }
176
177                         protected override WebHttpDispatchOperationSelector GetOperationSelector (ServiceEndpoint se)
178                         {
179                                 return new MySelector (se);
180                         }
181                 }
182
183                 [ServiceContract]
184                 public interface MyService
185                 {
186                         [OperationContract]
187 //                      [WebGet (UriTemplate = "MyService/Echo?input={input}")]
188 //                      [WebGet] // UriTemplate = "Echo?input={input}"
189                         string Echo (string input);
190                 }
191
192                 [ServiceContract (Name = "MyService")]
193                 public interface MyService2
194                 {
195                         [OperationContract (Name = "Echo")]
196                         [WebGet] // UriTemplate = "Echo?input={input}"
197                         string Echo (string input);
198                 }
199
200                 MySelector Create ()
201                 {
202                         ServiceEndpoint se = new ServiceEndpoint (ContractDescription.GetContract (typeof (MyService)));
203                         se.Address = new EndpointAddress ("http://localhost:8080");
204                         se.Contract.Operations [0].Behaviors.Add (new WebGetAttribute ());
205                         return new MySelector (se);
206                         //var b = new MyBehavior ();
207                         //se.Behaviors.Add (b);
208                         //return (MySelector) b.GetPublicOperationSelector (se);
209                 }
210
211                 MySelector Create2 ()
212                 {
213                         ServiceEndpoint se = new ServiceEndpoint (ContractDescription.GetContract (typeof (MyService2)));
214                         se.Address = new EndpointAddress ("http://localhost:8080");
215                         //se.Contract.Operations [0].Behaviors.Add (new WebGetAttribute ());
216                         return new MySelector (se);
217                 }
218
219                 #endregion
220
221                 #region "bug #656020"
222
223                 [DataContract]
224                 public class User
225                 {
226                         [DataMember]
227                         public string Name { get; set; }
228                 }
229
230                 [ServiceContract]
231                 interface IHello
232                 {
233                         [WebGet(UriTemplate = "{name}?age={age}&blah={blah}")]
234                         [OperationContract]
235                         string SayHi (string name, int age, string blah);
236
237                         [WebInvoke(UriTemplate = "blah")]
238                         [OperationContract]
239                         string SayHi2 (User user);
240                 }
241
242                 class Hello : IHello
243                 {
244                         public string SayHi (string name, int age, string blah)
245                         {
246                                 return string.Format ("Hi {0}: {1}, {2}", name, age, blah == null);
247                         }
248                 
249                         public string SayHi2 (User user)
250                         {
251                                 return string.Format ("Hi {0}.", user.Name);
252                         }
253                 }
254
255                 [Test]
256                 public void WebMessageFormats ()
257                 {
258                         var host = new WebServiceHost (typeof (Hello));
259                         host.AddServiceEndpoint (typeof (IHello), new WebHttpBinding (), "http://localhost:37564/");
260                         host.Description.Behaviors.Find<ServiceDebugBehavior> ().IncludeExceptionDetailInFaults = true;
261                         host.Open ();
262                         try {
263                                 // run client
264                                 using (ChannelFactory<IHello> factory = new ChannelFactory<IHello> (new WebHttpBinding (), "http://localhost:37564/"))
265                                 {
266                                         factory.Endpoint.Behaviors.Add (new WebHttpBehavior ());
267                                         IHello h = factory.CreateChannel ();
268                                         //Console.WriteLine(h.SayHi("Joe", 42, null));
269                                         Assert.AreEqual ("Hi Joe.", h.SayHi2 (new User { Name = "Joe" }), "#1");
270                                 }
271                         } finally {
272                                 host.Close ();
273                         }
274                 }
275                 
276                 #endregion
277         }
278 }