Эх сурвалжийг харах

Z991239-385 #comment 高权限实体添加测试案例;添加一个模块里面启动多个实体

gifur 5 жил өмнө
parent
commit
0cf51ccbd1

+ 21 - 11
CMakeLists.txt

@@ -117,23 +117,28 @@ if(BUILD_TESTING)
 	endif()
 endif()
 
-# specifies what build type (configuration) will be built in this build tree
-if(NOT CMAKE_BUILD_TYPE)
-	set(CMAKE_BUILD_TYPE "Debug")
-endif()
 if(BUILD_SHARED_LIBS)
 	message(STATUS "Build shared libraries")
 endif(BUILD_SHARED_LIBS)
 
-if (CMAKE_BUILD_TYPE STREQUAL Debug OR CMAKE_CONFIGURATION_TYPES STREQUAL Debug)
-	message(STATUS "debug type")
-	set(BUILD_TYPE_NAME "Debug")
-else()
-	set(BUILD_TYPE_NAME "Release")
-endif()
-string(TOLOWER ${BUILD_TYPE_NAME} BUILD_TYPE_NAME_lower)
+# Some buildsystems generated by CMake have a predetermined build-configuration set in the 
+# CMAKE_BUILD_TYPE variable. The buildsystem for the IDEs such as Visual Studio and Xcode are 
+# generated independent of the build-configuration, and the actual build configuration is not known 
+# until build-time. 
+# string(TOLOWER ${CMAKE_BUILD_TYPE} _type)
+#if (_type STREQUAL debug)
+#  target_compile_definitions(exe1 PRIVATE DEBUG_BUILD)
+# endif()
+#may appear to work for Makefile Generators and Ninja generators, but is not portable to IDE generators. 
+#Additionally, the IMPORTED configuration-mappings are not accounted for with code like this, so it should be avoided.
 
 if(${CMAKE_GENERATOR} MATCHES "Visual Studio*")
+	if(CMAKE_CONFIGURATION_TYPES STREQUAL Debug)
+		message(STATUS "debug type")
+		set(BUILD_TYPE_NAME "Debug")
+	else()
+		set(BUILD_TYPE_NAME "Release")
+	endif()
 	if(NOT CMAKE_GENERATOR_PLATFORM)
 		message(STATUS "set win32 platform default")
 		set(CMAKE_GENERATOR_PLATFORM "${CMAKE_SYSTEM_PROCESSOR}")
@@ -141,6 +146,10 @@ if(${CMAKE_GENERATOR} MATCHES "Visual Studio*")
 		message(STATUS ${CMAKE_GENERATOR_PLATFORM})
 	endif()
 elseif(${CMAKE_GENERATOR} MATCHES "Unix*")
+	if(NOT CMAKE_BUILD_TYPE)
+		set(CMAKE_BUILD_TYPE "Debug")
+	endif()
+	set(BUILD_TYPE_NAME ${CMAKE_BUILD_TYPE})
 	if(NOT CMAKE_GENERATOR_PLATFORM)
 		message(STATUS "set unix platform default")
 		set(CMAKE_GENERATOR_PLATFORM "${CMAKE_SYSTEM_PROCESSOR}")
@@ -148,6 +157,7 @@ elseif(${CMAKE_GENERATOR} MATCHES "Unix*")
 		message(STATUS ${CMAKE_GENERATOR_PLATFORM})
 	endif()
 endif()
+string(TOLOWER ${BUILD_TYPE_NAME} BUILD_TYPE_NAME_lower)
 # 注释掉之后,目测在Linux之下是跑 x64 位,否则会出现 pthread 找不到的情况,应该是没安装对应的版本
 #if(${CMAKE_GENERATOR} MATCHES "Unix*")
 #	message(STATUS "set 32bits and debug")

+ 31 - 10
CMakeSettings.json

@@ -1,33 +1,54 @@
 {
   "configurations": [
     {
-      "name": "x64-Debug",
-      "generator": "Visual Studio 16 2019 Win64",
+      "name": "x86-Debug",
+      "generator": "Visual Studio 16 2019",
       "configurationType": "Debug",
-      "inheritEnvironments": [ "msvc_x64_x64" ],
       "buildRoot": "${projectDir}\\out\\build\\${name}",
       "installRoot": "${projectDir}\\out\\install\\${name}",
-      "cmakeCommandArgs": "",
+      "cmakeCommandArgs": "-D BUILD_TESTING=ON",
       "buildCommandArgs": "",
-      "ctestCommandArgs": "",
+      "ctestCommandArgs": "-C Debug",
+      "inheritEnvironments": [ "msvc_x86" ],
       "variables": []
     },
     {
-      "name": "x86-Debug",
-      "generator": "Visual Studio 16 2019",
+      "name": "Linux-Debug",
+      "generator": "Unix Makefiles",
       "configurationType": "Debug",
+      "cmakeExecutable": "/usr/bin/cmake",
+      "remoteCopySourcesExclusionList": [ ".vs", ".git", "out" ],
+      "cmakeCommandArgs": "-D BUILD_TESTING=ON",
+      "buildCommandArgs": "",
+      "ctestCommandArgs": "--output-on-failure",
+      "inheritEnvironments": [ "linux_x64" ],
+      "remoteMachineName": "-530210665;10.42.0.1 (username=root, port=1022, authentication=Password)",
+      "remoteCMakeListsRoot": "$HOME/.vs/${projectDirName}/${workspaceHash}/src",
+      "remoteBuildRoot": "$HOME/.vs/${projectDirName}/${workspaceHash}/out/build/${name}",
+      "remoteInstallRoot": "$HOME/.vs/${projectDirName}/${workspaceHash}/out/install/${name}",
+      "remoteCopySources": true,
+      "rsyncCommandArgs": "-t --delete --delete-excluded --exclude \"/build\" --exclude \"/out\" --exclude-from=.gitignore",
+      "remoteCopyBuildOutput": false,
+      "remoteCopySourcesMethod": "rsync",
+      "addressSanitizerRuntimeFlags": "detect_leaks=0",
+      "variables": []
+    },
+    {
+      "name": "x86-Release",
+      "generator": "Visual Studio 16 2019",
+      "configurationType": "Release",
       "buildRoot": "${projectDir}\\out\\build\\${name}",
       "installRoot": "${projectDir}\\out\\install\\${name}",
       "cmakeCommandArgs": "-D BUILD_TESTING=OFF",
       "buildCommandArgs": "",
-      "ctestCommandArgs": "-C Debug",
+      "ctestCommandArgs": "-C Release",
       "inheritEnvironments": [ "msvc_x86" ],
       "variables": []
     },
     {
-      "name": "Linux-Debug",
+      "name": "Linux-Release",
       "generator": "Unix Makefiles",
-      "configurationType": "Debug",
+      "configurationType": "RelWithDebInfo",
       "cmakeExecutable": "/usr/bin/cmake",
       "remoteCopySourcesExclusionList": [ ".vs", ".git", "out" ],
       "cmakeCommandArgs": "-D BUILD_TESTING=ON",

+ 1 - 1
Common/SpBase.h

@@ -161,7 +161,7 @@ enum RebootWayEnum
 enum EntityTestEnum
 {
 	Test_ShakeHand=0,
-	Test_Examine,
+	Test_Examine, //no use at current time, even in selfcheck entity, they defined it but never call it.
 	Test_Reset,
 };
 

+ 25 - 0
Common/SpHelper.h

@@ -327,5 +327,30 @@ static ErrorCodeEnum SpSendBroadcast(CSmartPointer<IEntityFunction> pFunc, DWORD
 // <class_name>
 SPBASE_API ErrorCodeEnum SpExtractClassFunctionName(const char *pszParam, CSimpleStringA &strClassName, CSimpleStringA &strFunctionName);
 
+//helper macro for test temporary.
+
+#define IFFAILRET(func)	\
+do  {	\
+	ErrorCodeEnum errorCode = func;	\
+	if (errorCode != Error_Succeed) {	\
+	LogError(Severity_High, Error_Failed, 0,\
+		CSimpleStringA::Format("Invoke \"" #func "\" failed ec %s! at file: <%s>, line: %d",\
+		SpStrError(errorCode), _GetFileName(__FILE__), __LINE__));\
+		return Error_Failed;	\
+	}	\
+} while (false)
+
+
+#define REQUIRE(expr)	\
+do  {	\
+	if (!(expr)) {	\
+	LogError(Severity_High, Error_Failed, 0,\
+		CSimpleStringA::Format("expression (\"" #expr "\") requires failed! at file: <%s>, line: %d", _GetFileName(__FILE__), __LINE__));\
+		return Error_Failed;	\
+	}	\
+} while (false)
+
+#define REQUIRE_FALSE(expr)	\
+	REQUIRE(!(expr))
 
 #endif // __SP_SERVER_H

+ 8 - 1
addin/cfg/shell.ini.in

@@ -7,12 +7,19 @@ HelloClient=0,@LIB_PREFIX@mod_helloclient@LIB_SUFFIX@,0x102
 SampleEntity=0,@LIB_PREFIX@mod_SampleEntity@LIB_SUFFIX@,0x103
 LogSubscribe=0,@LIB_PREFIX@mod_logSubscribe@LIB_SUFFIX@,0x104
 BlackSheep=0,@LIB_PREFIX@mod_blackSheep@LIB_SUFFIX@,0x105
+TestPrivilegeEntity=1,@LIB_PREFIX@mod_testPrivilegeEntity@LIB_SUFFIX@,0x106
+TestNormalEntity=0,@LIB_PREFIX@mod_testNormalEntity@LIB_SUFFIX@,0x107
+TestPassiveEntity=0,@LIB_PREFIX@mod_testPassiveEntity@LIB_SUFFIX@,0x108
+TestPassiveSecondEntity=0,@LIB_PREFIX@mod_testPassiveEntity@LIB_SUFFIX@,0x109
+TestPassiveThirdEntity=0,@LIB_PREFIX@mod_testPassiveEntity@LIB_SUFFIX@,0x10A
 [Startup]
-Number=4
+Number=6
 1=HelloService
 2=HelloClient
 3=SampleEntity
 4=LogSubscribe
+5=TestPrivilegeEntity
+6=TestNormalEntity
 
 [Debug]
 HelloClient=1

+ 10 - 1
docs/designs/starup_routine.md

@@ -161,7 +161,16 @@ int app_run()
    11. 启动日志监听管理器对象
        1. 将包类型事件的处理函数加到服务层(svc)
 
-## 其他的启动
+## 实体的启动
+
+实体的初始化和启动是不一样的,实体的初始化会在模块被加载的时候就会执行,而实体的启动却是将实体运行起来达到Idle状态
+
+实体的启动有两个地方:
+
+1. 框架启动时,**spshell**直接拉起实体;
+2. 通过调用`StartEntity`启动实体
+
+
 
 
 

+ 1 - 1
module/mod_blackSheep/mod_blackSheep.cpp

@@ -1,7 +1,7 @@
 #include "stdafx.h"
 #include "SpBase.h"
 
-
+/*one of test module: use to test error: erro startup*/
 
 class CBlackSheep : public CEntityBase
 {

+ 1 - 1
module/mod_sample/SampleFSM.cpp

@@ -52,7 +52,7 @@ void CSampleFSM::SelfTest(EntityTestEnum eTestType,CSmartPointer<ITransactionCon
 
 void CSampleFSM::s0_on_entry()
 {
-	ScheduleTimer(TIMER_LOG_SEND_ID, TIMER_LOG_SEND_INTERVAL);
+	//ScheduleTimer(TIMER_LOG_SEND_ID, TIMER_LOG_SEND_INTERVAL);
 }
 
 void CSampleFSM::s0_on_exit()

+ 13 - 0
module/mod_testNormalEntity/CMakeLists.txt

@@ -0,0 +1,13 @@
+# 定义实体名称
+define_moudle("testNormalEntity")
+
+set(${MODULE_PREFIX}_SRCS
+	mod_testNormalEntity.cpp)
+
+add_module_libraries(${MODULE_PREFIX} ${MODULE_NAME})
+
+# 添加实体需要依赖的其他共享库(包括系统库)
+set(${MODULE_PREFIX}_LIBS spbase winpr)
+target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
+
+deploy_module(${MODULE_PREFIX} ${MODULE_NAME})

+ 181 - 0
module/mod_testNormalEntity/mod_testNormalEntity.cpp

@@ -0,0 +1,181 @@
+#include "stdafx.h"
+#include "SpBase.h"
+#include "SpHelper.h"
+
+/*one of test module: use to test error: erro startup*/
+
+class CNormalEntityTest : public CEntityBase
+{
+public:
+	CNormalEntityTest() {}
+	virtual ~CNormalEntityTest() {}
+	virtual const char *GetEntityName() const { return "TestNormalEntity"; }
+
+
+	virtual void OnPreStart(CAutoArray<CSimpleStringA> strArgs, CSmartPointer<ITransactionContext> pTransactionContext)
+	{
+		LOG_FUNCTION();
+		pTransactionContext->SendAnswer(__onTest());
+	}
+
+	virtual void OnStarted()
+	{
+		LOG_FUNCTION();
+	}
+
+	virtual void OnPreClose(EntityCloseCauseEnum eCloseCause,CSmartPointer<ITransactionContext> pTransactionContext) 
+	{ 
+		LOG_FUNCTION();
+		pTransactionContext->SendAnswer(Error_Succeed); 
+	}
+
+private:
+	ErrorCodeEnum __onTest();
+};
+
+static ErrorCodeEnum failTest()
+{
+	return Error_Bug;
+}
+
+ErrorCodeEnum CNormalEntityTest::__onTest()
+{
+	//auto func = GetFunction().ConvertCase<IEntityFunctionPrivilege>();
+	auto func = GetFunction();
+
+	REQUIRE_FALSE(func->HasPrivilege());
+
+	WORD wDevID = 0;
+	CEntityStaticInfo entStaticInfo = { 0 };
+	if (0 == GetFunction()->GetEntityStaticInfo(GetEntityName(), entStaticInfo)) {
+		wDevID = entStaticInfo.wEntityDevelopID;
+	}
+
+	CSystemStaticInfo sysStaticInfo;
+	IFFAILRET(func->GetSystemStaticInfo(sysStaticInfo));
+	REQUIRE(sysStaticInfo.strTerminalID.GetLength() == 10);
+	REQUIRE(sysStaticInfo.strMachineType.IsStartWith("RVC.", true));
+
+	CInstallInfo installInfo = { 0 };
+	IFFAILRET(func->GetInstallInfo(sysStaticInfo.InstallVersion, installInfo));
+
+	CVersion illegalVersion(1024, 256);
+	CInstallInfo noExistedInstallInfo = { 0 };
+	REQUIRE(func->GetInstallInfo(illegalVersion, noExistedInstallInfo) == Error_NotExist);
+
+	REQUIRE_FALSE(func->IsPackInstalled(NULL));
+	REQUIRE_FALSE(func->IsPackInstalled(""));
+
+	/*GetPath*/
+	CSimpleStringA strPath;
+	IFFAILRET(func->GetPath("Root", strPath));
+	IFFAILRET(func->GetPath("RootVer", strPath));
+	IFFAILRET(func->GetPath("Data", strPath));
+	IFFAILRET(func->GetPath("Bin", strPath));
+	IFFAILRET(func->GetPath("Cfg", strPath));
+	IFFAILRET(func->GetPath("Etc", strPath));
+	IFFAILRET(func->GetPath("Rec", strPath));
+	IFFAILRET(func->GetPath("Temp", strPath));
+	IFFAILRET(func->GetPath("Tmp", strPath));
+	IFFAILRET(func->GetPath("SysLog", strPath));
+	IFFAILRET(func->GetPath("InterLog", strPath));
+	IFFAILRET(func->GetPath("Base", strPath));
+	IFFAILRET(func->GetPath("BaseDir", strPath));
+	IFFAILRET(func->GetPath("SysRoot", strPath));
+	IFFAILRET(func->GetPath("Photo", strPath));
+	IFFAILRET(func->GetPath("UploadPhoto", strPath));
+	IFFAILRET(func->GetPath("Download", strPath));
+	IFFAILRET(func->GetPath("Downloads", strPath));
+	IFFAILRET(func->GetPath("Upgraded", strPath));
+	IFFAILRET(func->GetPath("Ad", strPath));
+	IFFAILRET(func->GetPath("UploadPhoto", strPath));
+	IFFAILRET(func->GetPath("UploadVideo", strPath));
+	IFFAILRET(func->GetPath("Dbg", strPath));
+	IFFAILRET(func->GetPath("Slv", strPath));
+	IFFAILRET(func->GetPath("Dep", strPath));
+	IFFAILRET(func->GetPath("Ad0", strPath));
+	IFFAILRET(func->GetPath("Dmp", strPath));
+	IFFAILRET(func->GetPath("Dump", strPath));
+	IFFAILRET(func->GetPath("RunInfo", strPath));
+	IFFAILRET(func->GetPath("HardwareCfg", strPath));
+	IFFAILRET(func->GetPath("CenterSetting", strPath));
+
+	IFFAILRET(func->GetPath("centersetting", strPath));
+
+	CSystemRunInfo runInfo = { 0 };
+	IFFAILRET(func->GetSystemRunInfo(runInfo));
+	REQUIRE(runInfo.strRunningEntityNames.GetCount() > 0);
+	for (uint32_t i = 0; i < runInfo.strRunningEntityNames.GetCount(); ++i) {
+		CEntityStaticInfo staticInfo = { 0 };
+		IFFAILRET(func->GetEntityStaticInfo(runInfo.strRunningEntityNames[i], staticInfo));
+	}
+
+
+	WORD nBusyEntityCount = 0;
+	WORD nAllEntityCount = 0;
+	IFFAILRET(func->GetEntityBusyRate(nBusyEntityCount, nAllEntityCount));
+	REQUIRE(nBusyEntityCount == 0);
+
+	CAutoArray<CSimpleStringA> spNames;
+	IFFAILRET(func->GetAllRegistSpFile(spNames));
+	REQUIRE(spNames.GetCount() > 0);
+	for (uint32_t i = 0; i < spNames.GetCount(); ++i) {
+		CSpInfo spInfo;
+		Dbg("Get %s 's SpFileInfo...", spNames[i].GetData());
+		IFFAILRET(func->GetSpFileInfo(spNames[i], spInfo));
+	}
+
+	CAutoArray<CSimpleStringA> strRegistEntityNames;
+	CAutoArray<WORD> strEntityDevIDs;
+	IFFAILRET(func->GetAllRegistedEntity(strRegistEntityNames, strEntityDevIDs));
+	REQUIRE(strRegistEntityNames.GetCount() > 0);
+
+
+	CAutoArray<CSimpleStringA> strStartedEntityNames;
+	CAutoArray<DWORD> strEntityInstanceIDs;
+	IFFAILRET(func->GetAllStartedEntity(strStartedEntityNames, strEntityInstanceIDs));
+	REQUIRE(strStartedEntityNames.GetCount() > 0);
+	REQUIRE(strStartedEntityNames.GetCount() == strEntityInstanceIDs.GetCount());
+	for (int i = 0; i < strStartedEntityNames.GetCount(); ++i) {
+		CEntityRunInfo curRunInfo;
+		IFFAILRET(func->GetEntityRunInfo(strStartedEntityNames[i], curRunInfo));
+		CAutoArray<CEntitySessionInfo> sesInfos;
+		IFFAILRET(func->GetEntitySessionInfo(strStartedEntityNames[i], sesInfos));
+		CSimpleStringA strEntityName;
+		IFFAILRET(func->GetEntityName(strEntityInstanceIDs[i], strEntityName));
+		REQUIRE(strEntityName.Compare(strStartedEntityNames[i]) == 0);
+	}
+
+	CEntityRunInfo entRunInfo;
+	IFFAILRET(func->GetSelfEntityRunInfo(entRunInfo));
+
+	CSmartPointer<IConfigInfo> configInfoPtr = NULL;
+	IFFAILRET(func->OpenConfig(Config_Hardware, configInfoPtr));
+	REQUIRE(configInfoPtr != NULL);
+
+	configInfoPtr = NULL;
+	IFFAILRET(func->OpenConfig(Config_Software, configInfoPtr));
+	REQUIRE(configInfoPtr != NULL);
+
+	configInfoPtr = NULL;
+	IFFAILRET(func->OpenConfig(Config_Run, configInfoPtr));
+	REQUIRE(configInfoPtr != NULL);
+
+	configInfoPtr = NULL;
+	IFFAILRET(func->OpenConfig(Config_Shell, configInfoPtr));
+	REQUIRE(configInfoPtr != NULL);
+
+	configInfoPtr = NULL;
+	IFFAILRET(func->OpenConfig(Config_Root, configInfoPtr));
+	REQUIRE(configInfoPtr != NULL);
+
+	configInfoPtr = NULL;
+	IFFAILRET(func->OpenConfig(Config_CenterSetting, configInfoPtr));
+	REQUIRE(configInfoPtr != NULL);
+
+	return Error_Succeed;
+}
+
+SP_BEGIN_ENTITY_MAP()
+	SP_ENTITY(CNormalEntityTest)
+SP_END_ENTITY_MAP()

+ 15 - 0
module/mod_testPassiveEntity/CMakeLists.txt

@@ -0,0 +1,15 @@
+# 定义实体名称
+define_moudle("testPassiveEntity")
+
+set(${MODULE_PREFIX}_SRCS
+	mod_testPassiveEntity.cpp
+	mod_viceEntities.hpp
+	)
+
+add_module_libraries(${MODULE_PREFIX} ${MODULE_NAME})
+
+# 添加实体需要依赖的其他共享库(包括系统库)
+set(${MODULE_PREFIX}_LIBS spbase winpr)
+target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
+
+deploy_module(${MODULE_PREFIX} ${MODULE_NAME})

+ 54 - 0
module/mod_testPassiveEntity/mod_testPassiveEntity.cpp

@@ -0,0 +1,54 @@
+#include "stdafx.h"
+#include "SpBase.h"
+
+#include "mod_viceEntities.hpp"
+
+/*one of test module: use to boot by other entity which has higher privilege.*/
+
+class CPassiveFirstEntity : public CEntityBase
+{
+public:
+	CPassiveFirstEntity() {}
+	virtual ~CPassiveFirstEntity() {}
+	virtual const char *GetEntityName() const { return "TestPassiveEntity"; }
+	void OnPreStart(CAutoArray<CSimpleStringA> strArgs, CSmartPointer<ITransactionContext> pTransactionContext)
+	{
+		LOG_FUNCTION();
+		for (int i = 0; i < strArgs.GetCount(); ++i) {
+			Dbg("args[%d]: %s", i, strArgs[i]);
+		}
+		pTransactionContext->SendAnswer(__onTest(strArgs));
+	}
+	void OnStarted()
+	{
+		LOG_FUNCTION();
+	}
+	void OnPreClose(EntityCloseCauseEnum eCloseCause,CSmartPointer<ITransactionContext> pTransactionContext) 
+	{ 
+		LOG_FUNCTION();
+		pTransactionContext->SendAnswer(Error_Succeed); 
+	}
+
+private:
+	ErrorCodeEnum __onTest(const CAutoArray<CSimpleStringA>& strArgs)
+	{
+		/*see request information at mod_testPrivilegeEntitiy::__onTest scope.*/
+		Dbg("strArgs count: %d", strArgs.GetCount());
+		REQUIRE(strArgs.GetCount() == 5);
+		REQUIRE(strArgs[0].Compare("param1") == 0);
+		REQUIRE(strArgs[1].Compare("2") == 0);
+		REQUIRE(strArgs[2].Compare("I am a bank") == 0);
+		REQUIRE(strArgs[3].Compare("-mode") == 0);
+		REQUIRE(strArgs[4].Compare("test") == 0);
+
+		return Error_Succeed;
+	}
+};
+/*
+if define more than one entity at module, you should regist all entities at one {SP_BEGIN_ENTITY_MAP} MACRO
+*/
+SP_BEGIN_ENTITY_MAP()
+	SP_ENTITY(CPassiveFirstEntity)
+	SP_ENTITY(CPassiveSecondEntity)
+	SP_ENTITY(CPassiveThirdEntity)
+SP_END_ENTITY_MAP()

+ 52 - 0
module/mod_testPassiveEntity/mod_viceEntities.hpp

@@ -0,0 +1,52 @@
+#ifndef _TEST_PASSIVE_VICE_ENTITIES_H_
+#define _TEST_PASSIVE_VICE_ENTITIES_H_
+
+#include "stdafx.h"
+#include "SpBase.h"
+#include "SpHelper.h"
+
+/*one of test module: use to simulate multi-entity at single module scope*/
+
+class CPassiveSecondEntity : public CEntityBase
+{
+public:
+	CPassiveSecondEntity() {}
+	virtual ~CPassiveSecondEntity() {}
+	virtual const char* GetEntityName() const { return "TestPassiveSecondEntity"; }
+	virtual void OnPreStart(CAutoArray<CSimpleStringA> strArgs, CSmartPointer<ITransactionContext> pTransactionContext)
+	{
+		LOG_FUNCTION();
+		pTransactionContext->SendAnswer(Error_Succeed);
+	}
+	virtual void OnPreClose(EntityCloseCauseEnum eCloseCause, CSmartPointer<ITransactionContext> pTransactionContext)
+	{
+		LOG_FUNCTION();
+		pTransactionContext->SendAnswer(Error_Succeed);
+	}
+};
+
+class CPassiveThirdEntity : public CEntityBase
+{
+public:
+	CPassiveThirdEntity() {}
+	virtual ~CPassiveThirdEntity() {}
+	virtual const char* GetEntityName() const { return "TestPassiveThirdEntity"; }
+	virtual void OnPreStart(CAutoArray<CSimpleStringA> strArgs, CSmartPointer<ITransactionContext> pTransactionContext)
+	{
+		LOG_FUNCTION();
+		pTransactionContext->SendAnswer(Error_Succeed);
+	}
+	virtual void OnPreClose(EntityCloseCauseEnum eCloseCause, CSmartPointer<ITransactionContext> pTransactionContext)
+	{
+		LOG_FUNCTION();
+		pTransactionContext->SendAnswer(Error_Succeed);
+	}
+};
+
+//SP_BEGIN_ENTITY_MAP()
+//SP_ENTITY(CPassiveSecondEntity)
+//SP_ENTITY(CPassiveThirdEntity)
+//SP_END_ENTITY_MAP()
+
+
+#endif //_TEST_PASSIVE_VICE_ENTITIES_H_

+ 13 - 0
module/mod_testPrivilegeEntity/CMakeLists.txt

@@ -0,0 +1,13 @@
+# 定义实体名称
+define_moudle("testPrivilegeEntity")
+
+set(${MODULE_PREFIX}_SRCS
+	mod_testPrivilegeEntity.cpp)
+
+add_module_libraries(${MODULE_PREFIX} ${MODULE_NAME})
+
+# 添加实体需要依赖的其他共享库(包括系统库)
+set(${MODULE_PREFIX}_LIBS spbase winpr)
+target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
+
+deploy_module(${MODULE_PREFIX} ${MODULE_NAME})

+ 211 - 0
module/mod_testPrivilegeEntity/mod_testPrivilegeEntity.cpp

@@ -0,0 +1,211 @@
+#include "stdafx.h"
+#include "SpBase.h"
+#include "SpHelper.h"
+
+const char* CHILD_TEST_ENTITY_NAME = "TestPassiveEntity";
+
+class CPrivilegeEntityTest : public CEntityBase, public IEntityLifeListener, public IEntityStateListener
+{
+public:
+	CPrivilegeEntityTest() {}
+	virtual ~CPrivilegeEntityTest() {}
+	virtual const char *GetEntityName() const { return "TestPrivilegeEntity"; }
+
+	virtual void OnPreStart(CAutoArray<CSimpleStringA> strArgs, CSmartPointer<ITransactionContext> pTransactionContext)
+	{
+		LOG_FUNCTION();
+		pTransactionContext->SendAnswer(_onTest());
+	}
+
+	void OnStarted()
+	{
+		LOG_FUNCTION();
+	}
+
+	void OnPreClose(EntityCloseCauseEnum eCloseCause,CSmartPointer<ITransactionContext> pTransactionContext) 
+	{ 
+		LOG_FUNCTION();
+		pTransactionContext->SendAnswer(Error_Succeed); 
+	}
+
+	//IEntityLifeListener
+	void OnCreated(const char* pszEntityName, ErrorCodeEnum eOnStartErrorCode, const char* pszCallerEntity)
+	{
+		LogEvent(Severity_High, 0, CSimpleStringA::Format("OnCreated: %s, %s, %s, ",
+				pszEntityName, pszCallerEntity, SpStrError(eOnStartErrorCode)));
+	}
+
+	void OnClosed(const char* pszEntityName, 
+		EntityCloseCauseEnum eCloseCause, 
+		ErrorCodeEnum eOnCloseErrorCode,
+		const char* pszCallerEntity)
+	{
+		if (strcmp(pszEntityName, CHILD_TEST_ENTITY_NAME) != 0) {
+			LogError(Severity_High, Error_Unexpect, 0,
+				CSimpleStringA::Format("OnClosed: %s, %s, %d, %s, ",
+					pszEntityName, pszCallerEntity, (int)eCloseCause, SpStrError(eOnCloseErrorCode)));
+		}
+		else {
+			Dbg("OnClosed: %s, %s, %d, %s, ",
+				pszEntityName, pszCallerEntity, (int)eCloseCause, SpStrError(eOnCloseErrorCode));
+		}
+	}
+	void OnException(const char* pszEntityName, 
+		const char* pszFunctionName,
+		EntityStateEnum eState, 
+		EntityStateEnum eLastState, 
+		ErrorCodeEnum eErrorCode)
+	{
+		if (strcmp(pszEntityName, CHILD_TEST_ENTITY_NAME) != 0) {
+			LogError(Severity_High, Error_Unexpect, 0,
+				CSimpleStringA::Format("OnException: %s, %s, %d from %d: ec:%s",
+					pszEntityName, pszFunctionName, (int)eState, (int)eLastState, SpStrError(eErrorCode)));
+		}
+		else {
+			Dbg("OnException: %s, %s, %d from %d: ec:%s",
+				pszEntityName, pszFunctionName, (int)eState, (int)eLastState, SpStrError(eErrorCode));
+		}
+	}
+	//IEntityStateListener
+	void OnEntityStateHook(const char* pszEntityName, 
+		const char* pszTriggerEntity, 
+		EntityStateEnum eState, 
+		EntityStateEnum eLastState)
+	{
+		if (strcmp(pszEntityName, CHILD_TEST_ENTITY_NAME) != 0) {
+			LogError(Severity_High, Error_Unexpect, 0,
+				CSimpleStringA::Format("OnEntityStateHook: %s, %s, %d from %d", pszEntityName, pszTriggerEntity, (int)eState, (int)eLastState));
+		}
+		else {
+			Dbg("OnEntityStateHook: %s, %s, %d from %d", pszEntityName, pszTriggerEntity, (int)eState, (int)eLastState);
+		}
+	}
+
+	void OnUserStateHook(const char* pszEntityName, DWORD dwState, DWORD dwLastState)
+	{
+		if (strcmp(pszEntityName, CHILD_TEST_ENTITY_NAME) != 0) {
+			LogError(Severity_High, Error_Unexpect, 0,
+				CSimpleStringA::Format("OnUserStateHook: %s, %d from %d", pszEntityName, dwState, dwLastState));
+		}
+		else {
+			Dbg("OnUserStateHook: %s, %d from %d", pszEntityName, dwState, dwLastState);
+		}
+	}
+
+	void OnCeateConnection(const char* pszCallerEntity, const char* pszServiceEntity)
+	{
+		Dbg("OnCeateConnection: %s, %s", pszCallerEntity, pszServiceEntity);
+	}
+
+	void OnCloseConnection(const char* pszCallerEntity, const char* pszServiceEntity)
+	{
+		Dbg("OnCloseConnection: %s, %s", pszCallerEntity, pszServiceEntity);
+	}
+
+private:
+	ErrorCodeEnum _onTest();
+};
+
+ErrorCodeEnum CPrivilegeEntityTest::_onTest()
+{
+	REQUIRE(GetFunction()->HasPrivilege());
+	auto privilegeFunc = GetFunction()->GetPrivilegeFunction();
+	REQUIRE(privilegeFunc != NULL);
+
+	CSmartPointer<IAsynWaitSp> spWait;
+	REQUIRE(Error_Null == privilegeFunc->PauseEntity(NULL, spWait));
+	REQUIRE(Error_Param == privilegeFunc->PauseEntity("", spWait));
+	REQUIRE(Error_NotExist == privilegeFunc->PauseEntity("NoExistedEntity", spWait));
+
+
+	IFFAILRET(privilegeFunc->StartEntity(CHILD_TEST_ENTITY_NAME, "param1 2 \"I am a bank\" -mode test", spWait));
+	REQUIRE(spWait != NULL);
+	IFFAILRET(spWait->WaitAnswer(10000));
+
+	IFFAILRET(privilegeFunc->RegistEntityLifeEvent(this));
+	IFFAILRET(privilegeFunc->RegistEntityStateEvent(CHILD_TEST_ENTITY_NAME, this));
+
+	//start other brother entity.
+	Dbg("Try to start TestPassiveSecondEntity entity");
+	spWait = NULL;
+	IFFAILRET(privilegeFunc->StartEntity("TestPassiveSecondEntity", NULL, spWait));
+	REQUIRE(spWait != NULL);
+	IFFAILRET(spWait->WaitAnswer(10000));
+
+	Dbg("Try to start TestPassiveThirdEntity entity");
+	spWait = NULL;
+	IFFAILRET(privilegeFunc->StartEntity("TestPassiveThirdEntity", NULL, spWait));
+	REQUIRE(spWait != NULL);
+	IFFAILRET(spWait->WaitAnswer(10000));
+
+	//pause entity.
+	spWait = NULL;
+	IFFAILRET(privilegeFunc->PauseEntity(CHILD_TEST_ENTITY_NAME, spWait));
+	REQUIRE(spWait != NULL);
+	IFFAILRET(spWait->WaitAnswer(10000));
+
+	//pause the same entity again.
+	spWait = NULL;
+	//still send succ
+	IFFAILRET(privilegeFunc->PauseEntity(CHILD_TEST_ENTITY_NAME, spWait));
+	REQUIRE(spWait != NULL);
+	REQUIRE(Error_InvalidState == spWait->WaitAnswer(10000));
+
+	//continue entity.
+	spWait = NULL;
+	IFFAILRET(privilegeFunc->ContinueEntity(CHILD_TEST_ENTITY_NAME, spWait));
+	REQUIRE(spWait != NULL);
+	IFFAILRET(spWait->WaitAnswer(10000));
+
+	//continue the same entity again.
+	spWait = NULL;
+	REQUIRE(Error_Succeed == privilegeFunc->ContinueEntity(CHILD_TEST_ENTITY_NAME, spWait));
+	REQUIRE(spWait != NULL);
+	REQUIRE(Error_InvalidState == spWait->WaitAnswer(10000));
+
+	//stop entity equals CloseEntity
+	spWait = NULL;
+	IFFAILRET(privilegeFunc->StopEntity(CHILD_TEST_ENTITY_NAME, spWait));
+	REQUIRE(spWait != NULL);
+	IFFAILRET(spWait->WaitAnswer(10000));
+
+	//stop the same entity again.
+	spWait = NULL;
+	REQUIRE(Error_Succeed == privilegeFunc->StopEntity(CHILD_TEST_ENTITY_NAME, spWait));
+	REQUIRE(spWait != NULL);
+	REQUIRE_FALSE(Error_Succeed == spWait->WaitAnswer(10000));
+
+	//start entity again.
+	spWait = NULL;
+	IFFAILRET(privilegeFunc->StartEntity(CHILD_TEST_ENTITY_NAME, "param1 2 \"I am a bank\" -mode test", spWait));
+	REQUIRE(spWait != NULL);
+	IFFAILRET(spWait->WaitAnswer(10000));
+
+	//test entity in shakehand mode.
+	spWait = NULL;
+	IFFAILRET(privilegeFunc->TestEntity(CHILD_TEST_ENTITY_NAME, Test_ShakeHand, spWait));
+	REQUIRE(spWait != NULL);
+	IFFAILRET(spWait->WaitAnswer(10000));
+
+	//test entity in examine mode.
+	spWait = NULL;
+	IFFAILRET(privilegeFunc->TestEntity(CHILD_TEST_ENTITY_NAME, Test_Examine, spWait));
+	REQUIRE(spWait != NULL);
+	IFFAILRET(spWait->WaitAnswer(10000));
+
+	//test entity in reset mode.
+	spWait = NULL;
+	IFFAILRET(privilegeFunc->TestEntity(CHILD_TEST_ENTITY_NAME, Test_Reset, spWait));
+	REQUIRE(spWait != NULL);
+	IFFAILRET(spWait->WaitAnswer(10000));
+
+	CSmartPointer<IEntityFunctionPrivilege> privilegeFunc2 = GetFunction().ConvertCase<IEntityFunctionPrivilege>();
+	REQUIRE(privilegeFunc2 != NULL);
+	REQUIRE((uintptr_t)privilegeFunc2.GetRawPointer() == (uintptr_t)privilegeFunc.GetRawPointer());
+	IFFAILRET(privilegeFunc->UnregistEntityStateEvent(CHILD_TEST_ENTITY_NAME));
+	return Error_Succeed;
+}
+
+SP_BEGIN_ENTITY_MAP()
+	SP_ENTITY(CPrivilegeEntityTest)
+SP_END_ENTITY_MAP()

+ 3 - 0
spbase/SpBase.cpp

@@ -317,6 +317,9 @@ extern "C" SPBASE_API int __stdcall SpRun(const char *mod_name, int epid, int ra
 	}
 #endif //_WIN32
 
+	/*the log is separeted by {mod_name},so if there are gt one entity defined at one module,
+	*the log about each brother entity also store in same log file.
+	*/
 	sp_dbg_init(mod_name);
 
 	if (winsock_init() != 0) {

+ 4 - 1
spbase/SpEntityPrivilege.cpp

@@ -44,8 +44,11 @@ static ErrorCodeEnum ControlEntity(
 	int param1, int param2,
 	CSmartPointer<IAsynWaitSp> &pAsynWaitSp)
 {
-	if (!pszEntityName)
+	if (!pszEntityName) {
 		return Error_Null;
+	} else if (strlen(pszEntityName) == 0) {
+		return Error_Param;
+	}
 
 	sp_env_t *env = sp_get_env();
 	sp_entity_t *ent = sp_mod_mgr_find_entity_by_name(env->mod_mgr, pszEntityName);

+ 1 - 0
spbase/SpModule.cpp

@@ -164,6 +164,7 @@ ErrorCodeEnum SpModule::AddEntityBase(CEntityBase *pEntity)
 {
 	sp_env_t *env = sp_get_env();
 	const char *lpEntityName = pEntity->GetEntityName();
+	sp_dbg_debug("Initialize entity %s...", lpEntityName);
 	SpEntity *pSpEntity = FindEntity(lpEntityName);
 	if (pSpEntity) {
 		return Error_AlreadyExist;

+ 9 - 7
spbase/sp_mod.c

@@ -1745,8 +1745,10 @@ static int unload_module(sp_mod_mgr_t *mgr, sp_mod_t *mod, int trigger_entity_id
 		if (rc == 0) {
 			ResetEvent(mod->evt_wait_handle);
 			rc = sp_svc_send(mod->mgr->shell_svc, mod->cfg->idx, SP_INVALID_SVC_ID, SP_PKT_MOD|MOD_CMD_TERM, 0, NULL);
-			if (rc != 0) {
-				sp_dbg_debug("unload %s module, send pkt cmd failed!", mod->cfg->name);
+			if (rc == 0) {
+				sp_dbg_debug("unload %s module, send pkt cmd ok!", mod->cfg->name);
+			} else  {
+				sp_dbg_error("unload %s module, send pkt cmd failed: %d!", mod->cfg->name, rc);
 			}
 		}
 	} else {
@@ -1781,7 +1783,7 @@ static int unload_module(sp_mod_mgr_t *mgr, sp_mod_t *mod, int trigger_entity_id
 						WaitForSingleObject(mod->process.handle, PROCESS_EXIT_TIMEOUT);
 						process_close(&mod->process);
 						break;
-					}
+					} //TODO: 
 				} else {
 					HANDLE hprocess = mod->process.handle;
 					if (hprocess && process_monitor_remove(mgr->process_monitor, &mod->process) == 0) {
@@ -2016,7 +2018,7 @@ static int stop_entity(sp_mod_mgr_t *mgr, sp_entity_t *ent, int trigger_entity_i
 #else
 	sp_mod_mgr_lock(mgr);
 #endif //_WIN32
-	if (mod->state) {
+	if (mod->state) {//judge module state
 		if (ent->state == EntityState_Busy || ent->state == EntityState_Idle || ent->state == EntityState_Pause) {
 			iobuffer_t *body = iobuffer_create(-1, -1);
 			ResetEvent(ent->evt_wait_handle);
@@ -2039,7 +2041,7 @@ static int stop_entity(sp_mod_mgr_t *mgr, sp_entity_t *ent, int trigger_entity_i
 			sp_dbg_debug("entity %s state is not correct, you may call TerminateEntity first!", ent->cfg->name);
 		}
 	} else {
-		sp_dbg_debug("entity's %s mod %s is not load or is pending!", ent->cfg->name, mod->cfg->name);
+		sp_dbg_warn("%s's mod %s is not load or is pending!", ent->cfg->name, mod->cfg->name);
 		rc = Error_Pending;
 	}
 #ifdef _WIN32
@@ -2051,7 +2053,7 @@ static int stop_entity(sp_mod_mgr_t *mgr, sp_entity_t *ent, int trigger_entity_i
 	if (rc == 0) {
 		int last_state = ent->state;
 		HANDLE hs[] = {mod->evt_app_exit, ent->evt_wait_handle};
-		DWORD dwRet = WaitForMultipleObjects(array_size(hs), &hs[0], FALSE, PROCESS_TIMEOUT);
+		DWORD dwRet = WaitForMultipleObjects(array_size(hs), &hs[0], FALSE, PROCESS_TIMEOUT); //2mins
 		if (dwRet == WAIT_OBJECT_0) {
 			sp_dbg_debug("wait for stop entity %s result, app exit!", ent->cfg->name);
 			rc = Error_Unexpect;
@@ -2114,7 +2116,7 @@ static int pause_entity(sp_mod_mgr_t *mgr, sp_entity_t *ent, int trigger_entity_
 				iobuffer_dec_ref(body);
 		} else {
 			rc = Error_InvalidState;
-			sp_dbg_debug("entity %s state is not correct!", ent->cfg->name);
+			sp_dbg_debug("entity %s state is not correct! current state: %d", ent->cfg->name, (int)ent->state);
 		}
 	} else {
 		sp_dbg_debug("entity's %s mod %s is not load or is pending!", ent->cfg->name, mod->cfg->name);

+ 1 - 1
spbase/sp_mod.h

@@ -98,7 +98,7 @@ void *sp_mod_entity_life_listener_get_tag(sp_mod_entity_life_listener_t *listene
 
 
 #define SP_MODULE_STATE_UNLOAD		0
-#define SP_MODULE_STATE_LOAD		1
+#define SP_MODULE_STATE_LOAD		    1
 
 
 typedef struct sp_mod_mgr_t sp_mod_mgr_t;

+ 10 - 0
third_party/.gitignore

@@ -0,0 +1,10 @@
+*
+**/*
+
+!.gitignore
+!CMakeLists.txt
+!openssl-1.1.1d
+!openssl-1.1.1d/**/*
+#!nanomsg-1.1.5
+#!nanomsg-1.1.5/**/*
+**/.vs

+ 2 - 1
third_party/CMakeLists.txt

@@ -3,4 +3,5 @@ if(BUILD_TESTING)
 	add_subdirectory(gtest)
 endif()
 add_subdirectory(openssl-1.1.1d)
-# add_subdirectory(libuv-1.35.0)
+# add_subdirectory(libuv-1.35.0)
+# add_subdirectory(nanomsg-1.1.5)