You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@milagro.apache.org by sa...@apache.org on 2016/10/25 09:50:51 UTC

[3/4] incubator-milagro-mfa-sdk-core git commit: Use pre-recorded backend communication data in unit tests

Use pre-recorded backend communication data in unit tests

Added functionality for recording http communication data and for replaying it when needed in order to be able to execute unit test without any backend communication.
Added utility hexdump project (Windows only) for generating C/C++ includable array data from a file.

Closes: MAASMOB-325


Project: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/commit/ae986820
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/tree/ae986820
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/diff/ae986820

Branch: refs/heads/master
Commit: ae986820e4781f61fb2a4ea486d6f25e5471d84b
Parents: 5a6c03f
Author: Slav Klenov <sl...@miracl.com>
Authored: Thu Oct 13 13:27:12 2016 +0300
Committer: Slav Klenov <sl...@miracl.com>
Committed: Fri Oct 14 12:07:48 2016 +0300

----------------------------------------------------------------------
 .gitignore                                      |    1 +
 project/unit_tests/Makefile                     |    8 +-
 project/visual_studio_2015/mpin_sdk.sln         |   25 +-
 .../mpin_sdk_test_common.vcxproj                |   10 +
 .../mpin_sdk_test_common.vcxproj.filters        |   30 +
 project/visual_studio_2015/unit_tests.vcxproj   |    6 +
 src/utils.cpp                                   |   18 +
 src/utils.h                                     |    3 +
 tests/cmdline_test.cpp                          |   10 +-
 tests/common/access_number_thread.cpp           |   54 +-
 tests/common/access_number_thread.h             |   13 +
 tests/common/http_player.cpp                    |   71 +
 tests/common/http_player.h                      |   55 +
 tests/common/http_recorded_data.cpp             |  239 ++
 tests/common/http_recorded_data.h               |   85 +
 tests/common/http_recorder.cpp                  |   82 +
 tests/common/http_recorder.h                    |   55 +
 tests/common/test_context.cpp                   |  101 +
 tests/common/test_context.h                     |   66 +
 tests/common/test_mpin_sdk.cpp                  |  124 +
 tests/common/test_mpin_sdk.h                    |   56 +
 tests/contexts/auto_context.cpp                 |   21 +-
 tests/contexts/auto_context.h                   |    8 +-
 tests/contexts/cmdline_context.cpp              |   21 +-
 tests/contexts/cmdline_context.h                |    7 +-
 tests/unit_tests.cpp                            |  107 +-
 tests/unit_tests_recorded_data.json             | 2749 ++++++++++++++++++
 .../project/visual_studio_2015/hexdump.sln      |   28 +
 .../project/visual_studio_2015/hexdump.vcxproj  |  133 +
 .../visual_studio_2015/hexdump.vcxproj.filters  |   13 +
 tools/hexdump/src/main.cpp                      |   66 +
 31 files changed, 4162 insertions(+), 103 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/ae986820/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
index c32d55d..923ebdd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,3 +11,4 @@ dist/
 *tokens.json
 *users.json
 cvlog.txt
+unit_tests_recorded_data.inc

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/ae986820/project/unit_tests/Makefile
----------------------------------------------------------------------
diff --git a/project/unit_tests/Makefile b/project/unit_tests/Makefile
index 7a7d456..e390606 100644
--- a/project/unit_tests/Makefile
+++ b/project/unit_tests/Makefile
@@ -80,7 +80,7 @@ SRC = $(call add_src_dir, src)
 SRC += $(call add_src_dir_including, ext/cvshared/cpp, \
 		%linux/CvHttpRequest.cpp %linux/CvThread.cpp %linux/CvLogger.cpp %linux/CvMutex.cpp %CvString.cpp %CvTime.cpp %CvXcode.cpp)
 SRC += $(call add_src_dir_including, tests, \
-        %auto_context.cpp %access_number_thread.cpp %memory_storage.cpp %http_request.cpp %unit_tests.cpp)
+        %auto_context.cpp %access_number_thread.cpp %http_player.cpp %http_recorded_data.cpp %http_recorder.cpp %http_request.cpp %memory_storage.cpp %test_context.cpp %test_mpin_sdk.cpp %unit_tests.cpp)
 
 # Generate a list of object files
 OBJ = $(call cpp_to_obj, $(call c_to_obj, $(SRC)))
@@ -103,6 +103,12 @@ $(foreach cfile, $(C_SRC), $(eval $(call generate_c_rule, $(cfile), $(call c_to_
 # Generate rules for each object file that depends on the corresponding .cpp file
 $(foreach cppfile, $(CPP_SRC), $(eval $(call generate_cpp_rule, $(cppfile), $(call cpp_to_obj, $(cppfile)))))
 
+# Generate unit tests recorded data include file
+$(BUILD_DIR)/tests/unit_tests.o: $(SRC_DIR)/tests/unit_tests_recorded_data.inc
+
+$(SRC_DIR)/tests/unit_tests_recorded_data.inc: $(SRC_DIR)/tests/unit_tests_recorded_data.json
+	$(shell xxd -i < $< > $@)
+
 # Clean target
 clean:
 	rm -f -R build/** $(EXECUTABLE)

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/ae986820/project/visual_studio_2015/mpin_sdk.sln
----------------------------------------------------------------------
diff --git a/project/visual_studio_2015/mpin_sdk.sln b/project/visual_studio_2015/mpin_sdk.sln
index b4a1c59..07d2631 100644
--- a/project/visual_studio_2015/mpin_sdk.sln
+++ b/project/visual_studio_2015/mpin_sdk.sln
@@ -1,39 +1,62 @@
 \ufeff
 Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 2012
+# Visual Studio 14
+VisualStudioVersion = 14.0.25123.0
+MinimumVisualStudioVersion = 10.0.40219.1
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mpin_sdk", "mpin_sdk.vcxproj", "{C47BB154-F9DF-4C88-81C0-A27510A16840}"
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unit_tests", "unit_tests.vcxproj", "{A08A5798-A25B-4F9F-88A0-F196222A74F3}"
 	ProjectSection(ProjectDependencies) = postProject
 		{C47BB154-F9DF-4C88-81C0-A27510A16840} = {C47BB154-F9DF-4C88-81C0-A27510A16840}
+		{05D3A1E2-3385-4CB0-BC55-E09B851EBADD} = {05D3A1E2-3385-4CB0-BC55-E09B851EBADD}
 	EndProjectSection
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mpin_sdk_test", "mpin_sdk_test.vcxproj", "{39536C4B-3293-4AD4-951F-0C4D5BCE7219}"
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mpin_sdk_test_common", "mpin_sdk_test_common.vcxproj", "{AB7741C8-A26B-4D8D-A0BC-806B5AC86CD9}"
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hexdump", "..\..\tools\hexdump\project\visual_studio_2015\hexdump.vcxproj", "{05D3A1E2-3385-4CB0-BC55-E09B851EBADD}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Win32 = Debug|Win32
+		Debug|x64 = Debug|x64
 		Release|Win32 = Release|Win32
+		Release|x64 = Release|x64
 	EndGlobalSection
 	GlobalSection(ProjectConfigurationPlatforms) = postSolution
 		{C47BB154-F9DF-4C88-81C0-A27510A16840}.Debug|Win32.ActiveCfg = Debug|Win32
 		{C47BB154-F9DF-4C88-81C0-A27510A16840}.Debug|Win32.Build.0 = Debug|Win32
+		{C47BB154-F9DF-4C88-81C0-A27510A16840}.Debug|x64.ActiveCfg = Debug|Win32
 		{C47BB154-F9DF-4C88-81C0-A27510A16840}.Release|Win32.ActiveCfg = Release|Win32
 		{C47BB154-F9DF-4C88-81C0-A27510A16840}.Release|Win32.Build.0 = Release|Win32
+		{C47BB154-F9DF-4C88-81C0-A27510A16840}.Release|x64.ActiveCfg = Release|Win32
 		{A08A5798-A25B-4F9F-88A0-F196222A74F3}.Debug|Win32.ActiveCfg = Debug|Win32
 		{A08A5798-A25B-4F9F-88A0-F196222A74F3}.Debug|Win32.Build.0 = Debug|Win32
+		{A08A5798-A25B-4F9F-88A0-F196222A74F3}.Debug|x64.ActiveCfg = Debug|Win32
 		{A08A5798-A25B-4F9F-88A0-F196222A74F3}.Release|Win32.ActiveCfg = Release|Win32
 		{A08A5798-A25B-4F9F-88A0-F196222A74F3}.Release|Win32.Build.0 = Release|Win32
+		{A08A5798-A25B-4F9F-88A0-F196222A74F3}.Release|x64.ActiveCfg = Release|Win32
 		{39536C4B-3293-4AD4-951F-0C4D5BCE7219}.Debug|Win32.ActiveCfg = Debug|Win32
 		{39536C4B-3293-4AD4-951F-0C4D5BCE7219}.Debug|Win32.Build.0 = Debug|Win32
+		{39536C4B-3293-4AD4-951F-0C4D5BCE7219}.Debug|x64.ActiveCfg = Debug|Win32
 		{39536C4B-3293-4AD4-951F-0C4D5BCE7219}.Release|Win32.ActiveCfg = Release|Win32
 		{39536C4B-3293-4AD4-951F-0C4D5BCE7219}.Release|Win32.Build.0 = Release|Win32
+		{39536C4B-3293-4AD4-951F-0C4D5BCE7219}.Release|x64.ActiveCfg = Release|Win32
 		{AB7741C8-A26B-4D8D-A0BC-806B5AC86CD9}.Debug|Win32.ActiveCfg = Debug|Win32
 		{AB7741C8-A26B-4D8D-A0BC-806B5AC86CD9}.Debug|Win32.Build.0 = Debug|Win32
+		{AB7741C8-A26B-4D8D-A0BC-806B5AC86CD9}.Debug|x64.ActiveCfg = Debug|Win32
 		{AB7741C8-A26B-4D8D-A0BC-806B5AC86CD9}.Release|Win32.ActiveCfg = Release|Win32
 		{AB7741C8-A26B-4D8D-A0BC-806B5AC86CD9}.Release|Win32.Build.0 = Release|Win32
+		{AB7741C8-A26B-4D8D-A0BC-806B5AC86CD9}.Release|x64.ActiveCfg = Release|Win32
+		{05D3A1E2-3385-4CB0-BC55-E09B851EBADD}.Debug|Win32.ActiveCfg = Debug|Win32
+		{05D3A1E2-3385-4CB0-BC55-E09B851EBADD}.Debug|Win32.Build.0 = Debug|Win32
+		{05D3A1E2-3385-4CB0-BC55-E09B851EBADD}.Debug|x64.ActiveCfg = Debug|x64
+		{05D3A1E2-3385-4CB0-BC55-E09B851EBADD}.Debug|x64.Build.0 = Debug|x64
+		{05D3A1E2-3385-4CB0-BC55-E09B851EBADD}.Release|Win32.ActiveCfg = Release|Win32
+		{05D3A1E2-3385-4CB0-BC55-E09B851EBADD}.Release|Win32.Build.0 = Release|Win32
+		{05D3A1E2-3385-4CB0-BC55-E09B851EBADD}.Release|x64.ActiveCfg = Release|x64
+		{05D3A1E2-3385-4CB0-BC55-E09B851EBADD}.Release|x64.Build.0 = Release|x64
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/ae986820/project/visual_studio_2015/mpin_sdk_test_common.vcxproj
----------------------------------------------------------------------
diff --git a/project/visual_studio_2015/mpin_sdk_test_common.vcxproj b/project/visual_studio_2015/mpin_sdk_test_common.vcxproj
index 45face2..e621e45 100644
--- a/project/visual_studio_2015/mpin_sdk_test_common.vcxproj
+++ b/project/visual_studio_2015/mpin_sdk_test_common.vcxproj
@@ -75,14 +75,24 @@
   <ItemGroup>
     <ClCompile Include="..\..\tests\common\access_number_thread.cpp" />
     <ClCompile Include="..\..\tests\common\file_storage.cpp" />
+    <ClCompile Include="..\..\tests\common\http_player.cpp" />
+    <ClCompile Include="..\..\tests\common\http_recorded_data.cpp" />
+    <ClCompile Include="..\..\tests\common\http_recorder.cpp" />
     <ClCompile Include="..\..\tests\common\http_request.cpp" />
     <ClCompile Include="..\..\tests\common\memory_storage.cpp" />
+    <ClCompile Include="..\..\tests\common\test_context.cpp" />
+    <ClCompile Include="..\..\tests\common\test_mpin_sdk.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\tests\common\access_number_thread.h" />
     <ClInclude Include="..\..\tests\common\file_storage.h" />
+    <ClInclude Include="..\..\tests\common\http_player.h" />
+    <ClInclude Include="..\..\tests\common\http_recorded_data.h" />
+    <ClInclude Include="..\..\tests\common\http_recorder.h" />
     <ClInclude Include="..\..\tests\common\http_request.h" />
     <ClInclude Include="..\..\tests\common\memory_storage.h" />
+    <ClInclude Include="..\..\tests\common\test_context.h" />
+    <ClInclude Include="..\..\tests\common\test_mpin_sdk.h" />
   </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/ae986820/project/visual_studio_2015/mpin_sdk_test_common.vcxproj.filters
----------------------------------------------------------------------
diff --git a/project/visual_studio_2015/mpin_sdk_test_common.vcxproj.filters b/project/visual_studio_2015/mpin_sdk_test_common.vcxproj.filters
index 9c5aefc..fb4c962 100644
--- a/project/visual_studio_2015/mpin_sdk_test_common.vcxproj.filters
+++ b/project/visual_studio_2015/mpin_sdk_test_common.vcxproj.filters
@@ -18,6 +18,21 @@
     <ClCompile Include="..\..\tests\common\access_number_thread.cpp">
       <Filter>src</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\tests\common\http_recorder.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\tests\common\http_recorded_data.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\tests\common\http_player.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\tests\common\test_context.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\tests\common\test_mpin_sdk.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\tests\common\file_storage.h">
@@ -32,5 +47,20 @@
     <ClInclude Include="..\..\tests\common\access_number_thread.h">
       <Filter>src</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\tests\common\http_recorder.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\tests\common\http_recorded_data.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\tests\common\http_player.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\tests\common\test_context.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\tests\common\test_mpin_sdk.h">
+      <Filter>src</Filter>
+    </ClInclude>
   </ItemGroup>
 </Project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/ae986820/project/visual_studio_2015/unit_tests.vcxproj
----------------------------------------------------------------------
diff --git a/project/visual_studio_2015/unit_tests.vcxproj b/project/visual_studio_2015/unit_tests.vcxproj
index be27489..96d0fdb 100644
--- a/project/visual_studio_2015/unit_tests.vcxproj
+++ b/project/visual_studio_2015/unit_tests.vcxproj
@@ -57,6 +57,9 @@
       <AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;WinHttp.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <SubSystem>Console</SubSystem>
     </Link>
+    <PreBuildEvent>
+      <Command>..\..\tools\hexdump\bin\hexdump.exe &lt; ..\..\tests\unit_tests_recorded_data.json &gt; ..\..\tests\unit_tests_recorded_data.inc</Command>
+    </PreBuildEvent>
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
     <ClCompile>
@@ -72,6 +75,9 @@
       <OptimizeReferences>true</OptimizeReferences>
       <AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;WinHttp.lib;%(AdditionalDependencies)</AdditionalDependencies>
     </Link>
+    <PreBuildEvent>
+      <Command>..\..\tools\hexdump\bin\hexdump.exe &lt; ..\..\tests\unit_tests_recorded_data.json &gt; ..\..\tests\unit_tests_recorded_data.inc</Command>
+    </PreBuildEvent>
   </ItemDefinitionGroup>
   <ItemGroup>
     <ClCompile Include="..\..\tests\contexts\auto_context.cpp" />

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/ae986820/src/utils.cpp
----------------------------------------------------------------------
diff --git a/src/utils.cpp b/src/utils.cpp
index 045e25e..4e70298 100644
--- a/src/utils.cpp
+++ b/src/utils.cpp
@@ -251,6 +251,24 @@ void OverwriteJsonValues(json::UnknownElement& element)
  * StringMap class
  */
 
+StringMap::StringMap(const json::Object & object)
+{
+    for (json::Object::const_iterator i = object.Begin(); i != object.End(); ++i)
+    {
+        (*this)[i->name] = ((const json::String&) i->element).Value();
+    }
+}
+
+json::Object StringMap::ToJsonObject() const
+{
+    json::Object object;
+    for (StringMap::const_iterator i = begin(); i != end(); ++i)
+    {
+        object[i->first] = json::String(i->second);
+    }
+    return object;
+}
+
 bool StringMap::Put(const String& key, const String& value)
 {
     iterator i = find(key);

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/ae986820/src/utils.h
----------------------------------------------------------------------
diff --git a/src/utils.h b/src/utils.h
index 2391da9..20ae803 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -82,6 +82,9 @@ void OverwriteJsonValues(json::UnknownElement& element);
 class StringMap : public std::map<String, String>
 {
 public:
+    StringMap() {}
+    StringMap(const json::Object& object);
+    json::Object ToJsonObject() const;
     bool Put(const String& key, const String& value);
     const char * Get(const String& key) const;
 };

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/ae986820/tests/cmdline_test.cpp
----------------------------------------------------------------------
diff --git a/tests/cmdline_test.cpp b/tests/cmdline_test.cpp
index d08336b..103b60b 100644
--- a/tests/cmdline_test.cpp
+++ b/tests/cmdline_test.cpp
@@ -18,12 +18,10 @@ under the License.
 */
 
 #include <iostream>
-#include <fstream>
 #include <conio.h>
-#include <map>
 #include <vector>
 
-#include "mpin_sdk.h"
+#include "common/test_mpin_sdk.h"
 #include "contexts/cmdline_context.h"
 #include "CvLogger.h"
 
@@ -63,11 +61,13 @@ int main(int argc, char *argv[])
     }
 
     CmdLineContext context("windows_test_users.json", "windows_test_tokens.json");
-    MPinSDK sdk;
+    //context.EnterRequestRecorderMode("cmdline_recorded_data.json");
+    //context.EnterRequestPlayerMode("cmdline_recorded_data.json");
+    TestMPinSDK sdk(context);
 
     cout << "Using MPinSDK version " << sdk.GetVersion() << endl;
 
-    MPinSDK::Status s = sdk.Init(config, &context);
+    MPinSDK::Status s = sdk.Init(config);
     if(s != MPinSDK::Status::OK)
     {
         cout << "Failed to initialize MPinSDK: status code = " << s.GetStatusCode() << ", error: " << s.GetErrorMessage() << endl;

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/ae986820/tests/common/access_number_thread.cpp
----------------------------------------------------------------------
diff --git a/tests/common/access_number_thread.cpp b/tests/common/access_number_thread.cpp
index 7f626e3..77756c1 100644
--- a/tests/common/access_number_thread.cpp
+++ b/tests/common/access_number_thread.cpp
@@ -18,21 +18,31 @@ under the License.
 */
 
 #include "access_number_thread.h"
-#include "../common/http_request.h"
 #include "CvTime.h"
 
+AccessNumberThread::AccessNumberThread(TestContext & context) : m_context(context), m_req(NULL), m_finished(false)
+{
+    m_mutex.Create();
+}
+
+AccessNumberThread::~AccessNumberThread()
+{
+    WaitWhileFinished();
+}
+
 void AccessNumberThread::Start(const String& backend, const String& webOTT, const String& authenticateURL)
 {
     m_backend = backend;
     m_webOTT = webOTT;
     m_authenticateURL = authenticateURL;
+    m_finished = false;
+    m_req = m_context.CreateHttpRequest();
     Create(NULL);
 }
 
 long AccessNumberThread::Body(void*)
 {
-    HttpRequest req;
-    HttpRequest::StringMap headers;
+    StringMap headers;
     headers.Put("Content-Type", "application/json");
     headers.Put("Accept", "*/*");
 
@@ -43,24 +53,46 @@ long AccessNumberThread::Body(void*)
     String url = String().Format("%s/rps/accessnumber", m_backend.c_str());
 
     int retryCount = 0;
-    while(req.GetHttpStatusCode() != 200 && retryCount++ < MAX_TRIES)
+    while(m_req->GetHttpStatusCode() != 200 && retryCount++ < MAX_TRIES)
     {
         CvShared::SleepFor(CvShared::Millisecs(RETRY_INTERVAL_MILLISEC).Value());
 
-        req.SetHeaders(headers);
-        req.SetContent(payload);
-        req.Execute(MPinSDK::IHttpRequest::POST, url);
+        m_req->SetHeaders(headers);
+        m_req->SetContent(payload);
+        m_req->Execute(MPinSDK::IHttpRequest::POST, url);
     }
 
     json.Clear();
     util::JsonObject mpinResponse;
-    mpinResponse.Parse(req.GetResponseData().c_str());
+    mpinResponse.Parse(m_req->GetResponseData().c_str());
     json["mpinResponse"] = mpinResponse;
     payload = json.ToString();
 
-    req.SetHeaders(headers);
-    req.SetContent(payload);
-    req.Execute(MPinSDK::IHttpRequest::POST, m_authenticateURL);
+    m_req->SetHeaders(headers);
+    m_req->SetContent(payload);
+    m_req->Execute(MPinSDK::IHttpRequest::POST, m_authenticateURL);
+
+    m_context.ReleaseHttpRequest(m_req);
+    m_req = NULL;
+
+    {
+        CvShared::CvMutexLock lock(m_mutex);
+        m_finished = true;
+    }
 
     return 0;
 }
+
+bool AccessNumberThread::IsFinished()
+{
+    CvShared::CvMutexLock lock(m_mutex);
+    return m_finished;
+}
+
+void AccessNumberThread::WaitWhileFinished()
+{
+    while (!IsFinished())
+    {
+        CvShared::SleepFor(CvShared::Millisecs(WAIT_INTERVAL_MILLISEC).Value());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/ae986820/tests/common/access_number_thread.h
----------------------------------------------------------------------
diff --git a/tests/common/access_number_thread.h b/tests/common/access_number_thread.h
index bb475be..e6bb138 100644
--- a/tests/common/access_number_thread.h
+++ b/tests/common/access_number_thread.h
@@ -21,23 +21,36 @@ under the License.
 #define _MPIN_SDK_TEST_ACCESS_NUMBER_THREAD_H_
 
 #include "mpin_sdk.h"
+#include "test_context.h"
 #include "CvThread.h"
+#include "CvMutex.h"
 
 class AccessNumberThread : public CvShared::CvThread
 {
 public:
     typedef MPinSDK::String String;
+    typedef MPinSDK::StringMap StringMap;
+    typedef MPinSDK::IHttpRequest IHttpRequest;
 
+    AccessNumberThread(TestContext& context);
+    virtual ~AccessNumberThread();
     void Start(const String& backend, const String& webOTT, const String& authenticateURL);
     virtual long Body(void*);
+    bool IsFinished();
+    void WaitWhileFinished();
 
     static const int MAX_TRIES = 5;
     static const int RETRY_INTERVAL_MILLISEC = 1000;
+    static const int WAIT_INTERVAL_MILLISEC = 100;
 
 private:
     String m_backend;
     String m_webOTT;
     String m_authenticateURL;
+    TestContext& m_context;
+    IHttpRequest *m_req;
+    bool m_finished;
+    CvShared::CvMutex m_mutex;
 };
 
 #endif // _MPIN_SDK_TEST_ACCESS_NUMBER_THREAD_H_

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/ae986820/tests/common/http_player.cpp
----------------------------------------------------------------------
diff --git a/tests/common/http_player.cpp b/tests/common/http_player.cpp
new file mode 100644
index 0000000..bef53f9
--- /dev/null
+++ b/tests/common/http_player.cpp
@@ -0,0 +1,71 @@
+/*
+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.
+*/
+
+/*
+ * MPinSDK::IHttpRequest implementation used for to reproduce recorded http requests
+ */
+
+#include "http_player.h"
+
+typedef MPinSDK::String String;
+typedef MPinSDK::StringMap StringMap;
+
+void HttpPlayer::SetHeaders(const StringMap & headers)
+{
+}
+
+void HttpPlayer::SetQueryParams(const StringMap & queryParams)
+{
+    assert(false);
+}
+
+void HttpPlayer::SetContent(const String & data)
+{
+    m_requestData = data;
+}
+
+void HttpPlayer::SetTimeout(int seconds)
+{
+}
+
+bool HttpPlayer::Execute(Method method, const String & url)
+{
+    m_response = m_recordedData.FindResponseFor(Request(method, url, m_requestData, m_context));
+    return m_response.success;
+}
+
+const String & HttpPlayer::GetExecuteErrorMessage() const
+{
+    return m_response.error;
+}
+
+int HttpPlayer::GetHttpStatusCode() const
+{
+    return m_response.httpStatus;
+}
+
+const StringMap & HttpPlayer::GetResponseHeaders() const
+{
+    return m_response.headers;
+}
+
+const String & HttpPlayer::GetResponseData() const
+{
+    return m_response.data;
+}

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/ae986820/tests/common/http_player.h
----------------------------------------------------------------------
diff --git a/tests/common/http_player.h b/tests/common/http_player.h
new file mode 100644
index 0000000..a1be0e9
--- /dev/null
+++ b/tests/common/http_player.h
@@ -0,0 +1,55 @@
+/*
+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.
+*/
+
+/*
+ * MPinSDK::IHttpRequest implementation used for to reproduce recorded http requests
+ */
+
+#ifndef _TEST_HTTP_PLAYER_H_
+#define _TEST_HTTP_PLAYER_H_
+
+#include "http_recorded_data.h"
+
+class HttpPlayer : public MPinSDK::IHttpRequest
+{
+public:
+    typedef MPinSDK::String String;
+    typedef MPinSDK::StringMap StringMap;
+    typedef HttpRecordedData::Request Request;
+    typedef HttpRecordedData::Response Response;
+
+    HttpPlayer(HttpRecordedData& recordedData, const String& context) : m_recordedData(recordedData), m_context(context) {}
+    virtual void SetHeaders(const StringMap& headers);
+    virtual void SetQueryParams(const StringMap& queryParams);
+    virtual void SetContent(const String& data);
+    virtual void SetTimeout(int seconds);
+    virtual bool Execute(Method method, const String& url);
+    virtual const String& GetExecuteErrorMessage() const;
+    virtual int GetHttpStatusCode() const;
+    virtual const StringMap& GetResponseHeaders() const;
+    virtual const String& GetResponseData() const;
+
+private:
+    String m_requestData;
+    HttpRecordedData& m_recordedData;
+    String m_context;
+    Response m_response;
+};
+
+#endif // _TEST_HTTP_PLAYER_H_

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/ae986820/tests/common/http_recorded_data.cpp
----------------------------------------------------------------------
diff --git a/tests/common/http_recorded_data.cpp b/tests/common/http_recorded_data.cpp
new file mode 100644
index 0000000..dcde68a
--- /dev/null
+++ b/tests/common/http_recorded_data.cpp
@@ -0,0 +1,239 @@
+/*
+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.
+*/
+
+/*
+ * Http requests recorded data
+ */
+
+#include "http_recorded_data.h"
+#include <fstream>
+
+using std::fstream;
+using std::cerr;
+using std::endl;
+
+typedef MPinSDK::String String;
+typedef MPinSDK::IHttpRequest IHttpRequest;
+typedef HttpRecordedData::Request Request;
+typedef HttpRecordedData::Response Response;
+
+namespace
+{
+    String MethodToString(IHttpRequest::Method method)
+    {
+        switch (method)
+        {
+        case IHttpRequest::GET:
+            return "GET";
+        case IHttpRequest::POST:
+            return "POST";
+        case IHttpRequest::PUT:
+            return "PUT";
+        case IHttpRequest::DELETE:
+            return "DELETE";
+        case IHttpRequest::OPTIONS:
+        case IHttpRequest::PATCH:
+        default:
+            assert(false);
+            return "Unknown";
+        }
+    }
+
+    bool operator==(const Response& left, const Response& right)
+    {
+        if (left.success != right.success)
+        {
+            return false;
+        }
+
+        if (!left.success)
+        {
+            return true;
+        }
+
+        if (left.httpStatus != right.httpStatus)
+        {
+            return false;
+        }
+
+        if (left.httpStatus != 200)
+        {
+            return true;
+        }
+
+        return left.data == right.data;
+    }
+}
+
+HttpRecordedData::Request::Request()
+{
+}
+
+HttpRecordedData::Request::Request(IHttpRequest::Method _method, const String & _url, const String & _data, const String& _context) :
+    method(MethodToString(_method)), url(_url), data(_data), context(_context)
+{
+}
+
+HttpRecordedData::Request::Request(const json::Object & object) :
+    method(((const json::String&) object["method"]).Value()),
+    url(((const json::String&) object["url"]).Value()),
+    data(((const json::String&) object["data"]).Value()),
+    context(((const json::String&) object["context"]).Value())
+{
+}
+
+json::Object HttpRecordedData::Request::ToJsonObject() const
+{
+    json::Object object;
+    object["method"] = json::String(method);
+    object["url"] = json::String(url);
+    object["data"] = json::String(data);
+    object["context"] = json::String(context);
+    return object;
+}
+
+String HttpRecordedData::Request::GetKey() const
+{
+    return method + " " + url + " " + context;
+}
+
+HttpRecordedData::Response::Response() : success(false), httpStatus(0)
+{
+}
+
+HttpRecordedData::Response::Response(bool _success, const String & _error, int _httpStatus, const StringMap & _headers, const String & _data) :
+    success(_success), error(_error), httpStatus(_httpStatus), headers(_headers), data(_data)
+{
+}
+
+HttpRecordedData::Response::Response(const json::Object & object) :
+    success(((const json::Boolean&) object["success"]).Value()),
+    error(((const json::String&) object["error"]).Value()),
+    httpStatus(static_cast<int>(((const json::Number&) object["httpStatus"]).Value())),
+    headers(object["headers"]),
+    data(((const json::String&) object["data"]).Value())
+{
+}
+
+json::Object HttpRecordedData::Response::ToJsonObject() const
+{
+    json::Object object;
+    object["success"] = json::Boolean(success);
+    object["error"] = json::String(error);
+    object["httpStatus"] = json::Number(httpStatus);
+    object["headers"] = headers.ToJsonObject();
+    object["data"] = json::String(data);
+    return object;
+}
+
+String HttpRecordedData::Response::ToString() const
+{
+    return success ? (String().Format("%d ", httpStatus) + data) : ("ERROR: " + error);
+}
+
+HttpRecordedData::HttpRecordedData()
+{
+    m_addRecordMutex.Create();
+}
+
+void HttpRecordedData::Record(const Request & request, const Response & response)
+{
+    CvShared::CvMutexLock lock(m_addRecordMutex);
+    if (AddMapping(request, response))
+    {
+        json::Object record;
+        record["request"] = request.ToJsonObject();
+        record["response"] = response.ToJsonObject();
+        m_data.Insert(record);
+    }
+}
+
+bool HttpRecordedData::AddMapping(const Request & request, const Response & response)
+{
+    String key = request.GetKey();
+    std::pair<ResponseMap::iterator, bool> res = m_responseMap.insert(std::make_pair(key, response));
+    if(!res.second && !(res.first->second == response) && request.url.find("clientSettings") == String::npos)
+    {
+        cerr << "WARNING: Found ambiguous response for request" << endl;
+        cerr << "  -      request: " + key << endl;
+        cerr << "  - old response: " + res.first->second.ToString() << endl;
+        cerr << "  - new response: " + response.ToString() << endl << endl;
+    }
+    return res.second;
+}
+
+Response HttpRecordedData::FindResponseFor(const Request & request) const
+{
+    String key = request.GetKey();
+    ResponseMap::const_iterator i = m_responseMap.find(key);
+    if (i == m_responseMap.end())
+    {
+        Response emptyResponse;
+        emptyResponse.error = String().Format("Cannot find HttpRecordedData for request '%s'", key.c_str());
+        cerr << "ERROR: " << emptyResponse.error << endl << endl;
+        return emptyResponse;
+    }
+
+    return i->second;
+}
+
+void HttpRecordedData::SaveTo(std::ostream & outputStream) const
+{
+    json::Writer::Write(m_data, outputStream);
+}
+
+void HttpRecordedData::SaveTo(const String & fileName) const
+{
+    fstream file(fileName.c_str(), fstream::out);
+    file.clear();
+    file.seekp(fstream::beg);
+    SaveTo(file);
+    file.close();
+}
+
+bool HttpRecordedData::LoadFrom(std::istream & inputStream)
+{
+    try
+    {
+        m_data.Clear();
+        json::Reader::Read(m_data, inputStream);
+
+        m_responseMap.clear();
+        for (json::Array::const_iterator i = m_data.Begin(); i != m_data.End(); ++i)
+        {
+            const json::Object& record = *i;
+            AddMapping(Request(record["request"]), Response(record["response"]));
+        }
+    }
+    catch (json::Exception& e)
+    {
+        cerr << "Failed to load HTTP recorded data: " << e.what() << endl;
+        return false;
+    }
+
+    return true;
+}
+
+bool HttpRecordedData::LoadFrom(const String & fileName)
+{
+    fstream file(fileName.c_str(), fstream::in);
+    bool res = LoadFrom(file);
+    file.close();
+    return res;
+}

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/ae986820/tests/common/http_recorded_data.h
----------------------------------------------------------------------
diff --git a/tests/common/http_recorded_data.h b/tests/common/http_recorded_data.h
new file mode 100644
index 0000000..03820d6
--- /dev/null
+++ b/tests/common/http_recorded_data.h
@@ -0,0 +1,85 @@
+/*
+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.
+*/
+
+/*
+ * Http requests recorded data
+ */
+
+#ifndef _TEST_HTTP_RECORDED_DATA_H_
+#define _TEST_HTTP_RECORDED_DATA_H_
+
+#include "mpin_sdk.h"
+#include "CvMutex.h"
+
+class HttpRecordedData
+{
+public:
+    typedef MPinSDK::String String;
+    typedef MPinSDK::StringMap StringMap;
+    typedef MPinSDK::IHttpRequest IHttpRequest;
+
+    class Request
+    {
+    public:
+        Request();
+        Request(IHttpRequest::Method _method, const String& _url, const String& _data, const String& _context);
+        Request(const json::Object& object);
+        json::Object ToJsonObject() const;
+        String GetKey() const;
+
+        String method;
+        String url;
+        String data;
+        String context;
+    };
+
+    class Response
+    {
+    public:
+        Response();
+        Response(bool _success, const String& _error, int _httpStatus, const StringMap& _headers, const String& _data);
+        Response(const json::Object& object);
+        json::Object ToJsonObject() const;
+        String ToString() const;
+
+        bool success;
+        String error;
+        int httpStatus;
+        StringMap headers;
+        String data;
+    };
+
+    HttpRecordedData();
+    void Record(const Request& request, const Response& response);
+    Response FindResponseFor(const Request& request) const;
+    void SaveTo(std::ostream& outputStream) const;
+    void SaveTo(const String& fileName) const;
+    bool LoadFrom(std::istream& inputStream);
+    bool LoadFrom(const String& fileName);
+
+private:
+    bool AddMapping(const Request& request, const Response& response);
+
+    json::Array m_data;
+    typedef std::map<String, Response> ResponseMap;
+    ResponseMap m_responseMap;
+    CvShared::CvMutex m_addRecordMutex;
+};
+
+#endif // _TEST_HTTP_RECORDED_DATA_H_

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/ae986820/tests/common/http_recorder.cpp
----------------------------------------------------------------------
diff --git a/tests/common/http_recorder.cpp b/tests/common/http_recorder.cpp
new file mode 100644
index 0000000..4216277
--- /dev/null
+++ b/tests/common/http_recorder.cpp
@@ -0,0 +1,82 @@
+/*
+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.
+*/
+
+/*
+ * MPinSDK::IHttpRequest implementation used for to record test http requests
+ */
+
+#include "http_recorder.h"
+#include "http_recorded_data.h"
+#include <cassert>
+
+typedef MPinSDK::String String;
+typedef MPinSDK::StringMap StringMap;
+typedef HttpRecordedData::Request Request;
+typedef HttpRecordedData::Response Response;
+
+void HttpRecorder::SetHeaders(const StringMap & headers)
+{
+    m_request.SetHeaders(headers);
+}
+
+void HttpRecorder::SetQueryParams(const StringMap & queryParams)
+{
+    assert(false);
+}
+
+void HttpRecorder::SetContent(const String & data)
+{
+    m_requestData = data;
+    m_request.SetContent(data);
+}
+
+void HttpRecorder::SetTimeout(int seconds)
+{
+    m_request.SetTimeout(seconds);
+}
+
+bool HttpRecorder::Execute(Method method, const String & url)
+{
+    bool res = m_request.Execute(method, url);
+
+    m_recorder.Record(Request(method, url, m_requestData, m_context),
+        Response(res, m_request.GetExecuteErrorMessage(), m_request.GetHttpStatusCode(), m_request.GetResponseHeaders(), m_request.GetResponseData()));
+
+    return res;
+}
+
+const String & HttpRecorder::GetExecuteErrorMessage() const
+{
+    return m_request.GetExecuteErrorMessage();
+}
+
+int HttpRecorder::GetHttpStatusCode() const
+{
+    return m_request.GetHttpStatusCode();
+}
+
+const StringMap & HttpRecorder::GetResponseHeaders() const
+{
+    return m_request.GetResponseHeaders();
+}
+
+const String & HttpRecorder::GetResponseData() const
+{
+    return m_request.GetResponseData();
+}

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/ae986820/tests/common/http_recorder.h
----------------------------------------------------------------------
diff --git a/tests/common/http_recorder.h b/tests/common/http_recorder.h
new file mode 100644
index 0000000..c8f6183
--- /dev/null
+++ b/tests/common/http_recorder.h
@@ -0,0 +1,55 @@
+/*
+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.
+*/
+
+/*
+ * MPinSDK::IHttpRequest implementation used for to record test http requests
+ */
+
+#ifndef _TEST_HTTP_RECORDER_H_
+#define _TEST_HTTP_RECORDER_H_
+
+#include "http_request.h"
+
+class HttpRecordedData;
+
+class HttpRecorder : public MPinSDK::IHttpRequest
+{
+public:
+    typedef MPinSDK::String String;
+    typedef MPinSDK::StringMap StringMap;
+
+    HttpRecorder(HttpRecordedData& recorder, const String& context) : m_recorder(recorder), m_context(context) {}
+    virtual void SetHeaders(const StringMap& headers);
+    virtual void SetQueryParams(const StringMap& queryParams);
+    virtual void SetContent(const String& data);
+    virtual void SetTimeout(int seconds);
+    virtual bool Execute(Method method, const String& url);
+    virtual const String& GetExecuteErrorMessage() const;
+    virtual int GetHttpStatusCode() const;
+    virtual const StringMap& GetResponseHeaders() const;
+    virtual const String& GetResponseData() const;
+
+private:
+    HttpRequest m_request;
+    String m_requestData;
+    HttpRecordedData& m_recorder;
+    String m_context;
+};
+
+#endif // _TEST_HTTP_RECORDER_H_

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/ae986820/tests/common/test_context.cpp
----------------------------------------------------------------------
diff --git a/tests/common/test_context.cpp b/tests/common/test_context.cpp
new file mode 100644
index 0000000..9924f31
--- /dev/null
+++ b/tests/common/test_context.cpp
@@ -0,0 +1,101 @@
+/*
+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.
+*/
+
+/*
+* MPinSDK::IContext tests base implementation
+*/
+
+#include "test_context.h"
+#include "../common/http_request.h"
+#include "../common/http_recorder.h"
+#include "../common/http_player.h"
+
+typedef MPinSDK::String String;
+typedef MPinSDK::IHttpRequest IHttpRequest;
+
+TestContext::TestContext() : m_mode(MODE_MAKE_REAL_REQUESTS), m_autoContextData(NULL)
+{
+}
+
+TestContext::TestContext(const AutoContextData& autoContextData) : m_autoContextData(&autoContextData)
+{
+}
+
+TestContext::~TestContext()
+{
+    if (m_mode == MODE_RECORD_REAL_REQUESTS)
+    {
+        m_recordedData.SaveTo(m_recordedDataFile);
+    }
+}
+
+void TestContext::EnterRequestRecorderMode(const String& recordedDataFile)
+{
+    m_mode = MODE_RECORD_REAL_REQUESTS;
+    m_recordedDataFile = recordedDataFile;
+}
+
+void TestContext::EnterRequestPlayerMode(const String& recordedDataFile)
+{
+    m_mode = MODE_USE_RECORDED_REQUESTS;
+    m_recordedDataFile = recordedDataFile;
+    m_recordedData.LoadFrom(recordedDataFile);
+}
+
+void TestContext::EnterRequestPlayerMode(std::istream & recordedDataInputStream)
+{
+    m_mode = MODE_USE_RECORDED_REQUESTS;
+    m_recordedData.LoadFrom(recordedDataInputStream);
+}
+
+IHttpRequest * TestContext::CreateHttpRequest() const
+{
+    switch (m_mode)
+    {
+    case MODE_MAKE_REAL_REQUESTS:
+        return new HttpRequest();
+    case MODE_USE_RECORDED_REQUESTS:
+        return new HttpPlayer(const_cast<HttpRecordedData&>(m_recordedData), GetRequestContextData());
+    case MODE_RECORD_REAL_REQUESTS:
+        return new HttpRecorder(const_cast<HttpRecordedData&>(m_recordedData), GetRequestContextData());
+    default:
+        assert(false);
+        return NULL;
+    }
+}
+
+void TestContext::ReleaseHttpRequest(IN IHttpRequest * request) const
+{
+    delete request;
+}
+
+void TestContext::SetRequestContextData(const String & requestContextData)
+{
+    m_requestContextData = requestContextData;
+}
+
+void TestContext::SetAdditionalContextData(const String & additionalContextData)
+{
+    m_additionalContextData = additionalContextData;
+}
+
+String TestContext::GetRequestContextData() const
+{
+    return m_requestContextData + (m_autoContextData ? ("@" + m_autoContextData->Get()) : "") + m_additionalContextData;
+}

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/ae986820/tests/common/test_context.h
----------------------------------------------------------------------
diff --git a/tests/common/test_context.h b/tests/common/test_context.h
new file mode 100644
index 0000000..04bbb28
--- /dev/null
+++ b/tests/common/test_context.h
@@ -0,0 +1,66 @@
+/*
+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.
+*/
+
+/*
+ * MPinSDK::IContext tests base implementation
+ */
+
+#ifndef _TEST_CONTEXT_H_
+#define _TEST_CONTEXT_H_
+
+#include "mpin_sdk.h"
+#include "http_recorded_data.h"
+
+class TestContext : public MPinSDK::IContext
+{
+public:
+    typedef MPinSDK::String String;
+    typedef MPinSDK::IHttpRequest IHttpRequest;
+
+    class AutoContextData
+    {
+    public:
+        virtual ~AutoContextData() {}
+        virtual String Get() const = 0;
+    };
+
+    TestContext();
+    TestContext(const AutoContextData& autoContextData);
+    ~TestContext();
+    void EnterRequestRecorderMode(const String& recordedDataFile);
+    void EnterRequestPlayerMode(const String& recordedDataFile);
+    void EnterRequestPlayerMode(std::istream& recordedDataInputStream);
+    virtual IHttpRequest * CreateHttpRequest() const;
+    virtual void ReleaseHttpRequest(IN IHttpRequest *request) const;
+    void SetRequestContextData(const String& requestContextData);
+    void SetAdditionalContextData(const String& additionalContextData);
+
+protected:
+    String GetRequestContextData() const;
+
+    enum Mode { MODE_MAKE_REAL_REQUESTS, MODE_USE_RECORDED_REQUESTS, MODE_RECORD_REAL_REQUESTS };
+    Mode m_mode;
+    String m_recordedDataFile;
+    HttpRecordedData m_recordedData;
+    String m_requestContextData;
+    const AutoContextData *m_autoContextData;
+    String m_additionalContextData;
+};
+
+#endif // _TEST_CONTEXT_H_

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/ae986820/tests/common/test_mpin_sdk.cpp
----------------------------------------------------------------------
diff --git a/tests/common/test_mpin_sdk.cpp b/tests/common/test_mpin_sdk.cpp
new file mode 100644
index 0000000..d2eb60e
--- /dev/null
+++ b/tests/common/test_mpin_sdk.cpp
@@ -0,0 +1,124 @@
+/*
+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.
+*/
+
+/*
+* M-Pin SDK test interface
+*/
+
+#include "test_mpin_sdk.h"
+#include "test_context.h"
+
+typedef MPinSDK::Status Status;
+
+TestMPinSDK::TestMPinSDK(TestContext & testContext) : m_testContext(testContext)
+{
+}
+
+Status TestMPinSDK::Init(const StringMap & config)
+{
+    return MPinSDK::Init(config, &m_testContext);
+}
+
+Status TestMPinSDK::StartRegistration(INOUT UserPtr user, const String & activateCode, const String & userData)
+{
+    m_testContext.SetRequestContextData(user->GetId() + "-" + activateCode + "-" + userData);
+    Status s = MPinSDK::StartRegistration(user, activateCode, userData);
+    m_testContext.SetRequestContextData("");
+    return s;
+}
+
+Status TestMPinSDK::RestartRegistration(INOUT UserPtr user, const String & userData)
+{
+    m_testContext.SetRequestContextData(user->GetId() + "-" + userData);
+    Status s = MPinSDK::RestartRegistration(user, userData);
+    m_testContext.SetRequestContextData("");
+    return s;
+}
+
+Status TestMPinSDK::ConfirmRegistration(INOUT UserPtr user, const String & pushMessageIdentifier)
+{
+    m_testContext.SetRequestContextData(user->GetId() + "-" + pushMessageIdentifier);
+    Status s = MPinSDK::ConfirmRegistration(user, pushMessageIdentifier);
+    m_testContext.SetRequestContextData("");
+    return s;
+}
+
+Status TestMPinSDK::FinishRegistration(INOUT UserPtr user, const String & pin)
+{
+    m_testContext.SetRequestContextData(user->GetId() + "-" + pin);
+    Status s = MPinSDK::FinishRegistration(user, pin);
+    m_testContext.SetRequestContextData("");
+    return s;
+}
+
+Status TestMPinSDK::StartAuthentication(INOUT UserPtr user, const String & accessCode)
+{
+    m_testContext.SetRequestContextData(user->GetId() + "-" + accessCode);
+    Status s = MPinSDK::StartAuthentication(user, accessCode);
+    m_testContext.SetRequestContextData("");
+    return s;
+}
+
+Status TestMPinSDK::FinishAuthentication(INOUT UserPtr user, const String & pin)
+{
+    m_testContext.SetRequestContextData(user->GetId() + "-" + pin);
+    Status s = MPinSDK::FinishAuthentication(user, pin);
+    m_testContext.SetRequestContextData("");
+    return s;
+}
+
+Status TestMPinSDK::FinishAuthentication(INOUT UserPtr user, const String & pin, OUT String & authResultData)
+{
+    m_testContext.SetRequestContextData(user->GetId() + "-" + pin + "-ARD");
+    Status s = MPinSDK::FinishAuthentication(user, pin, authResultData);
+    m_testContext.SetRequestContextData("");
+    return s;
+}
+
+Status TestMPinSDK::FinishAuthenticationOTP(INOUT UserPtr user, const String & pin, OUT OTP & otp)
+{
+    m_testContext.SetRequestContextData(user->GetId() + "-" + pin + "-OTP");
+    Status s = MPinSDK::FinishAuthenticationOTP(user, pin, otp);
+    m_testContext.SetRequestContextData("");
+    return s;
+}
+
+Status TestMPinSDK::FinishAuthenticationAN(INOUT UserPtr user, const String & pin, const String & accessNumber)
+{
+    m_testContext.SetRequestContextData(user->GetId() + "-" + pin + "-" + accessNumber);
+    Status s = MPinSDK::FinishAuthenticationAN(user, pin, accessNumber);
+    m_testContext.SetRequestContextData("");
+    return s;
+}
+
+Status TestMPinSDK::GetSessionDetails(const String & accessCode, OUT SessionDetails & sessionDetails)
+{
+    m_testContext.SetRequestContextData(accessCode);
+    Status s = MPinSDK::GetSessionDetails(accessCode, sessionDetails);
+    m_testContext.SetRequestContextData("");
+    return s;
+}
+
+bool TestMPinSDK::Logout(IN UserPtr user)
+{
+    m_testContext.SetRequestContextData(user->GetId());
+    bool res = MPinSDK::Logout(user);
+    m_testContext.SetRequestContextData("");
+    return res;
+}

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/ae986820/tests/common/test_mpin_sdk.h
----------------------------------------------------------------------
diff --git a/tests/common/test_mpin_sdk.h b/tests/common/test_mpin_sdk.h
new file mode 100644
index 0000000..9b8e3d7
--- /dev/null
+++ b/tests/common/test_mpin_sdk.h
@@ -0,0 +1,56 @@
+/*
+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.
+*/
+
+/*
+ * M-Pin SDK test interface
+ */
+
+#ifndef _TEST_MPIN_SDK_H_
+#define _TEST_MPIN_SDK_H_
+
+#include "mpin_sdk.h"
+
+class TestContext;
+
+class TestMPinSDK : public MPinSDK
+{
+public:
+    TestMPinSDK(TestContext& testContext);
+
+    Status Init(const StringMap& config);
+
+    Status StartRegistration(INOUT UserPtr user, const String& activateCode = "", const String& userData = "");
+    Status RestartRegistration(INOUT UserPtr user, const String& userData = "");
+    Status ConfirmRegistration(INOUT UserPtr user, const String& pushMessageIdentifier = "");
+    Status FinishRegistration(INOUT UserPtr user, const String& pin);
+
+    Status StartAuthentication(INOUT UserPtr user, const String& accessCode = "");
+    Status FinishAuthentication(INOUT UserPtr user, const String& pin);
+    Status FinishAuthentication(INOUT UserPtr user, const String& pin, OUT String& authResultData);
+    Status FinishAuthenticationOTP(INOUT UserPtr user, const String& pin, OUT OTP& otp);
+    Status FinishAuthenticationAN(INOUT UserPtr user, const String& pin, const String& accessNumber);
+
+    Status GetSessionDetails(const String& accessCode, OUT SessionDetails& sessionDetails);
+    bool Logout(IN UserPtr user);
+
+private:
+    TestContext& m_testContext;
+};
+
+#endif // _TEST_MPIN_SDK_H_

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/ae986820/tests/contexts/auto_context.cpp
----------------------------------------------------------------------
diff --git a/tests/contexts/auto_context.cpp b/tests/contexts/auto_context.cpp
index dc3c981..c656d0d 100644
--- a/tests/contexts/auto_context.cpp
+++ b/tests/contexts/auto_context.cpp
@@ -22,25 +22,18 @@ under the License.
  */
 
 #include "auto_context.h"
-#include "../common/http_request.h"
 #include "../common/memory_storage.h"
 
-#include <iostream>
-#include <fstream>
-
 typedef MPinSDK::String String;
-typedef MPinSDK::IHttpRequest IHttpRequest;
 typedef MPinSDK::CryptoType CryptoType;
-typedef MPinSDK::UserPtr UserPtr;
 
 /*
  * Context class impl
  */
 
-AutoContext::AutoContext()
+AutoContext::AutoContext(const AutoContextData& autoContextData) :
+    TestContext(autoContextData), m_nonSecureStorage(new MemoryStorage()), m_secureStorage(new MemoryStorage())
 {
-    m_nonSecureStorage = new MemoryStorage();
-    m_secureStorage = new MemoryStorage();
 }
 
 AutoContext::~AutoContext()
@@ -49,16 +42,6 @@ AutoContext::~AutoContext()
     delete m_secureStorage;
 }
 
-IHttpRequest * AutoContext::CreateHttpRequest() const
-{
-    return new HttpRequest();
-}
-
-void AutoContext::ReleaseHttpRequest(IN IHttpRequest *request) const
-{
-    delete request;
-}
-
 MPinSDK::IStorage * AutoContext::GetStorage(IStorage::Type type) const
 {
     if(type == IStorage::SECURE)

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/ae986820/tests/contexts/auto_context.h
----------------------------------------------------------------------
diff --git a/tests/contexts/auto_context.h b/tests/contexts/auto_context.h
index 7c6b011..a91a1d7 100644
--- a/tests/contexts/auto_context.h
+++ b/tests/contexts/auto_context.h
@@ -25,19 +25,17 @@ under the License.
 #define _AUTO_CONTEXT_H_
 
 #include "mpin_sdk.h"
+#include "../common/test_context.h"
 
-class AutoContext : public MPinSDK::IContext
+class AutoContext : public TestContext
 {
 public:
     typedef MPinSDK::String String;
-    typedef MPinSDK::IHttpRequest IHttpRequest;
     typedef MPinSDK::IStorage IStorage;
     typedef MPinSDK::CryptoType CryptoType;
 
-    AutoContext();
+    AutoContext(const AutoContextData& autoContextData);
     ~AutoContext();
-    virtual IHttpRequest * CreateHttpRequest() const;
-    virtual void ReleaseHttpRequest(IN IHttpRequest *request) const;
     virtual IStorage * GetStorage(IStorage::Type type) const;
     virtual CryptoType GetMPinCryptoType() const;
 

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/ae986820/tests/contexts/cmdline_context.cpp
----------------------------------------------------------------------
diff --git a/tests/contexts/cmdline_context.cpp b/tests/contexts/cmdline_context.cpp
index 0bc97fd..a4462d3 100644
--- a/tests/contexts/cmdline_context.cpp
+++ b/tests/contexts/cmdline_context.cpp
@@ -22,26 +22,19 @@ under the License.
  */
 
 #include "cmdline_context.h"
-#include "../common/http_request.h"
 #include "../common/file_storage.h"
 
-#include <iostream>
-#include <fstream>
-
 typedef MPinSDK::String String;
 typedef MPinSDK::IHttpRequest IHttpRequest;
 typedef MPinSDK::CryptoType CryptoType;
-typedef MPinSDK::UserPtr UserPtr;
-using namespace std;
 
 /*
  * Context class impl
  */
 
-CmdLineContext::CmdLineContext(const String& usersFile, const String& tokensFile)
+CmdLineContext::CmdLineContext(const String& usersFile, const String& tokensFile) :
+    m_nonSecureStorage(new FileStorage(usersFile)), m_secureStorage(new FileStorage(tokensFile))
 {
-    m_nonSecureStorage = new FileStorage(usersFile);
-    m_secureStorage = new FileStorage(tokensFile);
 }
 
 CmdLineContext::~CmdLineContext()
@@ -50,16 +43,6 @@ CmdLineContext::~CmdLineContext()
     delete m_secureStorage;
 }
 
-IHttpRequest * CmdLineContext::CreateHttpRequest() const
-{
-    return new HttpRequest();
-}
-
-void CmdLineContext::ReleaseHttpRequest(IN IHttpRequest *request) const
-{
-    delete request;
-}
-
 MPinSDK::IStorage * CmdLineContext::GetStorage(IStorage::Type type) const
 {
     if(type == IStorage::SECURE)

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/ae986820/tests/contexts/cmdline_context.h
----------------------------------------------------------------------
diff --git a/tests/contexts/cmdline_context.h b/tests/contexts/cmdline_context.h
index 80c4511..3035187 100644
--- a/tests/contexts/cmdline_context.h
+++ b/tests/contexts/cmdline_context.h
@@ -24,20 +24,17 @@ under the License.
 #ifndef _CMDLINE_CONTEXT_H_
 #define _CMDLINE_CONTEXT_H_
 
-#include "mpin_sdk.h"
+#include "../common/test_context.h"
 
-class CmdLineContext : public MPinSDK::IContext
+class CmdLineContext : public TestContext
 {
 public:
     typedef MPinSDK::String String;
-    typedef MPinSDK::IHttpRequest IHttpRequest;
     typedef MPinSDK::IStorage IStorage;
     typedef MPinSDK::CryptoType CryptoType;
 
     CmdLineContext(const String& usersFile, const String& tokensFile);
     ~CmdLineContext();
-    virtual IHttpRequest * CreateHttpRequest() const;
-    virtual void ReleaseHttpRequest(IN IHttpRequest *request) const;
     virtual IStorage * GetStorage(IStorage::Type type) const;
     virtual CryptoType GetMPinCryptoType() const;
 

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/ae986820/tests/unit_tests.cpp
----------------------------------------------------------------------
diff --git a/tests/unit_tests.cpp b/tests/unit_tests.cpp
index f963195..b741c37 100644
--- a/tests/unit_tests.cpp
+++ b/tests/unit_tests.cpp
@@ -17,11 +17,9 @@ specific language governing permissions and limitations
 under the License.
 */
 
-#include "mpin_sdk.h"
+#include "common/test_mpin_sdk.h"
 #include "contexts/auto_context.h"
-#include "common/http_request.h"
 #include "common/access_number_thread.h"
-#include "CvTime.h"
 #include "CvLogger.h"
 
 #define BOOST_TEST_MODULE Simple testcases
@@ -31,13 +29,47 @@ typedef MPinSDK::User User;
 typedef MPinSDK::UserPtr UserPtr;
 typedef MPinSDK::Status Status;
 typedef MPinSDK::String String;
+using namespace boost::unit_test;
 
-static AutoContext context;
-static MPinSDK sdk;
-static MPinSDK::StringMap config;
-static const char *backend = "http://192.168.98.98:8005";
 
-using namespace boost::unit_test;
+static char RECORDED_DATA_JSON[] = {
+#include "unit_tests_recorded_data.inc"
+};
+
+class MemBuf : public std::streambuf
+{
+public:
+    MemBuf(char *buf, size_t len)
+    {
+        this->setg(buf, buf, buf + len);
+    }
+};
+
+static const char * GetRecordedDataFileName()
+{
+    int argc = framework::master_test_suite().argc;
+    if (argc > 1)
+    {
+        char **argv = framework::master_test_suite().argv;
+        return argv[1];
+    }
+    return "unit_tests_recorded_data.json";
+}
+
+class TestNameData : public TestContext::AutoContextData
+{
+public:
+    virtual String Get() const
+    {
+        return framework::current_test_case().p_name.get();
+    }
+};
+
+static TestNameData testNameData;
+static AutoContext context(testNameData);
+static TestMPinSDK sdk(context);
+static MPinSDK::StringMap config;
+static const char *backend = "http://10.10.40.62:8005";
 
 static std::ostream& operator<<(std::ostream& ostr, const Status& s)
 {
@@ -53,12 +85,10 @@ BOOST_AUTO_TEST_CASE(testNoInit)
 
     CvShared::InitLogger("cvlog.txt", CvShared::enLogLevel_None);
 
-    int argc = framework::master_test_suite().argc;
-    if(argc > 1)
-    {
-        char **argv = framework::master_test_suite().argv;
-        backend = argv[1];
-    }
+    //context.EnterRequestRecorderMode(GetRecordedDataFileName());
+    MemBuf buf(RECORDED_DATA_JSON, sizeof(RECORDED_DATA_JSON));
+    std::istream recordedDataInputStream(&buf);
+    context.EnterRequestPlayerMode(recordedDataInputStream);
 
     Status s = sdk.TestBackend("12354");
     BOOST_CHECK_EQUAL(s, Status::FLOW_ERROR);
@@ -115,7 +145,7 @@ BOOST_AUTO_TEST_CASE(testInit)
 
     config.Put(MPinSDK::CONFIG_BACKEND, backend);
 
-    Status s = sdk.Init(config, &context);
+    Status s = sdk.Init(config);
 
     BOOST_CHECK_EQUAL(s, Status::OK);
 
@@ -395,11 +425,15 @@ BOOST_AUTO_TEST_CASE(testAuthenticate1)
     BOOST_CHECK_EQUAL(s, Status::INCORRECT_PIN);
     BOOST_CHECK_EQUAL(user->GetState(), User::REGISTERED);
 
+    context.SetAdditionalContextData("SecondAuth");
+
     //s = sdk.StartAuthentication(user);
     s = sdk.FinishAuthentication(user, "1234");
     BOOST_CHECK_EQUAL(s, Status::OK);
     BOOST_CHECK_EQUAL(user->GetState(), User::REGISTERED);
 
+    context.SetAdditionalContextData("");
+
     sdk.DeleteUser(user);
 
     BOOST_MESSAGE("    testAuthenticate1 finished");
@@ -432,12 +466,12 @@ BOOST_AUTO_TEST_CASE(testAuthenticate2)
     BOOST_CHECK_EQUAL(user->GetState(), User::REGISTERED);
 
     //s = sdk.StartAuthentication(user);
-    s = sdk.FinishAuthentication(user, "1111");
+    s = sdk.FinishAuthentication(user, "1112");
     BOOST_CHECK_EQUAL(s, Status::INCORRECT_PIN);
     BOOST_CHECK_EQUAL(user->GetState(), User::REGISTERED);
 
     //s = sdk.StartAuthentication(user);
-    s = sdk.FinishAuthentication(user, "1111");
+    s = sdk.FinishAuthentication(user, "1113");
     BOOST_CHECK_EQUAL(s, Status::INCORRECT_PIN);
     BOOST_CHECK_EQUAL(user->GetState(), User::BLOCKED);
 
@@ -479,8 +513,6 @@ BOOST_AUTO_TEST_CASE(testAuthenticateOTP)
     BOOST_MESSAGE("    testAuthenticateOTP finished");
 }
 
-static AccessNumberThread g_accessNumberThread;
-
 BOOST_AUTO_TEST_CASE(testAuthenticateAN1)
 {
     BOOST_MESSAGE("Starting testAuthenticateAN1...");
@@ -501,18 +533,19 @@ BOOST_AUTO_TEST_CASE(testAuthenticateAN1)
     BOOST_CHECK_EQUAL(user->GetState(), User::REGISTERED);
 
     // Request access number
-    HttpRequest req;
-    HttpRequest::StringMap headers;
+    MPinSDK::IHttpRequest *req = context.CreateHttpRequest();
+    MPinSDK::StringMap headers;
     headers.Put("Content-Type", "application/json");
     headers.Put("Accept", "*/*");
-    req.SetHeaders(headers);
+    req->SetHeaders(headers);
 
     String url = String().Format("%s/rps/getAccessNumber", backend);
-    bool res = req.Execute(MPinSDK::IHttpRequest::POST, url);
+    bool res = req->Execute(MPinSDK::IHttpRequest::POST, url);
     BOOST_CHECK(res);
-    BOOST_CHECK_EQUAL(req.GetHttpStatusCode(), 200);
+    BOOST_CHECK_EQUAL(req->GetHttpStatusCode(), 200);
 
-    String data = req.GetResponseData();
+    String data = req->GetResponseData();
+    context.ReleaseHttpRequest(req);
     util::JsonObject json;
     res = json.Parse(data.c_str());
     BOOST_CHECK(res);
@@ -521,7 +554,8 @@ BOOST_AUTO_TEST_CASE(testAuthenticateAN1)
     BOOST_CHECK(accessNumber.length() > 0);
 
     // Start access number thread
-    g_accessNumberThread.Start(backend, json.GetStringParam("webOTT"), sdk.GetClientParam("authenticateURL"));
+    AccessNumberThread accessNumberThread(context);
+    accessNumberThread.Start(backend, json.GetStringParam("webOTT"), sdk.GetClientParam("authenticateURL"));
 
     // Authenticate with access number
     s = sdk.StartAuthentication(user);
@@ -561,18 +595,19 @@ BOOST_AUTO_TEST_CASE(testAuthenticateAN2)
     BOOST_CHECK_EQUAL(user->GetState(), User::REGISTERED);
 
     // Request access number
-    HttpRequest req;
-    HttpRequest::StringMap headers;
+    MPinSDK::IHttpRequest *req = context.CreateHttpRequest();
+    MPinSDK::StringMap headers;
     headers.Put("Content-Type", "application/json");
     headers.Put("Accept", "*/*");
-    req.SetHeaders(headers);
+    req->SetHeaders(headers);
 
     String url = String().Format("%s/rps/getAccessNumber", backend);
-    bool res = req.Execute(MPinSDK::IHttpRequest::POST, url);
+    bool res = req->Execute(MPinSDK::IHttpRequest::POST, url);
     BOOST_CHECK(res);
-    BOOST_CHECK_EQUAL(req.GetHttpStatusCode(), 200);
+    BOOST_CHECK_EQUAL(req->GetHttpStatusCode(), 200);
 
-    String data = req.GetResponseData();
+    String data = req->GetResponseData();
+    context.ReleaseHttpRequest(req);
     util::JsonObject json;
     res = json.Parse(data.c_str());
     BOOST_CHECK(res);
@@ -589,7 +624,8 @@ BOOST_AUTO_TEST_CASE(testAuthenticateAN2)
     }
 
     // Start access number thread
-    g_accessNumberThread.Start(backend, json.GetStringParam("webOTT"), sdk.GetClientParam("authenticateURL"));
+    AccessNumberThread accessNumberThread(context);
+    accessNumberThread.Start(backend, json.GetStringParam("webOTT"), sdk.GetClientParam("authenticateURL"));
 
     // Authenticate with access number
     s = sdk.StartAuthentication(user);
@@ -612,14 +648,11 @@ BOOST_AUTO_TEST_CASE(testAuthenticateAN2)
     // Fix access number - must fail with incorrect pin already
     accessNumber = originalAccessNumber;
     //s = sdk.StartAuthentication(user);
-    s = sdk.FinishAuthenticationAN(user, "1233", accessNumber);
+    s = sdk.FinishAuthenticationAN(user, "1235", accessNumber);
     BOOST_CHECK_EQUAL(s, Status::INCORRECT_PIN);
     BOOST_CHECK_EQUAL(user->GetState(), User::REGISTERED);
 
     sdk.DeleteUser(user);
 
-    // Wait the AccessNumberThread to complete
-    CvShared::SleepFor(CvShared::Millisecs(AccessNumberThread::RETRY_INTERVAL_MILLISEC * AccessNumberThread::MAX_TRIES).Value());
-
     BOOST_MESSAGE("    testAuthenticateAN2 finished");
 }