[System/ServiceModel] Fix more hardcoded test ports
[mono.git] / mcs / class / System.ServiceModel / Test / System.ServiceModel / ServiceHostTest.cs
1 //
2 // ServiceHostTest.cs
3 //
4 // Author:
5 //      Ankit Jain  <jankit@novell.com>
6 //      Atsushi Enomoto  <atsushi@ximian.com>
7 //
8 // Copyright (C) 2005-2006 Novell, Inc.  http://www.novell.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.Collections.Generic;
31 using System.ServiceModel;
32 using System.ServiceModel.Channels;
33 using System.ServiceModel.Description;
34 using System.ServiceModel.Dispatcher;
35 using NUnit.Framework;
36
37 using MonoTests.Helpers;
38
39 namespace MonoTests.System.ServiceModel
40 {
41         [TestFixture]
42         public class ServiceHostTest
43         {
44                 class MyHost : ServiceHost
45                 {
46                         public MyHost (Type type, Uri uri)
47                                 : base (type, uri)
48                         {
49                         }
50
51                         public IDictionary<string,ContractDescription> ExposedContracts {
52                                 get { return ImplementedContracts; }
53                         }
54                 }
55
56                 [Test]
57                 public void Ctor ()
58                 {
59                         MyHost host = new MyHost (typeof (Foo), new Uri ("http://localhost"));
60                         Assert.IsNotNull (host.Description, "#1");
61                         Assert.AreEqual (typeof (Foo), host.Description.ServiceType, "#1-2");
62                         Assert.IsNotNull (host.BaseAddresses, "#2");
63                         Assert.AreEqual (1, host.BaseAddresses.Count, "#3");
64
65                         Assert.IsNotNull (host.ChannelDispatchers, "#4");
66                         Assert.AreEqual (0, host.ChannelDispatchers.Count, "#5");
67                         Assert.IsNotNull (host.Authorization, "#6");
68                         Assert.IsNotNull (host.ExposedContracts, "#7");
69                         // Foo is already in the contracts.
70                         Assert.AreEqual (1, host.ExposedContracts.Count, "#8");
71                         // this loop iterates only once.
72                         foreach (KeyValuePair<string,ContractDescription> e in host.ExposedContracts) {
73                                 // hmm... so, seems like the key is just the full name of the contract type.
74                                 Assert.AreEqual ("MonoTests.System.ServiceModel.ServiceHostTest+Foo", e.Key, "#9");
75                                 ContractDescription cd = e.Value;
76                                 Assert.AreEqual ("Foo", cd.Name, "#10");
77                                 Assert.AreEqual ("http://tempuri.org/", cd.Namespace, "#11");
78                         }
79                 }
80
81                 [Test]
82                 [ExpectedException (typeof (ArgumentNullException))]
83                 public void CtorNull ()
84                 {
85                         new ServiceHost (typeof (Foo), null);
86                 }
87
88                 [Test]
89                 [ExpectedException (typeof (ArgumentException))]
90                 public void CtorServiceTypeNotClass ()
91                 {
92                         new ServiceHost (typeof (IBar), new Uri ("http://localhost"));
93                 }
94
95                 [Test]
96                 [ExpectedException (typeof (ArgumentException))]
97                 public void CtorRelativeBaseAddress ()
98                 {
99                         new ServiceHost (typeof (Foo), new Uri ("test", UriKind.Relative));
100                 }
101                 
102                 [Test]
103                 [ExpectedException (typeof (ArgumentException))]
104                 public void CtorMultipleAddressPerScheme ()
105                 {
106                         new ServiceHost ( typeof (Foo), 
107                                         new Uri ("http://localhost", UriKind.Absolute),
108                                         new Uri ("http://someotherhost", UriKind.Absolute));
109                 }
110
111                 [Test]
112                 public void AddServiceEndpoint ()
113                 {
114                         ServiceHost host = new ServiceHost (typeof (Foo), new Uri ("http://localhost/echo"));
115                         host.AddServiceEndpoint (typeof (Foo), new BasicHttpBinding (), "rel");
116                         host.AddServiceEndpoint (typeof (Foo), new BasicHttpBinding (), "svc");
117
118                         Assert.IsNotNull (host.Description, "#6");
119                         Assert.IsNotNull (host.Description.Endpoints, "#7");
120                         Assert.AreEqual (host.Description.Endpoints.Count, 2, "#8");
121                         Assert.AreEqual ("http://localhost/echo/rel", host.Description.Endpoints [0].Address.Uri.AbsoluteUri,  "#9");
122                 }
123
124                 [Test]
125                 [ExpectedException (typeof (InvalidOperationException))]
126                 public void AddServiceEndpoint1 ()
127                 {
128                         ServiceHost host = new ServiceHost (typeof (Foo), new Uri ("ftp://localhost/echo"));
129                         // ftp does not match BasicHttpBinding
130                         host.AddServiceEndpoint (typeof (Foo), new BasicHttpBinding (), "rel");
131                 }
132
133                 [Test]
134                 [ExpectedException (typeof (InvalidOperationException))]
135                 public void AddServiceEndpoint2 ()
136                 {
137                         ServiceHost host = new ServiceHost (typeof (Foo), new Uri ("http://localhost/echo"));
138                         host.AddServiceEndpoint (typeof (Foo), new BasicHttpBinding (), "rel");
139                         host.AddServiceEndpoint (typeof (Foo), new BasicHttpBinding (), "rel"); // duplicate URI
140
141                         host.Open ();
142                         host.Close (); // should not reach here. It is to make sure to close unexpectedly opened host.
143                 }
144
145                 [Test]
146                 [ExpectedException (typeof (InvalidOperationException))]
147                 public void AddServiceEndpoint2_2 ()
148                 {
149                         ServiceHost host = new ServiceHost (typeof (Foo), new Uri ("http://localhost/echo"));
150                         // same as above, but through Endpoints.Add()
151                         host.Description.Endpoints.Add (new ServiceEndpoint (ContractDescription.GetContract (typeof (Foo)), new BasicHttpBinding (), new EndpointAddress ("http://localhost/echo/rel")));
152                         host.Description.Endpoints.Add (new ServiceEndpoint (ContractDescription.GetContract (typeof (Foo)), new BasicHttpBinding (), new EndpointAddress ("http://localhost/echo/rel")));
153
154                         host.Open ();
155                         host.Close (); // should not reach here. It is to make sure to close unexpectedly opened host.
156                 }
157
158                 [Test]
159                 [ExpectedException (typeof (InvalidOperationException))]
160                 public void AddServiceEndpoint2_3 ()
161                 {
162                         ServiceHost host = new ServiceHost (typeof (HogeFuga), new Uri ("http://localhost/echo"));
163                         host.Description.Endpoints.Add (new ServiceEndpoint (ContractDescription.GetContract (typeof (IHoge)), new BasicHttpBinding (), new EndpointAddress ("http://localhost/echo")));
164                         host.Description.Endpoints.Add (new ServiceEndpoint (ContractDescription.GetContract (typeof (IFuga)), new BasicHttpBinding (), new EndpointAddress ("http://localhost/echo")));
165
166                         // Different contracts unlike previous two cases.
167                         // If two or more endpoints are bound to the same listen
168                         // URI, then they must share the same instance.
169
170                         host.Open ();
171                         host.Close (); // should not reach here. It is to make sure to close unexpectedly opened host.
172                 }
173
174                 [Test]
175                 public void AddServiceEndpoint2_4 ()
176                 {
177                         var ep = "http://" + NetworkHelpers.LocalEphemeralEndPoint().ToString();
178                         ServiceHost host = new ServiceHost (typeof (HogeFuga), new Uri (ep));
179                         var binding = new BasicHttpBinding ();
180                         host.AddServiceEndpoint (typeof (IHoge), binding, new Uri (ep));
181                         host.AddServiceEndpoint (typeof (IFuga), binding, new Uri (ep));
182
183                         // Use the same binding, results in one ChannelDispatcher (actually two, for metadata/debug behavior).
184                         host.Open ();
185                         try {
186                                 Assert.AreEqual (2, host.ChannelDispatchers.Count, "#1");
187                                 foreach (ChannelDispatcher cd in host.ChannelDispatchers) {
188                                         if (cd.BindingName != binding.Name)
189                                                 continue; // mex
190                                         Assert.AreEqual (2, cd.Endpoints.Count, "#2");
191                                 }
192                         } finally {
193                                 host.Close ();
194                         }
195                 }
196
197                 [Test]
198                 [ExpectedException (typeof (InvalidOperationException))]
199                 public void AddServiceEndpoint3 ()
200                 {
201                         ServiceHost host = new ServiceHost (typeof (Foo), new Uri ("http://localhost/echo"));
202                         host.AddServiceEndpoint (typeof (Foo), new BasicHttpBinding (), "rel");
203                         host.AddServiceEndpoint (typeof (Foo), new BasicHttpBinding (), "http://localhost/echo/rel"); // duplicate URI when resolved
204
205                         host.Open ();
206                         host.Close (); // should not reach here. It is to make sure to close unexpectedly opened host.
207                 }
208
209                 [Test]
210                 public void Open ()
211                 {
212                         ServiceHost host = new ServiceHost (typeof (ZeroOperationsImpl));
213                         host.AddServiceEndpoint (typeof (IHaveZeroOperarationsContract), new BasicHttpBinding (), "http://localhost/echo");
214
215                         try {
216                                 host.Open ();
217                                 Assert.Fail ("InvalidOperationException expected");
218                         } 
219                         catch (InvalidOperationException e) {
220                                 //"ContractDescription 'IHaveZeroOperarationsContract' has zero operations; a contract must have at least one operation."
221                                 StringAssert.Contains ("IHaveZeroOperarationsContract", e.Message);
222                         }
223                         finally {
224                                 if (host.State == CommunicationState.Opened)
225                                         host.Close (); // It is to make sure to close unexpectedly opened host if the test fail.
226                         }
227                 }
228
229                 [Test]
230                 public void AddServiceEndpoint4 ()
231                 {
232                         ServiceHost host = new ServiceHost (typeof (Baz), new Uri ("http://localhost/echo"));
233                         host.AddServiceEndpoint ("MonoTests.System.ServiceModel.ServiceHostTest+IBaz", new BasicHttpBinding (), "rel");
234                 }
235
236                 [Test]
237                 [ExpectedException (typeof (InvalidOperationException))]
238                 public void AddServiceEndpoint5 ()
239                 {
240                         ServiceHost host = new ServiceHost (typeof (Baz), new Uri ("http://localhost/echo"));
241
242                         // Full type name is expected here (see AddServiceEndpoint4).
243                         host.AddServiceEndpoint ("IBaz", new BasicHttpBinding (), "rel");
244                 }
245
246                 [Test]
247                 [ExpectedException (typeof (InvalidOperationException))]
248                 public void AddServiceEndpoint6 ()
249                 {
250                         ServiceHost host = new ServiceHost (typeof (Foo), new Uri ("http://localhost/echo"));
251                         host.AddServiceEndpoint ("ISuchTypeDoesNotExist", new BasicHttpBinding (), "rel");
252                 }
253
254                 [Test]
255                 public void AddServiceEndpoint7 ()
256                 {
257                         ServiceHost host = new ServiceHost (typeof (Foo), new Uri ("http://localhost/echo"));
258                         var a = host.AddServiceEndpoint (typeof (Foo), new BasicHttpBinding (), "a");
259                         Console.WriteLine (a.Address);
260                         Assert.AreEqual ("http", a.Address.Uri.Scheme, "#1");
261                         Assert.AreEqual ("http://localhost/echo/a", a.Address.Uri.AbsoluteUri, "#2");
262
263                         var b = host.AddServiceEndpoint (typeof (Foo), new BasicHttpBinding (), "/b");
264                         Console.WriteLine (b.Address);
265                         Assert.AreEqual ("http", b.Address.Uri.Scheme, "#3");
266                         Assert.AreEqual ("http://localhost/echo/b", b.Address.Uri.AbsoluteUri, "#4");
267                 }
268                 
269                 [Test]
270                 [ExpectedException (typeof (InvalidOperationException))]
271                 public void AddServiceEndpointMexWithNoImpl ()
272                 {
273                         var port = NetworkHelpers.FindFreePort ();
274                         using (ServiceHost h = new ServiceHost (typeof (Foo), new Uri ("http://localhost:" + port))) {
275                                 // it expects ServiceMetadataBehavior
276                                 h.AddServiceEndpoint (ServiceMetadataBehavior.MexContractName, MetadataExchangeBindings.CreateMexHttpBinding (), "mex");
277                         }
278                 }
279
280                 [Test]
281                 public void AddServiceEndpointMetadataExchange ()
282                 {
283                         var port = NetworkHelpers.FindFreePort ();
284                         // MyMetadataExchange implements IMetadataExchange
285                         ServiceHost host = new ServiceHost (typeof (MyMetadataExchange));
286                         host.AddServiceEndpoint ("IMetadataExchange",
287                                                  new BasicHttpBinding (),
288                                                  "http://localhost:" + port + "/");
289                 }
290
291                 [Test]
292                 [ExpectedException (typeof (InvalidOperationException))]
293                 public void AddServiceEndpointMetadataExchangeFullNameFails ()
294                 {
295                         var port = NetworkHelpers.FindFreePort ();
296                         ServiceHost host = new ServiceHost (typeof (MyMetadataExchange));
297                         host.AddServiceEndpoint ("System.ServiceModel.Description.IMetadataExchange",
298                                                  new BasicHttpBinding (),
299                                                  "http://localhost:" + port);
300                 }
301
302                 [Test]
303                 public void InstanceWithNonSingletonMode ()
304                 {
305                         var ep = NetworkHelpers.LocalEphemeralEndPoint().ToString();
306                         ServiceHost host = new ServiceHost (
307                                 new NonSingletonService ());
308                         Assert.IsNotNull (host.Description.Behaviors.Find<ServiceBehaviorAttribute> ().GetWellKnownSingleton (), "premise1");
309                         host.AddServiceEndpoint (
310                                 typeof (NonSingletonService),
311                                 new BasicHttpBinding (),
312                                 new Uri ("http://" + ep + "/s1"));
313
314                         // in case Open() didn't fail, we need to close the host.
315                         // And even if Close() caused the expected exception,
316                         // the test should still fail.
317                         try {
318                                 host.Open ();
319                                 try {
320                                         if (host.State == CommunicationState.Opened)
321                                                 host.Close ();
322                                 } catch (InvalidOperationException) {
323                                 }
324                                 Assert.Fail ("InstanceContextMode was not checked");
325                         } catch (InvalidOperationException) {
326                         }
327                 }
328
329
330                 [Test]
331                 public void InstanceWithSingletonMode ()
332                 {
333             var ep = NetworkHelpers.LocalEphemeralEndPoint().ToString();
334                         SingletonService instance = new SingletonService ();
335                         ServiceHost host = new ServiceHost (instance);
336                         Assert.IsNotNull (host.Description.Behaviors.Find<ServiceBehaviorAttribute> ().GetWellKnownSingleton (), "#1");
337                         host.AddServiceEndpoint (
338                                 typeof (SingletonService),
339                                 new BasicHttpBinding (),
340                                 new Uri ("http://" + ep + "/s2"));
341
342                         // in case Open() didn't fail, we need to close the host.
343                         // And even if Close() caused the expected exception,
344                         // the test should still fail.
345                         try {
346                                 host.Open ();
347                                 ChannelDispatcher cd = (ChannelDispatcher) host.ChannelDispatchers [0];
348                                 DispatchRuntime dr = cd.Endpoints [0].DispatchRuntime;
349                                 Assert.IsNotNull (dr.InstanceContextProvider, "#2");
350                                 InstanceContext ctx = dr.InstanceContextProvider.GetExistingInstanceContext (null, null);
351                                 Assert.IsNotNull (ctx, "#3");
352                                 Assert.AreEqual (instance, ctx.GetServiceInstance (), "#4");
353                         } finally {
354                                 if (host.State == CommunicationState.Opened)
355                                         host.Close ();
356                         }
357                 }
358
359                 [Test]
360                 public void InstanceWithSingletonMode_InheritServiceBehavior ()
361                 {
362                         // # 37035
363
364                         var ep = NetworkHelpers.LocalEphemeralEndPoint ().ToString ();
365
366                         ChildSingletonService instance = new ChildSingletonService ();
367                         ServiceHost host = new ServiceHost (instance);
368
369                         host.AddServiceEndpoint (typeof (SingletonService),
370                                                  new BasicHttpBinding (),
371                                                  new Uri ("http://" + ep + "/s3"));
372
373                         try {
374                                 host.Open ();
375                         } catch (InvalidOperationException ex) {
376                                 Assert.Fail ("InstanceContextMode was not inherited from parent, exception was: {0}", ex);
377                         } finally {
378                                 host.Close ();
379                         }
380                 }
381
382                 [ServiceContract]
383                 interface IBar
384                 {
385                 }
386
387                 [ServiceContract]
388                 class Foo
389                 {
390                         [OperationContract]
391                         public void SayWhat () { }
392                 }
393
394                 [ServiceContract]
395                 interface IBaz
396                 {
397                         [OperationContract]
398                         string Echo (string source);
399                 }
400                 
401                 [ServiceContract]
402                 interface IHoge
403                 {
404                         [OperationContract]
405                         void DoX ();
406                 }
407
408                 [ServiceContract]
409                 interface IFuga
410                 {
411                         [OperationContract]
412                         void DoY ();
413                 }
414
415                 [ServiceContract]
416                 interface IHaveZeroOperarationsContract
417                 {
418                         string Echo (string source);
419                 }
420
421                 class ZeroOperationsImpl : IHaveZeroOperarationsContract
422                 {
423                         public string Echo(string source)
424                         {
425                                 return null;
426                         }
427                 }
428
429                 class HogeFuga : IHoge, IFuga
430                 {
431                         public void DoX () {}
432                         public void DoY () {}
433                 }
434
435                 class Baz : IBaz
436                 {
437                         public string Echo (string source)
438                         {
439                                 return source;
440                         }
441                 }
442
443                 class MyMetadataExchange : IMetadataExchange
444                 {
445                         public Message Get (Message req)
446                         {
447                                 throw new NotImplementedException ();
448                         }
449
450                         public IAsyncResult BeginGet (Message request, AsyncCallback cb, object state)
451                         {
452                                 throw new NotImplementedException ();
453                         }
454
455                         public Message EndGet (IAsyncResult result)
456                         {
457                                 throw new NotImplementedException ();
458                         }
459                 }
460
461                 [ServiceContract]
462                 public class NonSingletonService
463                 {
464                         [OperationContract]
465                         public void Process (string input)
466                         {
467                         }
468                 }
469
470                 [ServiceContract]
471                 [ServiceBehavior (InstanceContextMode = InstanceContextMode.Single)]
472                 public class SingletonService
473                 {
474                         [OperationContract]
475                         public virtual void Process (string input)
476                         {
477                         }
478                 }
479
480                 public class ChildSingletonService : SingletonService
481                 {
482                         public override void Process (string input)
483                         {
484                         }
485                 }
486         }
487 }