Merge pull request #2799 from BrzVlad/fix-conc-card-clean
[mono.git] / mcs / class / System.ServiceModel / Test / System.ServiceModel / ServiceHostTest.cs
index c3ef2365e9a7579bfd754d5a93fe5767cc818828..baf704655ca9ad618c1a50753b68dea39b22986d 100644 (file)
@@ -34,6 +34,8 @@ using System.ServiceModel.Description;
 using System.ServiceModel.Dispatcher;
 using NUnit.Framework;
 
+using MonoTests.Helpers;
+
 namespace MonoTests.System.ServiceModel
 {
        [TestFixture]
@@ -107,12 +109,11 @@ namespace MonoTests.System.ServiceModel
                }
 
                [Test]
-               [Ignore ("AddServiceEndpoint part does not work")]
                public void AddServiceEndpoint ()
                {
                        ServiceHost host = new ServiceHost (typeof (Foo), new Uri ("http://localhost/echo"));
-                       host.AddServiceEndpoint ("IBar", new BasicHttpBinding (), "rel");
-                       host.AddServiceEndpoint ("IBar", new BasicHttpBinding (), "svc");
+                       host.AddServiceEndpoint (typeof (Foo), new BasicHttpBinding (), "rel");
+                       host.AddServiceEndpoint (typeof (Foo), new BasicHttpBinding (), "svc");
 
                        Assert.IsNotNull (host.Description, "#6");
                        Assert.IsNotNull (host.Description.Endpoints, "#7");
@@ -126,27 +127,103 @@ namespace MonoTests.System.ServiceModel
                {
                        ServiceHost host = new ServiceHost (typeof (Foo), new Uri ("ftp://localhost/echo"));
                        // ftp does not match BasicHttpBinding
-                       host.AddServiceEndpoint ("IBar", new BasicHttpBinding (), "rel");
+                       host.AddServiceEndpoint (typeof (Foo), new BasicHttpBinding (), "rel");
                }
 
                [Test]
                [ExpectedException (typeof (InvalidOperationException))]
                public void AddServiceEndpoint2 ()
                {
-                       // IBar is not part of the contract
                        ServiceHost host = new ServiceHost (typeof (Foo), new Uri ("http://localhost/echo"));
-                       host.AddServiceEndpoint ("IBar", new BasicHttpBinding (), "rel");
-                       //host.AddServiceEndpoint ("IBar", new BasicHttpBinding (), "rel");
+                       host.AddServiceEndpoint (typeof (Foo), new BasicHttpBinding (), "rel");
+                       host.AddServiceEndpoint (typeof (Foo), new BasicHttpBinding (), "rel"); // duplicate URI
+
+                       host.Open ();
+                       host.Close (); // should not reach here. It is to make sure to close unexpectedly opened host.
+               }
+
+               [Test]
+               [ExpectedException (typeof (InvalidOperationException))]
+               public void AddServiceEndpoint2_2 ()
+               {
+                       ServiceHost host = new ServiceHost (typeof (Foo), new Uri ("http://localhost/echo"));
+                       // same as above, but through Endpoints.Add()
+                       host.Description.Endpoints.Add (new ServiceEndpoint (ContractDescription.GetContract (typeof (Foo)), new BasicHttpBinding (), new EndpointAddress ("http://localhost/echo/rel")));
+                       host.Description.Endpoints.Add (new ServiceEndpoint (ContractDescription.GetContract (typeof (Foo)), new BasicHttpBinding (), new EndpointAddress ("http://localhost/echo/rel")));
+
+                       host.Open ();
+                       host.Close (); // should not reach here. It is to make sure to close unexpectedly opened host.
+               }
+
+               [Test]
+               [ExpectedException (typeof (InvalidOperationException))]
+               public void AddServiceEndpoint2_3 ()
+               {
+                       ServiceHost host = new ServiceHost (typeof (HogeFuga), new Uri ("http://localhost/echo"));
+                       host.Description.Endpoints.Add (new ServiceEndpoint (ContractDescription.GetContract (typeof (IHoge)), new BasicHttpBinding (), new EndpointAddress ("http://localhost/echo")));
+                       host.Description.Endpoints.Add (new ServiceEndpoint (ContractDescription.GetContract (typeof (IFuga)), new BasicHttpBinding (), new EndpointAddress ("http://localhost/echo")));
+
+                       // Different contracts unlike previous two cases.
+                       // If two or more endpoints are bound to the same listen
+                       // URI, then they must share the same instance.
+
+                       host.Open ();
+                       host.Close (); // should not reach here. It is to make sure to close unexpectedly opened host.
+               }
+
+               [Test]
+               public void AddServiceEndpoint2_4 ()
+               {
+                       var ep = "http://" + NetworkHelpers.LocalEphemeralEndPoint().ToString();
+                       ServiceHost host = new ServiceHost (typeof (HogeFuga), new Uri (ep));
+                       var binding = new BasicHttpBinding ();
+                       host.AddServiceEndpoint (typeof (IHoge), binding, new Uri (ep));
+                       host.AddServiceEndpoint (typeof (IFuga), binding, new Uri (ep));
+
+                       // Use the same binding, results in one ChannelDispatcher (actually two, for metadata/debug behavior).
+                       host.Open ();
+                       try {
+                               Assert.AreEqual (2, host.ChannelDispatchers.Count, "#1");
+                               foreach (ChannelDispatcher cd in host.ChannelDispatchers) {
+                                       if (cd.BindingName != binding.Name)
+                                               continue; // mex
+                                       Assert.AreEqual (2, cd.Endpoints.Count, "#2");
+                               }
+                       } finally {
+                               host.Close ();
+                       }
                }
 
                [Test]
                [ExpectedException (typeof (InvalidOperationException))]
                public void AddServiceEndpoint3 ()
                {
-                       // IBar is not part of the contract
                        ServiceHost host = new ServiceHost (typeof (Foo), new Uri ("http://localhost/echo"));
-                       host.AddServiceEndpoint ("IBar", new BasicHttpBinding (), "rel");
-                       // host.AddServiceEndpoint ("IBar", new BasicHttpBinding (), "http://localhost/echo/rel");
+                       host.AddServiceEndpoint (typeof (Foo), new BasicHttpBinding (), "rel");
+                       host.AddServiceEndpoint (typeof (Foo), new BasicHttpBinding (), "http://localhost/echo/rel"); // duplicate URI when resolved
+
+                       host.Open ();
+                       host.Close (); // should not reach here. It is to make sure to close unexpectedly opened host.
+               }
+
+               [Test]
+               public void Open ()
+               {
+                       ServiceHost host = new ServiceHost (typeof (ZeroOperationsImpl));
+                       host.AddServiceEndpoint (typeof (IHaveZeroOperarationsContract), new BasicHttpBinding (), "http://localhost/echo");
+
+                       try {
+                               host.Open ();
+                               Assert.Fail ("InvalidOperationException expected");
+                       } 
+                       catch (InvalidOperationException e) {
+                               //"ContractDescription 'IHaveZeroOperarationsContract' has zero operations; a contract must have at least one operation."
+                               StringAssert.Contains ("IHaveZeroOperarationsContract", e.Message);
+                       }
+                       finally {
+                               if (host.State == CommunicationState.Opened)
+                                       host.Close (); // It is to make sure to close unexpectedly opened host if the test fail.
+                       }
                }
 
                [Test]
@@ -174,11 +251,27 @@ namespace MonoTests.System.ServiceModel
                        host.AddServiceEndpoint ("ISuchTypeDoesNotExist", new BasicHttpBinding (), "rel");
                }
 
+               [Test]
+               public void AddServiceEndpoint7 ()
+               {
+                       ServiceHost host = new ServiceHost (typeof (Foo), new Uri ("http://localhost/echo"));
+                       var a = host.AddServiceEndpoint (typeof (Foo), new BasicHttpBinding (), "a");
+                       Console.WriteLine (a.Address);
+                       Assert.AreEqual ("http", a.Address.Uri.Scheme, "#1");
+                       Assert.AreEqual ("http://localhost/echo/a", a.Address.Uri.AbsoluteUri, "#2");
+
+                       var b = host.AddServiceEndpoint (typeof (Foo), new BasicHttpBinding (), "/b");
+                       Console.WriteLine (b.Address);
+                       Assert.AreEqual ("http", b.Address.Uri.Scheme, "#3");
+                       Assert.AreEqual ("http://localhost/echo/b", b.Address.Uri.AbsoluteUri, "#4");
+               }
+               
                [Test]
                [ExpectedException (typeof (InvalidOperationException))]
-               public void AddServiceEndpointMex ()
+               public void AddServiceEndpointMexWithNoImpl ()
                {
-                       using (ServiceHost h = new ServiceHost (typeof (Foo), new Uri ("http://localhost:8080"))) {
+                       var port = NetworkHelpers.FindFreePort ();
+                       using (ServiceHost h = new ServiceHost (typeof (Foo), new Uri ("http://localhost:" + port))) {
                                // it expects ServiceMetadataBehavior
                                h.AddServiceEndpoint (ServiceMetadataBehavior.MexContractName, MetadataExchangeBindings.CreateMexHttpBinding (), "mex");
                        }
@@ -187,33 +280,36 @@ namespace MonoTests.System.ServiceModel
                [Test]
                public void AddServiceEndpointMetadataExchange ()
                {
+                       var port = NetworkHelpers.FindFreePort ();
+                       // MyMetadataExchange implements IMetadataExchange
                        ServiceHost host = new ServiceHost (typeof (MyMetadataExchange));
-                       // strange, but unlike above, it is accepted. The only difference I can see is the binding name.
                        host.AddServiceEndpoint ("IMetadataExchange",
                                                 new BasicHttpBinding (),
-                                                "http://localhost:8080");
+                                                "http://localhost:" + port + "/");
                }
 
                [Test]
                [ExpectedException (typeof (InvalidOperationException))]
                public void AddServiceEndpointMetadataExchangeFullNameFails ()
                {
+                       var port = NetworkHelpers.FindFreePort ();
                        ServiceHost host = new ServiceHost (typeof (MyMetadataExchange));
                        host.AddServiceEndpoint ("System.ServiceModel.Description.IMetadataExchange",
                                                 new BasicHttpBinding (),
-                                                "http://localhost:8080");
+                                                "http://localhost:" + port);
                }
 
                [Test]
                public void InstanceWithNonSingletonMode ()
                {
+                       var ep = NetworkHelpers.LocalEphemeralEndPoint().ToString();
                        ServiceHost host = new ServiceHost (
                                new NonSingletonService ());
                        Assert.IsNotNull (host.Description.Behaviors.Find<ServiceBehaviorAttribute> ().GetWellKnownSingleton (), "premise1");
                        host.AddServiceEndpoint (
                                typeof (NonSingletonService),
                                new BasicHttpBinding (),
-                               new Uri ("http://localhost:37564/s1"));
+                               new Uri ("http://" + ep + "/s1"));
 
                        // in case Open() didn't fail, we need to close the host.
                        // And even if Close() caused the expected exception,
@@ -234,13 +330,14 @@ namespace MonoTests.System.ServiceModel
                [Test]
                public void InstanceWithSingletonMode ()
                {
+            var ep = NetworkHelpers.LocalEphemeralEndPoint().ToString();
                        SingletonService instance = new SingletonService ();
                        ServiceHost host = new ServiceHost (instance);
                        Assert.IsNotNull (host.Description.Behaviors.Find<ServiceBehaviorAttribute> ().GetWellKnownSingleton (), "#1");
                        host.AddServiceEndpoint (
                                typeof (SingletonService),
                                new BasicHttpBinding (),
-                               new Uri ("http://localhost:37564/s2"));
+                               new Uri ("http://" + ep + "/s2"));
 
                        // in case Open() didn't fail, we need to close the host.
                        // And even if Close() caused the expected exception,
@@ -259,6 +356,29 @@ namespace MonoTests.System.ServiceModel
                        }
                }
 
+               [Test]
+               public void InstanceWithSingletonMode_InheritServiceBehavior ()
+               {
+                       // # 37035
+
+                       var ep = NetworkHelpers.LocalEphemeralEndPoint ().ToString ();
+
+                       ChildSingletonService instance = new ChildSingletonService ();
+                       ServiceHost host = new ServiceHost (instance);
+
+                       host.AddServiceEndpoint (typeof (SingletonService),
+                                                new BasicHttpBinding (),
+                                                new Uri ("http://" + ep + "/s3"));
+
+                       try {
+                               host.Open ();
+                       } catch (InvalidOperationException ex) {
+                               Assert.Fail ("InstanceContextMode was not inherited from parent, exception was: {0}", ex);
+                       } finally {
+                               host.Close ();
+                       }
+               }
+
                [ServiceContract]
                interface IBar
                {
@@ -277,6 +397,40 @@ namespace MonoTests.System.ServiceModel
                        [OperationContract]
                        string Echo (string source);
                }
+               
+               [ServiceContract]
+               interface IHoge
+               {
+                       [OperationContract]
+                       void DoX ();
+               }
+
+               [ServiceContract]
+               interface IFuga
+               {
+                       [OperationContract]
+                       void DoY ();
+               }
+
+               [ServiceContract]
+               interface IHaveZeroOperarationsContract
+               {
+                       string Echo (string source);
+               }
+
+               class ZeroOperationsImpl : IHaveZeroOperarationsContract
+               {
+                       public string Echo(string source)
+                       {
+                               return null;
+                       }
+               }
+
+               class HogeFuga : IHoge, IFuga
+               {
+                       public void DoX () {}
+                       public void DoY () {}
+               }
 
                class Baz : IBaz
                {
@@ -318,7 +472,14 @@ namespace MonoTests.System.ServiceModel
                public class SingletonService
                {
                        [OperationContract]
-                       public void Process (string input)
+                       public virtual void Process (string input)
+                       {
+                       }
+               }
+
+               public class ChildSingletonService : SingletonService
+               {
+                       public override void Process (string input)
                        {
                        }
                }