Merge pull request #2698 from esdrubal/iosxmlarray
[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 #if !MOBILE
30 using System;
31 using System.Globalization;
32 using System.Runtime.Serialization;
33 using System.ServiceModel;
34 using System.ServiceModel.Channels;
35 using System.ServiceModel.Description;
36 using System.ServiceModel.Dispatcher;
37 using System.ServiceModel.Web;
38 using System.Text;
39 using System.Xml;
40 using NUnit.Framework;
41
42 using MonoTests.Helpers;
43
44 namespace MonoTests.System.ServiceModel.Dispatcher
45 {
46         [TestFixture]
47         public class WebHttpDispatchOperationSelectorTest
48         {
49                 [Test]
50                 [ExpectedException (typeof (ArgumentNullException))]
51                 public void ConstructorNullEndpoint ()
52                 {
53                         new WebHttpDispatchOperationSelector (null);
54                 }
55
56                 [Test]
57                 [ExpectedException (typeof (InvalidOperationException))]
58                 public void ConstructorEndpointNullAddress ()
59                 {
60                         ServiceEndpoint se = new ServiceEndpoint (ContractDescription.GetContract (typeof (MyService)));
61                         new WebHttpDispatchOperationSelector (se);
62                 }
63
64                 #region SelectOperation
65
66                 [Test]
67                 public void SelectOperation ()
68                 {
69                         SelectOperationCore (Create ());
70                 }
71
72                 [Test]
73                 public void SelectOperation2 ()
74                 {
75                         SelectOperationCore (Create2 ());
76                 }
77
78                 [Test]
79                 public void SelectOperation3 ()
80                 {
81                         ContractDescription cd = ContractDescription.GetContract (typeof (MyService2));
82                         Assert.IsNotNull (cd.Operations [0].Behaviors.Find<WebGetAttribute> (), "#1");
83
84                         cd = ContractDescription.GetContract (typeof (MyService));
85                         Assert.IsNull (cd.Operations [0].Behaviors.Find<WebGetAttribute> (), "#2");
86                 }
87
88                 void SelectOperationCore (MySelector d)
89                 {
90                         string name;
91                         var msg = Message.CreateMessage (MessageVersion.Soap12, "http://temuri.org/MyService/Echo"); // looks like Version is not checked
92                         Assert.IsNull (msg.Headers.To, "#1-0");
93                         Assert.IsFalse (d.SelectOperation (ref msg, out name), "#1");
94                         Assert.AreEqual ("", name, "#1-2");
95                         Assert.IsNull (msg.Headers.To, "#1-3"); // no overwrite
96                         Assert.IsFalse (msg.Properties.ContainsKey ("UriMatched"), "#1-4");
97
98                         msg = Message.CreateMessage (MessageVersion.None, "http://temuri.org/MyService/Echo");
99                         Assert.IsFalse (d.SelectOperation (ref msg, out name), "#2");
100                         Assert.IsFalse (msg.Properties.ContainsKey ("UriMatched"), "#2-2");
101
102                         msg = Message.CreateMessage (MessageVersion.None, "http://foobar.org/MyService/NonExistent");
103                         Assert.IsFalse (d.SelectOperation (ref msg, out name), "#3");
104                         Assert.AreEqual ("", name, "#3-2");
105                         Assert.IsFalse (msg.Properties.ContainsKey ("UriMatched"), "#3-3");
106
107                         // version and action do not matter
108                         msg = Message.CreateMessage (MessageVersion.Soap12, "http://nonexistent.org/");
109                         var http = new HttpRequestMessageProperty ();
110                         // this mismatch is allowed. Lack of this value is OK.
111 //                      http.Method = "POST";
112                         // this mismatch is allowed. Lack of this value is OK.
113 //                      http.QueryString = "foo=bar";
114                         // this mismatch is allowed. Lack of this value is OK.
115 //                      http.Headers.Add ("Content-Type", "application/json");
116                         // so, the http property can be empty, but is required.
117                         msg.Properties.Add (HttpRequestMessageProperty.Name, http);
118                         msg.Headers.To = new Uri ("http://localhost:8080/Echo?input=hoge");
119                         Assert.IsTrue (d.SelectOperation (ref msg, out name), "#4");
120                         // FIXME: hmm... isn'y "Echo" expected?
121                         // Assert.AreEqual ("", name, "#4-2");
122                 }
123
124                 [Test]
125                 [Category ("NotWorking")]
126                 public void SelectOperationOnlyMessage ()
127                 {
128                         // This test shows strange result ... it adds UriMatched property while it does not really match the URI.
129
130                         var d = Create ();
131                         var msg = Message.CreateMessage (MessageVersion.None, "http://temuri.org/MyService/Echo"); // looks like Version is not checked
132                         Assert.AreEqual ("", d.SelectOperation (ref msg), "#1");
133                         Assert.IsTrue (msg.Properties.ContainsKey ("UriMatched"), "#1-2");
134
135                         msg = Message.CreateMessage (MessageVersion.None, "http://foobar.org/MyService/NonExistent");
136                         Assert.AreEqual ("", d.SelectOperation (ref msg), "#2");
137                         Assert.IsNotNull (msg.Properties ["UriMatched"], "#2-2");
138                 }
139
140                 [Test]
141                 [ExpectedException (typeof (ArgumentException))]
142                 public void SelectOperationCheckExistingProperty ()
143                 {
144                         var d = Create ();
145                         var msg = Message.CreateMessage (MessageVersion.None, "http://temuri.org/MyService/Echo"); // heh, I mistyped it and turned to prove that Action does not matter.
146                         msg.Headers.To = new Uri ("http://localhost:8080/Echo");
147
148                         // LAMESPEC: .NET does returns String.Empty, while we return the name of the operation (as IOperationSelector.SelectOperation is expected to do!)
149                         // Assert.AreEqual (String.Empty, d.SelectOperation (ref msg), "#1");
150                         d.SelectOperation (ref msg);
151
152                         // The second invocation should raise the expected exception
153                         d.SelectOperation (ref msg);
154                 }
155
156                 // Types
157
158                 class MySelector : WebHttpDispatchOperationSelector
159                 {
160                         public MySelector (ServiceEndpoint se)
161                                 : base (se)
162                         {
163                         }
164
165                         public bool SelectOperation (ref Message msg, out string name)
166                         {
167                                 bool ret;
168                                 name = SelectOperation (ref msg, out ret);
169                                 return ret;
170                         }
171                 }
172
173                 class MyBehavior : WebHttpBehavior
174                 {
175                         public WebHttpDispatchOperationSelector GetPublicOperationSelector (ServiceEndpoint se)
176                         {
177                                 return GetOperationSelector (se);
178                         }
179
180                         protected override WebHttpDispatchOperationSelector GetOperationSelector (ServiceEndpoint se)
181                         {
182                                 return new MySelector (se);
183                         }
184                 }
185
186                 [ServiceContract]
187                 public interface MyService
188                 {
189                         [OperationContract]
190 //                      [WebGet (UriTemplate = "MyService/Echo?input={input}")]
191 //                      [WebGet] // UriTemplate = "Echo?input={input}"
192                         string Echo (string input);
193                 }
194
195                 [ServiceContract (Name = "MyService")]
196                 public interface MyService2
197                 {
198                         [OperationContract (Name = "Echo")]
199                         [WebGet] // UriTemplate = "Echo?input={input}"
200                         string Echo (string input);
201                 }
202
203                 MySelector Create ()
204                 {
205                         ServiceEndpoint se = new ServiceEndpoint (ContractDescription.GetContract (typeof (MyService)));
206                         se.Address = new EndpointAddress ("http://localhost:8080");
207                         se.Contract.Operations [0].Behaviors.Add (new WebGetAttribute ());
208                         return new MySelector (se);
209                         //var b = new MyBehavior ();
210                         //se.Behaviors.Add (b);
211                         //return (MySelector) b.GetPublicOperationSelector (se);
212                 }
213
214                 MySelector Create2 ()
215                 {
216                         ServiceEndpoint se = new ServiceEndpoint (ContractDescription.GetContract (typeof (MyService2)));
217                         se.Address = new EndpointAddress ("http://localhost:8080");
218                         //se.Contract.Operations [0].Behaviors.Add (new WebGetAttribute ());
219                         return new MySelector (se);
220                 }
221
222                 #endregion
223
224                 #region "bug #656020"
225
226                 [DataContract]
227                 public class User
228                 {
229                         [DataMember]
230                         public string Name { get; set; }
231                 }
232
233                 [ServiceContract]
234                 interface IHello
235                 {
236                         [WebGet(UriTemplate = "{name}?age={age}&blah={blah}")]
237                         [OperationContract]
238                         string SayHi (string name, int age, string blah);
239
240                         [WebInvoke(UriTemplate = "blah")]
241                         [OperationContract]
242                         string SayHi2 (User user);
243                 }
244
245                 class Hello : IHello
246                 {
247                         public string SayHi (string name, int age, string blah)
248                         {
249                                 return string.Format ("Hi {0}: {1}, {2}", name, age, blah == null);
250                         }
251                 
252                         public string SayHi2 (User user)
253                         {
254                                 return string.Format ("Hi {0}.", user.Name);
255                         }
256                 }
257
258                 [Test]
259                 public void WebMessageFormats ()
260                 {
261                         var host = new WebServiceHost (typeof (Hello));
262                         var port = NetworkHelpers.FindFreePort ();
263                         host.AddServiceEndpoint (typeof (IHello), new WebHttpBinding (), "http://localhost:" + port + "/");
264                         host.Description.Behaviors.Find<ServiceDebugBehavior> ().IncludeExceptionDetailInFaults = true;
265                         host.Open ();
266                         try {
267                                 // run client
268                                 using (ChannelFactory<IHello> factory = new ChannelFactory<IHello> (new WebHttpBinding (), "http://localhost:" + port + "/"))
269                                 {
270                                         factory.Endpoint.Behaviors.Add (new WebHttpBehavior ());
271                                         IHello h = factory.CreateChannel ();
272                                         //Console.WriteLine(h.SayHi("Joe", 42, null));
273                                         Assert.AreEqual ("Hi Joe.", h.SayHi2 (new User { Name = "Joe" }), "#1");
274                                 }
275                         } finally {
276                                 host.Close ();
277                         }
278                 }
279                 
280                 #endregion
281         }
282 }
283 #endif