Repository: reef
Updated Branches:
  refs/heads/master 6977d2291 -> 5e9375dcb


[REEF-1436] Validate Service constructor failure => FailedContext Event

This addressed the issue by
  * Adding test that submits a failing Service configuration.
  * Adding context ID reporting in FailedContext.
  * Report the correct ParentContext in FailedContext.

JIRA:
  [REEF-1436](https://issues.apache.org/jira/browse/REEF-1436)

Pull request:
  This closes #1046


Project: http://git-wip-us.apache.org/repos/asf/reef/repo
Commit: http://git-wip-us.apache.org/repos/asf/reef/commit/5e9375dc
Tree: http://git-wip-us.apache.org/repos/asf/reef/tree/5e9375dc
Diff: http://git-wip-us.apache.org/repos/asf/reef/diff/5e9375dc

Branch: refs/heads/master
Commit: 5e9375dcbf2df081cb611f968c9b0fb55ede0d6b
Parents: 6977d22
Author: Andrew Chung <[email protected]>
Authored: Fri Jun 17 16:05:01 2016 -0700
Committer: Mariia Mykhailova <[email protected]>
Committed: Wed Jun 29 12:19:20 2016 -0700

----------------------------------------------------------------------
 .../FailedContextClr2Java.cpp                   |   6 -
 .../Context/ContextClientCodeException.cs       |  12 -
 .../Runtime/Evaluator/Context/ContextManager.cs |  18 +-
 .../Runtime/Evaluator/Context/ContextRuntime.cs |  21 +-
 .../User/ServiceConstructorExceptionTest.cs     | 242 +++++++++++++++++++
 .../Org.Apache.REEF.Tests.csproj                |   1 +
 6 files changed, 264 insertions(+), 36 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/reef/blob/5e9375dc/lang/cs/Org.Apache.REEF.Bridge/FailedContextClr2Java.cpp
----------------------------------------------------------------------
diff --git a/lang/cs/Org.Apache.REEF.Bridge/FailedContextClr2Java.cpp 
b/lang/cs/Org.Apache.REEF.Bridge/FailedContextClr2Java.cpp
index 7efb2b1..115fddc 100644
--- a/lang/cs/Org.Apache.REEF.Bridge/FailedContextClr2Java.cpp
+++ b/lang/cs/Org.Apache.REEF.Bridge/FailedContextClr2Java.cpp
@@ -34,18 +34,12 @@ namespace Org {
                                                  if (env->GetJavaVM(pJavaVm) 
!= 0) {
                                                          
ManagedLog::LOGGER->LogError("Failed to get JavaVM", nullptr);
                                                  }
-                          
ManagedLog::LOGGER->LogStart("FailedContextClr2Java::FailedContextClr2Java");
                                                  _jobjectFailedContext = 
reinterpret_cast<jobject>(env->NewGlobalRef(jobjectFailedContext));
                                                  jclass jclassFailedContext = 
env->GetObjectClass(_jobjectFailedContext);
-                          
ManagedLog::LOGGER->LogStart("FailedContextClr2Java::FailedContextClr2Java");
 
                                                  jmethodID jmidGetParentId = 
env->GetMethodID(jclassFailedContext, "getParentIdString", 
"()Ljava/lang/String;");
-
-                          
ManagedLog::LOGGER->LogStart("FailedContextClr2Java::FailedContextClr2Java");
                                                  _jstringContextId = 
CommonUtilities::GetJObjectId(env, jobjectFailedContext, jclassFailedContext);
-                          
ManagedLog::LOGGER->LogStart("FailedContextClr2Java::FailedContextClr2Java");
                                                  _jstringEvaluatorId = 
CommonUtilities::GetJObjectEvaluatorId(env, jobjectFailedContext, 
jclassFailedContext);
-                          
ManagedLog::LOGGER->LogStart("FailedContextClr2Java::FailedContextClr2Java");
                                                  _jstringParentContextId = 
reinterpret_cast<jstring>(env->NewGlobalRef(env->CallObjectMethod(_jobjectFailedContext,
 jmidGetParentId)));
 
                                                  
ManagedLog::LOGGER->LogStop("FailedContextClr2Java::FailedContextClr2Java");

http://git-wip-us.apache.org/repos/asf/reef/blob/5e9375dc/lang/cs/Org.Apache.REEF.Common/Runtime/Evaluator/Context/ContextClientCodeException.cs
----------------------------------------------------------------------
diff --git 
a/lang/cs/Org.Apache.REEF.Common/Runtime/Evaluator/Context/ContextClientCodeException.cs
 
b/lang/cs/Org.Apache.REEF.Common/Runtime/Evaluator/Context/ContextClientCodeException.cs
index ae8f44b..a6f9b74 100644
--- 
a/lang/cs/Org.Apache.REEF.Common/Runtime/Evaluator/Context/ContextClientCodeException.cs
+++ 
b/lang/cs/Org.Apache.REEF.Common/Runtime/Evaluator/Context/ContextClientCodeException.cs
@@ -16,7 +16,6 @@
 // under the License.
 
 using System;
-using Org.Apache.REEF.Tang.Interface;
 using Org.Apache.REEF.Utilities;
 
 namespace Org.Apache.REEF.Common.Runtime.Evaluator.Context
@@ -53,16 +52,5 @@ namespace Org.Apache.REEF.Common.Runtime.Evaluator.Context
         {
             get { return _parentId; }
         }
-
-        /// <summary>
-        /// Extracts a context id from the given configuration.
-        /// </summary>
-        /// <param name="c"></param>
-        /// <returns>the context id in the given configuration.</returns>
-        public static string GetId(IConfiguration c)
-        {
-            // TODO: update after TANG is available
-            return string.Empty;
-        }
     }
 }

http://git-wip-us.apache.org/repos/asf/reef/blob/5e9375dc/lang/cs/Org.Apache.REEF.Common/Runtime/Evaluator/Context/ContextManager.cs
----------------------------------------------------------------------
diff --git 
a/lang/cs/Org.Apache.REEF.Common/Runtime/Evaluator/Context/ContextManager.cs 
b/lang/cs/Org.Apache.REEF.Common/Runtime/Evaluator/Context/ContextManager.cs
index 1387d51..7f9e846 100644
--- a/lang/cs/Org.Apache.REEF.Common/Runtime/Evaluator/Context/ContextManager.cs
+++ b/lang/cs/Org.Apache.REEF.Common/Runtime/Evaluator/Context/ContextManager.cs
@@ -184,18 +184,14 @@ namespace Org.Apache.REEF.Common.Runtime.Evaluator.Context
                     Utilities.Diagnostics.Exceptions.Throw(e, LOGGER);
                 } 
             }
-            catch (Exception e)
+            catch (TaskClientCodeException e)
             {
-                if (e is TaskClientCodeException)
-                {
-                    HandleTaskException(e as TaskClientCodeException);
-                }
-                else if (e is ContextClientCodeException)
-                {
-                    HandleContextException(e as ContextClientCodeException);
-                }
-                Utilities.Diagnostics.Exceptions.CaughtAndThrow(e, 
Level.Error, LOGGER);
-            }  
+                HandleTaskException(e);
+            }
+            catch (ContextClientCodeException e)
+            {
+                HandleContextException(e);
+            }
         }
 
         /// <summary>

http://git-wip-us.apache.org/repos/asf/reef/blob/5e9375dc/lang/cs/Org.Apache.REEF.Common/Runtime/Evaluator/Context/ContextRuntime.cs
----------------------------------------------------------------------
diff --git 
a/lang/cs/Org.Apache.REEF.Common/Runtime/Evaluator/Context/ContextRuntime.cs 
b/lang/cs/Org.Apache.REEF.Common/Runtime/Evaluator/Context/ContextRuntime.cs
index 3a49f53..eced5e2 100644
--- a/lang/cs/Org.Apache.REEF.Common/Runtime/Evaluator/Context/ContextRuntime.cs
+++ b/lang/cs/Org.Apache.REEF.Common/Runtime/Evaluator/Context/ContextRuntime.cs
@@ -28,6 +28,7 @@ using Org.Apache.REEF.Common.Services;
 using Org.Apache.REEF.Common.Tasks;
 using Org.Apache.REEF.Common.Tasks.Events;
 using Org.Apache.REEF.Tang.Exceptions;
+using Org.Apache.REEF.Tang.Implementations.Tang;
 using Org.Apache.REEF.Tang.Interface;
 using Org.Apache.REEF.Utilities;
 using Org.Apache.REEF.Utilities.Attributes;
@@ -225,15 +226,21 @@ namespace Org.Apache.REEF.Common.Runtime.Evaluator.Context
                 {
                     Utilities.Diagnostics.Exceptions.Caught(e, Level.Error, 
LOGGER);
 
-                    Optional<string> parentId = ParentContext.IsPresent() ?
-                        Optional<string>.Of(ParentContext.Value.Id) :
-                        Optional<string>.Empty();
-                    ContextClientCodeException ex = new 
ContextClientCodeException(ContextClientCodeException.GetId(childContextConfiguration),
 parentId, "Unable to spawn context", e);
-                    
-                    Utilities.Diagnostics.Exceptions.Throw(ex, LOGGER);
+                    var childContextId = string.Empty;
+                    try
+                    {
+                        var injector = 
TangFactory.GetTang().NewInjector(childContextConfiguration);
+                        childContextId = 
injector.GetNamedInstance<ContextConfigurationOptions.ContextIdentifier, 
string>();
+                    }
+                    catch (InjectionException)
+                    {
+                        Utilities.Diagnostics.Exceptions.Caught(
+                            e, Level.Error, "Unable to get Context ID from 
child ContextConfiguration. Using empty string.", LOGGER);
+                    }
+
+                    throw new ContextClientCodeException(childContextId, 
Optional<string>.Of(Id), "Unable to spawn context", e);
                 }
             }
-            return null;
         }
 
         /// <summary>

http://git-wip-us.apache.org/repos/asf/reef/blob/5e9375dc/lang/cs/Org.Apache.REEF.Tests/Functional/Failure/User/ServiceConstructorExceptionTest.cs
----------------------------------------------------------------------
diff --git 
a/lang/cs/Org.Apache.REEF.Tests/Functional/Failure/User/ServiceConstructorExceptionTest.cs
 
b/lang/cs/Org.Apache.REEF.Tests/Functional/Failure/User/ServiceConstructorExceptionTest.cs
new file mode 100644
index 0000000..3bfecee
--- /dev/null
+++ 
b/lang/cs/Org.Apache.REEF.Tests/Functional/Failure/User/ServiceConstructorExceptionTest.cs
@@ -0,0 +1,242 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+// 
+//   http://www.apache.org/licenses/LICENSE-2.0
+// 
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+using System;
+using Org.Apache.REEF.Common.Context;
+using Org.Apache.REEF.Common.Services;
+using Org.Apache.REEF.Common.Tasks;
+using Org.Apache.REEF.Driver;
+using Org.Apache.REEF.Driver.Context;
+using Org.Apache.REEF.Driver.Evaluator;
+using Org.Apache.REEF.Driver.Task;
+using Org.Apache.REEF.Tang.Annotations;
+using Org.Apache.REEF.Tang.Util;
+using Org.Apache.REEF.Tests.Functional.Common.Task;
+using Org.Apache.REEF.Utilities.Logging;
+using Xunit;
+
+namespace Org.Apache.REEF.Tests.Functional.Failure.User
+{
+    [Collection("FunctionalTests")]
+    public sealed class ServiceConstructorExceptionTest : ReefFunctionalTest
+    {
+        private static readonly Logger Logger = 
Logger.GetLogger(typeof(ServiceConstructorExceptionTest));
+        private static readonly string FailedEvaluatorReceived = 
"FailedEvaluatorReceived";
+        private static readonly string ActiveContextReceived = 
"ActiveContextReceived";
+        private static readonly string FailedContextReceived = 
"FailedContextReceived";
+        private static readonly string RunningTaskReceived = 
"RunningTaskReceived";
+        private static readonly string CompletedTaskReceived = 
"CompletedTaskReceived";
+        private static readonly string Context0 = "Context0";
+        private static readonly string Context1 = "Context1";
+        private static readonly string Context2 = "Context2";
+        private static readonly string TaskId = "TaskId";
+        private static readonly string TaskRunningMessage = 
"TaskRunningMessage";
+
+        /// <summary>
+        /// This test tests that an Exception in the constructor of a Service 
object triggers a FailedContext event
+        /// on a non-root Context. Also tests that an Exception in the 
constructor of a Service object triggers a FailedEvaluator
+        /// event on a root Context. Upon failing the non-root context, we 
submit a Task to the failed context's parent
+        /// to verify that a Task can still be run on the parent context.
+        /// </summary>
+        [Fact]
+        [Trait("Priority", "1")]
+        [Trait("Category", "FunctionalGated")]
+        [Trait("Description", 
+            "Test Exception in the constructor of a Service object and 
validate that we receive either a FailedContext event " +
+            "in the case of non-root contexts, or a FailedEvaluator event in 
the case of the root context.")]
+        public void TestServiceConstructorExceptionOnLocalRuntime()
+        {
+            string testFolder = DefaultRuntimeFolder + TestId;
+            TestRun(
+                DriverConfiguration.ConfigurationModule
+                    .Set(DriverConfiguration.OnDriverStarted, 
GenericType<ServiceConstructorExceptionDriver>.Class)
+                    .Set(DriverConfiguration.OnEvaluatorFailed, 
GenericType<ServiceConstructorExceptionDriver>.Class)
+                    .Set(DriverConfiguration.OnEvaluatorAllocated, 
GenericType<ServiceConstructorExceptionDriver>.Class)
+                    .Set(DriverConfiguration.OnContextActive, 
GenericType<ServiceConstructorExceptionDriver>.Class)
+                    .Set(DriverConfiguration.OnContextFailed, 
GenericType<ServiceConstructorExceptionDriver>.Class)
+                    .Set(DriverConfiguration.OnTaskRunning, 
GenericType<ServiceConstructorExceptionDriver>.Class)
+                    .Set(DriverConfiguration.OnTaskCompleted, 
GenericType<ServiceConstructorExceptionDriver>.Class)
+                    .Build(),
+                typeof(ServiceConstructorExceptionDriver), 1, 
"serviceConstructorExceptionTest", "local", testFolder);
+
+            ValidateSuccessForLocalRuntime(numberOfContextsToClose: 1, 
numberOfTasksToFail: 0, numberOfEvaluatorsToFail: 1, testFolder: testFolder);
+            ValidateMessagesSuccessfullyLoggedForDriver(
+                new[] { FailedEvaluatorReceived, ActiveContextReceived, 
RunningTaskReceived, CompletedTaskReceived }, testFolder, 1);
+            CleanUp(testFolder);
+        }
+
+        private sealed class ServiceConstructorExceptionDriver : 
+            IObserver<IDriverStarted>,
+            IObserver<IAllocatedEvaluator>,
+            IObserver<IActiveContext>,
+            IObserver<IFailedContext>,
+            IObserver<IFailedEvaluator>,
+            IObserver<IRunningTask>,
+            IObserver<ICompletedTask>
+        {
+            private readonly object _lock = new object();
+            private readonly IEvaluatorRequestor _requestor;
+            private bool _shouldFailOnRootContext = true;
+
+            [Inject]
+            private ServiceConstructorExceptionDriver(IEvaluatorRequestor 
requestor)
+            {
+                _requestor = requestor;
+            }
+
+            public void OnNext(IDriverStarted value)
+            {
+                
_requestor.Submit(_requestor.NewBuilder().SetNumber(2).Build());
+            }
+
+            public void OnNext(IFailedEvaluator value)
+            {
+                // We should expect 0 failed contexts here, since the 
Evaluator fails
+                // to instantiate the RootContext.
+                Assert.Equal(0, value.FailedContexts.Count);
+                Logger.Log(Level.Info, FailedEvaluatorReceived);
+            }
+
+            /// <summary>
+            /// Submits two contexts, one that fails the Evaluator and another 
that allows for
+            /// Context Stacking.
+            /// </summary>
+            public void OnNext(IAllocatedEvaluator value)
+            {
+                lock (_lock)
+                {
+                    if (_shouldFailOnRootContext)
+                    {
+                        // Failing config.
+                        var ctxConf = ContextConfiguration.ConfigurationModule
+                            .Set(ContextConfiguration.Identifier, Context0)
+                            .Build();
+
+                        var serviceConf = 
ServiceConfiguration.ConfigurationModule
+                            .Set(ServiceConfiguration.Services, 
GenericType<ServiceConstructorExceptionService>.Class)
+                            .Build();
+
+                        value.SubmitContextAndService(ctxConf, serviceConf);
+                        _shouldFailOnRootContext = false;
+                    }
+                    else
+                    {
+                        // Context stacking config.
+                        value.SubmitContext(
+                            ContextConfiguration.ConfigurationModule
+                                .Set(ContextConfiguration.Identifier, Context1)
+                                .Build());
+                    }
+                }
+            }
+
+            /// <summary>
+            /// Submits the failing Context config on the non-failing Context.
+            /// </summary>
+            public void OnNext(IActiveContext value)
+            {
+                lock (_lock)
+                {
+                    Logger.Log(Level.Info, ActiveContextReceived);
+                    Assert.False(_shouldFailOnRootContext);
+
+                    var ctxConf = ContextConfiguration.ConfigurationModule
+                        .Set(ContextConfiguration.Identifier, Context2)
+                        .Build();
+
+                    var serviceConf = ServiceConfiguration.ConfigurationModule
+                        .Set(ServiceConfiguration.Services, 
GenericType<ServiceConstructorExceptionService>.Class)
+                        .Build();
+
+                    value.SubmitContextAndService(ctxConf, serviceConf);
+                }
+            }
+
+            /// <summary>
+            /// Only Context2 is expected as the FailedContext.
+            /// Context0 should trigger a FailedEvaluator directly.
+            /// Submit a Task on to the parent of Context2 (Context1) and make 
sure 
+            /// that it runs to completion.
+            /// </summary>
+            public void OnNext(IFailedContext value)
+            {
+                Assert.Equal(Context2, value.Id);
+                Assert.True(value.ParentContext.IsPresent(), "Expected " + 
Context2 + " to have parent of " + Context1);
+
+                if (value.ParentContext.IsPresent())
+                {
+                    // Submit Task on the good Context, i.e. the 
FailedContext's parent.
+                    Assert.Equal(Context1, value.ParentContext.Value.Id);
+                    value.ParentContext.Value.SubmitTask(
+                        TaskConfiguration.ConfigurationModule
+                            .Set(TaskConfiguration.Identifier, TaskId)
+                            .Set(TaskConfiguration.Task, 
GenericType<ServiceConstructorExceptionTestTask>.Class)
+                            .Build());
+                }
+
+                Logger.Log(Level.Info, FailedContextReceived);
+            }
+
+            public void OnNext(IRunningTask value)
+            {
+                Assert.Equal(TaskId, value.Id);
+                Assert.Equal(Context1, value.ActiveContext.Id);
+                Logger.Log(Level.Info, RunningTaskReceived);
+            }
+
+            public void OnNext(ICompletedTask value)
+            {
+                Assert.Equal(TaskId, value.Id);
+                Logger.Log(Level.Info, CompletedTaskReceived);
+                value.ActiveContext.Dispose();
+            }
+
+            public void OnError(Exception error)
+            {
+            }
+
+            public void OnCompleted()
+            {
+            }
+        }
+
+        /// <summary>
+        /// A test service class that is not injectable.
+        /// </summary>
+        private sealed class ServiceConstructorExceptionService
+        {
+            /// <summary>
+            /// Not injectable on purpose to make Service injection fail.
+            /// </summary>
+            private ServiceConstructorExceptionService()
+            {
+            }
+        }
+
+        /// <summary>
+        /// A Test Task class that simply logs a Task running message.
+        /// </summary>
+        private sealed class ServiceConstructorExceptionTestTask : LoggingTask
+        {
+            [Inject]
+            private ServiceConstructorExceptionTestTask() 
+                : base(TaskRunningMessage)
+            {
+            }
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/reef/blob/5e9375dc/lang/cs/Org.Apache.REEF.Tests/Org.Apache.REEF.Tests.csproj
----------------------------------------------------------------------
diff --git a/lang/cs/Org.Apache.REEF.Tests/Org.Apache.REEF.Tests.csproj 
b/lang/cs/Org.Apache.REEF.Tests/Org.Apache.REEF.Tests.csproj
index e58f980..c7f295a 100644
--- a/lang/cs/Org.Apache.REEF.Tests/Org.Apache.REEF.Tests.csproj
+++ b/lang/cs/Org.Apache.REEF.Tests/Org.Apache.REEF.Tests.csproj
@@ -80,6 +80,7 @@ under the License.
     <Compile Include="Functional\Bridge\TestContextStack.cs" />
     <Compile Include="Functional\Bridge\TestFailedEvaluatorEventHandler.cs" />
     <Compile Include="Functional\Common\Task\ExceptionTask.cs" />
+    <Compile 
Include="Functional\Failure\User\ServiceConstructorExceptionTest.cs" />
     <Compile Include="Functional\Failure\User\TaskCallExceptionTest.cs" />
     <Compile 
Include="Functional\Bridge\Exceptions\TestNonSerializableException.cs" />
     <Compile 
Include="Functional\Bridge\Exceptions\TestSerializableException.cs" />

Reply via email to