* Add tests for ecsclient

* Update lib/modules to latest

* add github workflows for exp

Co-authored-by: Hongji Cai <hocai@microsoft.com>
Co-authored-by: Max Golovanov <maxgolov@microsoft.com>
Co-authored-by: Hongji <hongji@Hongjis-MacBook-Pro.local>
This commit is contained in:
Chua 2020-09-10 18:13:55 +08:00 коммит произвёл GitHub
Родитель 6fd59a81ce
Коммит d5fe0c042b
21 изменённых файлов: 1008 добавлений и 11 удалений

30
.github/workflows/build-posix-latest-exp.yml поставляемый Normal file
Просмотреть файл

@ -0,0 +1,30 @@
name: SDK with exp - C/C++ CI on Linux and Mac
on:
push:
branches:
- master
- release/*
- buildme/*
pull_request:
branches:
- master
schedule:
- cron: 0 2 * * 1-5
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
config: [release, debug]
os: [ubuntu-latest, macOS-latest]
steps:
- uses: actions/checkout@v1
- name: Test ${{ matrix.os }} ${{ matrix.config }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GIT_PULL_TOKEN: ${{ secrets.GIT_PULL_TOKEN }}
run: ./build.sh ${{ matrix.config }} CUSTOM_BUILD_FLAGS="-DHAVE_MAT_EXP -DHAVE_MAT_FIFOSTORAGE" && ./out/tests/functests/FuncTests && ./out/tests/unittests/UnitTests

37
.github/workflows/build-windows-vs2017-exp.yaml поставляемый Normal file
Просмотреть файл

@ -0,0 +1,37 @@
name: SDK with exp - C/C++ CI on Windows (vs2017)
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
build:
runs-on: windows-2016
name: Build
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup Tools
shell: cmd
run: tools\setup-buildtools.cmd
- name: Build
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GIT_PULL_TOKEN: ${{ secrets.GIT_PULL_TOKEN }}
SKIP_ARM_BUILD: 1
SKIP_ARM64_BUILD: 1
shell: cmd
run: build-all.bat %CD%\Solutions\build.compact-exp.props
- name: ListOutput
shell: cmd
run: tree %CD%\Solutions\out

32
.github/workflows/test-win-latest-exp.yml поставляемый Normal file
Просмотреть файл

@ -0,0 +1,32 @@
name: SDK with exp - Build and Run Unit/Functional tests on Windows
on:
push:
branches:
- master
- release/*
- buildme/*
pull_request:
branches:
- master
schedule:
- cron: 0 2 * * 1-5
jobs:
test:
name: Test on Windows ${{ matrix.arch }}-${{ matrix.config }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
arch: [Win32, x64]
config: [Release, Debug]
os: [windows-2016]
steps:
- uses: actions/checkout@v1
- name: Test ${{ matrix.arch }} ${{ matrix.config }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GIT_PULL_TOKEN: ${{ secrets.GIT_PULL_TOKEN }}
shell: cmd
run: build-tests.cmd ${{ matrix.arch }} ${{ matrix.config }} %CD%\Solutions\build.compact-exp.props

Просмотреть файл

@ -15,6 +15,13 @@ set PLAT=%1
REM Possible configurations: Release|Debug
set CONFIGURATION=%2
set CUSTOM_PROPS=
if ("%3"=="") goto skip
set CUSTOM_PROPS="/p:ForceImportBeforeCppTargets=%3"
echo Using custom properties file for the build:
echo %CUSTOM_PROPS%
:skip
REM Add path to vs2017 MSBuild.exe
set "PATH=%PATH%;C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin\"
@ -25,7 +32,7 @@ call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\Too
set MAXCPUCOUNT=%NUMBER_OF_PROCESSORS%
set SOLUTION=Solutions\MSTelemetrySDK.sln
msbuild %SOLUTION% /target:sqlite,zlib,Tests\gmock,Tests\gtest,Tests\UnitTests,Tests\FuncTests /p:BuildProjectReferences=true /maxcpucount:%MAXCPUCOUNT% /detailedsummary /p:Configuration=%CONFIGURATION% /p:Platform=%PLAT%
msbuild %SOLUTION% /target:sqlite,zlib,Tests\gmock,Tests\gtest,Tests\UnitTests,Tests\FuncTests /p:BuildProjectReferences=true /maxcpucount:%MAXCPUCOUNT% /detailedsummary /p:Configuration=%CONFIGURATION% /p:Platform=%PLAT% %CUSTOM_PROPS%
if errorLevel 1 goto end
Solutions\out\%CONFIGURATION%\%PLAT%\UnitTests\UnitTests.exe
if errorLevel 1 goto end

Просмотреть файл

@ -25,24 +25,36 @@ if [ "$1" == "clean" ]; then
# make clean
fi
if [ "$1" == "noroot" ] || [ "$2" == "noroot" ]; then
if [ "$1" == "noroot" ] || [ "$2" == "noroot" ] || [ "$3" == "noroot" ]; then
export NOROOT=true
fi
if [ "$1" == "release" ] || [ "$2" == "release" ]; then
if [ "$1" == "release" ] || [ "$2" == "release" ] || [ "$3" == "release" ]; then
BUILD_TYPE="Release"
else
BUILD_TYPE="Debug"
fi
if [ "$1" == "arm64" ] || [ "$2" == "arm64" ]; then
if [ "$1" == "arm64" ] || [ "$2" == "arm64" ] || [ "$3" == "arm64" ]; then
MAC_ARCH="arm64"
elif [ "$1" == "universal" ] || [ "$2" == "universal" ]; then
elif [ "$1" == "universal" ] || [ "$2" == "universal" ] || [ "$3" == "universal" ]; then
MAC_ARCH="universal"
else
MAC_ARCH="x86_64"
fi
CUSTOM_CMAKE_CXX_FLAG=""
if [[ $1 == CUSTOM_BUILD_FLAGS* ]] || [[ $2 == CUSTOM_BUILD_FLAGS* ]] || [[ $3 == CUSTOM_BUILD_FLAGS* ]]; then
if [[ $1 == CUSTOM_BUILD_FLAGS* ]]; then
CUSTOM_CMAKE_CXX_FLAG="\"${1:19:999}\""
elif [[ $2 == CUSTOM_BUILD_FLAGS* ]]; then
CUSTOM_CMAKE_CXX_FLAG="\"${2:19:999}\""
elif [[ $3 == CUSTOM_BUILD_FLAGS* ]]; then
CUSTOM_CMAKE_CXX_FLAG="\"${3:19:999}\""
fi
fi
echo "custom build flags="$CUSTOM_CMAKE_CXX_FLAG
# Set target MacOS minver
export MACOSX_DEPLOYMENT_TARGET=10.10
@ -92,8 +104,9 @@ fi
set -e
# TODO: pass custom build flags?
cmake -DMAC_ARCH=$MAC_ARCH -DBUILD_SHARED_LIBS=OFF -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_PACKAGE_TYPE=$CMAKE_PACKAGE_TYPE ..
cmake_cmd="cmake -DMAC_ARCH=$MAC_ARCH -DBUILD_SHARED_LIBS=OFF -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_PACKAGE_TYPE=$CMAKE_PACKAGE_TYPE -DCMAKE_CXX_FLAGS="${CUSTOM_CMAKE_CXX_FLAG}" .."
echo $cmake_cmd
eval $cmake_cmd
# TODO: strip symbols to minimize (release-only)
# Build all

Просмотреть файл

@ -7,7 +7,7 @@
#define HAVE_MAT_JSONHPP
#define HAVE_MAT_ZLIB
/* #define HAVE_MAT_LOGGING */
/* #define HAVE_MAT_STORAGE */
#define HAVE_MAT_STORAGE
/* #define HAVE_MAT_NETDETECT */
/* #define HAVE_MAT_SHORT_NS */
#define HAVE_MAT_DEFAULT_HTTP_CLIENT

@ -1 +1 @@
Subproject commit ec8510fd1646e5e45779b398b6ab4f0daee8733e
Subproject commit 312407c4f3bff3bf0a7b2d8c8c6fbeaec3fc2131

Просмотреть файл

@ -656,8 +656,7 @@ namespace MAT_NS_BEGIN {
std::ostringstream tempPragma;
tempPragma << "PRAGMA temp_store_directory = '" << GetTempDirectory() << "'";
SqliteStatement(*m_db, tempPragma.str().c_str()).select();
const char * result = sqlite3_temp_directory;
LOG_INFO("Set sqlite3 temp_store_directory to '%s'", result);
LOG_INFO("Set sqlite3 temp_store_directory to '%s'", sqlite3_temp_directory);
}
int openedDbVersion;

Просмотреть файл

@ -9,6 +9,9 @@ set(SRCS
LogSessionDataFuncTests.cpp
Main.cpp
MultipleLogManagersTests.cpp
ECSClientFuncTests.cpp
ECSClientRealworldFuncTests.cpp
ECSConfigCacheFuncTests.cpp
)
source_group(" " REGULAR_EXPRESSION "")

Просмотреть файл

@ -0,0 +1,83 @@
// Copyright (c) Microsoft. All rights reserved.
#pragma once
#include "mat/config.h"
#ifdef HAVE_MAT_EXP
#include <chrono>
#include <thread>
#include <iostream>
#include <memory>
#include <functional>
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#endif
#include "common/Common.hpp"
#include "common/HttpServer.hpp"
#include "utils/Utils.hpp"
#include "modules/exp/ecs/ecsclient/ECSClient.hpp"
#include "json.hpp"
#include "utils/StringUtils.hpp"
using json = nlohmann::json;
using namespace testing;
using namespace MAT;
using namespace Microsoft::Applications::Experimentation::ECS;
using namespace Microsoft::Applications::Events;
namespace ECSClientCommon{
const int maxRetryCount = 50;
class ECSClientCallback : public IECSClientCallback
{
std::function<void()> callback;
public:
ECSClientCallback(const std::function<void()> &callback):callback(callback){ }
virtual void OnECSClientEvent(ECSClientEventType evtType, ECSClientEventContext evtContext)
{
if (evtType == ECSClientEventType::ET_CONFIG_UPDATE_SUCCEEDED)
{
callback();
}
}
};
inline std::unique_ptr<ECSClient> GetInitilizedECSClient(const ECSClientConfiguration& config, const std::function<void(ECSClient*)> &callback = nullptr)
{
auto client = std::make_unique<ECSClient>();
if (callback)
{
callback(client.get());
}
client->Initialize(config);
return client;
}
inline void InitilizeAndStartECSClientThen(const ECSClientConfiguration& config, const std::function<void(ECSClient*)> &callback, const std::function<void(ECSClient*)> &initCallback = nullptr)
{
auto client = GetInitilizedECSClient(config);
if (initCallback)
{
initCallback(client.get());
}
auto ret = client->Start();
ASSERT_EQ(ret, true);
bool configUpdated = false;
auto onConfigUpdate = std::make_unique<ECSClientCallback>([&configUpdated](){
configUpdated = true;
});
client->AddListener(onConfigUpdate.get());
int retryCount = 0;
while(!configUpdated && retryCount < maxRetryCount){
std::this_thread::sleep_for(std::chrono::milliseconds(200));
++retryCount;
};
if(configUpdated)
{
callback(client.get());
}
else
{
FAIL() << "Config should be updated";
}
}
}
#endif

Просмотреть файл

@ -0,0 +1,344 @@
// Copyright (c) Microsoft. All rights reserved.
#include "ECSClientCommon.hpp"
#ifdef HAVE_MAT_EXP
namespace {
using namespace ECSClientCommon;
int port = 8888;
const char* const jsonConfigString = "{\"ECSDemo\":{\"intArray\":[1,2],\"dblArray\":[1.1],\"strArray\":[\"hello\"],\"bool\":true,\"int\":123,\"double\":1.1,\"string\":\"str\",\"object\":{\"a\":\"b\",\"c\":\"d\"},\"null\":null},\"Headers\":{\"ETag\":\"\\\"kq49sHJi58LmvklHzjiuJ4UNE/VdiaeFjrYkErAZr1w=\\\"\",\"Expires\":\"Fri, 14 Aug 2020 07:12:13 GMT\",\"CountryCode\":\"JP\",\"StatusCode\":\"200\"}}";
const char* const agent = "ECSDemo";
const char* const userIdHitString = "{\"hit\":\"userId\"}";
const char* const deviceIdHitString = "{\"hit\":\"clientId\"}";
const char* const filterHitString = "{\"hit\":\"filter\"}";
const char* const etagVal = "\"kq49sHJi58LmvklHzjiuJ4UNE/VdiaeFjrYkErAZr1w=\"";
const char* const cacheFilePathName = "cacheFilePathName";
class ECSServerCallback : public HttpServer::Callback
{
public:
virtual int onHttpRequest(HttpServer::Request const& request, HttpServer::Response& response) override
{
std::vector<std::string> uriParam;
std::vector<std::string> params;
StringUtils::SplitString(request.uri, '?', uriParam);
if (uriParam.size() == 2)
{
StringUtils::SplitString(uriParam[1], '&', params);
for (auto param : params)
{
std::vector<std::string> kv;
StringUtils::SplitString(param, '=', kv);
if (kv.size() == 2)
{
if (kv[0] == "id" && kv[1] == "hocai")
{
response.content = userIdHitString;
return 200;
}
if (kv[0] == "clientId" && kv[1] == "hocaiDevice")
{
response.content = deviceIdHitString;
return 200;
}
if (kv[0] == "customFilter" && kv[1] == "filterVal")
{
response.content = filterHitString;
return 200;
}
if (kv[0] == "customStatusCode")
{
response.content = jsonConfigString;
return std::stoi(kv[1]);
}
}
}
}
response.headers = std::map<std::string, std::string>
{
{"etag", etagVal},
{"date", "Thu, 20 Aug 2020 01:28:19 GMT"},
{"expires", "Thu, 20 Aug 2020 01:28:19 GMT"}
};
response.content = jsonConfigString;
return 200;
}
};
class ECSClientFuncTests : public ::testing::Test
{
protected:
HttpServer server;
ECSServerCallback callback;
const std::string offlineStoragePath = ECSConfigCache::GetStoragePath(cacheFilePathName);
virtual void SetUp()
{
// there are some error on windows
// looks like port didn't get recycled immediately so we randomize port
port += 1;
std:: cout<< "server port:" << port << std::endl;
server.addListeningPort(port);
server.addHandler("/config/v1", callback);
server.start();
std::remove(offlineStoragePath.c_str());
}
virtual void TearDown()
{
server.stop();
std::remove(offlineStoragePath.c_str());
}
};
ECSClientConfiguration GetECSClientConfiguration()
{
auto config = ECSClientConfiguration();
config.clientName = "Test";
config.clientVersion = "1.0";
config.cacheFilePathName = cacheFilePathName;
config.serverUrls.push_back("http://127.0.0.1:" + std::to_string(port) + "/config/v1");
return config;
}
TEST_F(ECSClientFuncTests, GetConfigs)
{
InitilizeAndStartECSClientThen(
GetECSClientConfiguration(),
[](ECSClient* client){
auto configs = client->GetConfigs();
ASSERT_EQ(json::parse(configs), json::parse(jsonConfigString));
});
}
TEST_F(ECSClientFuncTests, GetETag)
{
InitilizeAndStartECSClientThen(
GetECSClientConfiguration(),
[](ECSClient* client){
auto etag = client->GetETag();
ASSERT_EQ(etag, etagVal);
});
}
TEST_F(ECSClientFuncTests, GetSetting_Int)
{
InitilizeAndStartECSClientThen(
GetECSClientConfiguration(),
[](ECSClient* client){
auto ret = client->GetSetting(agent, "int", 0);
ASSERT_EQ(ret, 123);
});
}
TEST_F(ECSClientFuncTests, GetSetting_Bool)
{
InitilizeAndStartECSClientThen(
GetECSClientConfiguration(),
[](ECSClient* client){
auto ret = client->GetSetting(agent, "bool", false);
ASSERT_EQ(ret, true);
});
}
TEST_F(ECSClientFuncTests, GetSetting_Double)
{
InitilizeAndStartECSClientThen(
GetECSClientConfiguration(),
[](ECSClient* client){
auto ret = client->GetSetting(agent, "double", 0.0);
EXPECT_DOUBLE_EQ(ret, 1.1);
});
}
TEST_F(ECSClientFuncTests, GetSetting_String)
{
InitilizeAndStartECSClientThen(
GetECSClientConfiguration(),
[](ECSClient* client){
auto ret = client->GetSetting(agent, "string", std::string());
ASSERT_EQ(ret, std::string("str"));
});
}
TEST_F(ECSClientFuncTests, GetSettingsAsInts)
{
InitilizeAndStartECSClientThen(
GetECSClientConfiguration(),
[](ECSClient* client){
auto ret = client->GetSettingsAsInts(agent, "intArray");
ASSERT_THAT(ret, ElementsAre(1, 2));
});
}
TEST_F(ECSClientFuncTests, GetSettings)
{
InitilizeAndStartECSClientThen(
GetECSClientConfiguration(),
[](ECSClient* client){
auto ret = client->GetSettings(agent, "strArray");
ASSERT_THAT(ret, ElementsAre(std::string("hello")));
});
}
TEST_F(ECSClientFuncTests, GetSettingsAsDbls)
{
InitilizeAndStartECSClientThen(
GetECSClientConfiguration(),
[](ECSClient* client){
auto ret = client->GetSettingsAsDbls(agent, "dblArray");
ASSERT_THAT(ret, ElementsAre(1.1));
});
}
TEST_F(ECSClientFuncTests, TryGetSetting_String)
{
InitilizeAndStartECSClientThen(
GetECSClientConfiguration(),
[](ECSClient* client){
std::string val;
auto ret = client->TryGetSetting(agent, "string", val);
ASSERT_EQ(ret, true);
ASSERT_EQ(val, "str");
});
}
TEST_F(ECSClientFuncTests, TryGetSetting_Long)
{
InitilizeAndStartECSClientThen(
GetECSClientConfiguration(),
[](ECSClient* client){
long val = 0;
auto ret = client->TryGetLongSetting(agent, "int", val);
ASSERT_EQ(ret, true);
ASSERT_EQ(val, 123);
});
}
TEST_F(ECSClientFuncTests, TryGetSetting_Bool)
{
InitilizeAndStartECSClientThen(
GetECSClientConfiguration(),
[](ECSClient* client){
bool val = 0;
auto ret = client->TryGetBoolSetting(agent, "bool", val);
ASSERT_EQ(ret, true);
ASSERT_EQ(val, true);
});
}
TEST_F(ECSClientFuncTests, TryGetSetting_Int)
{
InitilizeAndStartECSClientThen(
GetECSClientConfiguration(),
[](ECSClient* client){
int val = 0;
auto ret = client->TryGetIntSetting(agent, "int", val);
ASSERT_EQ(ret, true);
ASSERT_EQ(val, 123);
});
}
TEST_F(ECSClientFuncTests, TryGetSetting_Double)
{
InitilizeAndStartECSClientThen(
GetECSClientConfiguration(),
[](ECSClient* client){
double val = 0.0;
auto ret = client->TryGetDoubleSetting(agent, "double", val);
ASSERT_EQ(ret, true);
EXPECT_DOUBLE_EQ(val, 1.1);
});
}
TEST_F(ECSClientFuncTests, GetKeys)
{
InitilizeAndStartECSClientThen(
GetECSClientConfiguration(),
[](ECSClient* client){
auto ret = client->GetKeys(agent, "");
ASSERT_THAT(ret, ElementsAre("bool", "dblArray", "double", "int", "intArray", "null", "object", "strArray", "string"));
});
}
TEST_F(ECSClientFuncTests, SetUserId)
{
auto initCallback = [](ECSClient* client){
client->SetUserId("hocai");
};
InitilizeAndStartECSClientThen(
GetECSClientConfiguration(),
[](ECSClient* client){
auto ret = client->GetConfigs();
ASSERT_EQ(ret, userIdHitString);
}, initCallback);
}
TEST_F(ECSClientFuncTests, SetDeviceId)
{
auto initCallback = [](ECSClient* client){
client->SetDeviceId("hocaiDevice");
};
InitilizeAndStartECSClientThen(
GetECSClientConfiguration(),
[](ECSClient* client){
auto ret = client->GetConfigs();
ASSERT_EQ(ret, deviceIdHitString);
}, initCallback);
}
TEST_F(ECSClientFuncTests, SetRequestParameters)
{
auto initCallback = [](ECSClient* client){
client->SetRequestParameters(std::map<std::string, std::string>{{"customFilter","filterVal"}});
};
InitilizeAndStartECSClientThen(
GetECSClientConfiguration(),
[](ECSClient* client){
auto ret = client->GetConfigs();
ASSERT_EQ(ret, filterHitString);
}, initCallback);
}
TEST_F(ECSClientFuncTests, GetActiveConfigVariant_NotStarted)
{
auto client = GetInitilizedECSClient(GetECSClientConfiguration());
auto configVariant = client->GetActiveConfigVariant();
ASSERT_EQ(configVariant, json());
}
TEST_F(ECSClientFuncTests, GetActiveConfigVariant_Started)
{
InitilizeAndStartECSClientThen(
GetECSClientConfiguration(),
[](ECSClient* client){
auto configVariant = client->GetActiveConfigVariant();
ASSERT_EQ(configVariant, json::parse(jsonConfigString));
});
}
TEST_F(ECSClientFuncTests, GetExpiryTimeInSec_NotStarted)
{
auto client = GetInitilizedECSClient(GetECSClientConfiguration());
auto expiryTimeInSec = client->GetExpiryTimeInSec();
ASSERT_EQ(expiryTimeInSec, DEFAULT_EXPIRE_INTERVAL_IN_SECONDS_MIN);
}
TEST_F(ECSClientFuncTests, GetExpiryTimeInSec_Started)
{
InitilizeAndStartECSClientThen(
GetECSClientConfiguration(),
[](ECSClient* client){
auto expiryTimeInSec = client->GetExpiryTimeInSec();
// server return expriy time is zero, client will use DEFAULT_EXPIRE_INTERVAL_IN_SECONDS_MIN as expiry time
ASSERT_EQ(expiryTimeInSec > 0, true);
ASSERT_LE(expiryTimeInSec, DEFAULT_EXPIRE_INTERVAL_IN_SECONDS_MIN);
});
}
}
#endif

Просмотреть файл

@ -0,0 +1,180 @@
// Copyright (c) Microsoft. All rights reserved.
#include "ECSClientCommon.hpp"
#ifdef HAVE_MAT_EXP
namespace {
// config: https://ecs.skype.net/?page=ExperimentPage&type=Rollout&id=45994
using namespace ECSClientCommon;
const char* const clientName = "ECS";
const char* const agent = "ECSDemo";
const char* const cacheFilePathName = "cacheFilePathName";
class ECSClientRealworldFuncTests : public ::testing::Test
{
protected:
std::string offlineStoragePath = ECSConfigCache::GetStoragePath(cacheFilePathName);
virtual void SetUp()
{
std::remove(offlineStoragePath.c_str());
}
virtual void TearDown()
{
std::remove(offlineStoragePath.c_str());
}
};
ECSClientConfiguration GetECSClientConfiguration()
{
auto config = ECSClientConfiguration();
config.clientName = clientName;
config.clientVersion = "1";
config.cacheFilePathName = cacheFilePathName;
config.serverUrls.push_back("https://s2s.config.skype.net/config/v1/");
return config;
}
TEST_F(ECSClientRealworldFuncTests, GetConfigs)
{
InitilizeAndStartECSClientThen(
GetECSClientConfiguration(),
[](ECSClient* client){
{
auto configs = client->GetConfigs();
std::cout<< configs << std::endl;
ASSERT_EQ(json::parse(configs)["ECSDemo"]["hit"], std::string("default"));
}
// TEST_F(ECSClientRealworldFuncTests, GetETag)
{
auto etag = client->GetETag();
std::cout<< etag << std::endl;
// etag start with " and end with "
// no need to check is it equal because config change will modify the val
ASSERT_EQ(0, etag.find("\""));
ASSERT_EQ(etag.size()-1, etag.rfind("\""));
}
// TEST_F(ECSClientRealworldFuncTests, GetSetting_Int)
{
auto ret = client->GetSetting(agent, "int", 0);
ASSERT_EQ(ret, 123);
}
// TEST_F(ECSClientRealworldFuncTests, GetSetting_Bool)
{
auto ret = client->GetSetting(agent, "bool", false);
ASSERT_EQ(ret, true);
}
// TEST_F(ECSClientRealworldFuncTests, GetSetting_Double)
{
auto ret = client->GetSetting(agent, "double", (double)0);
EXPECT_DOUBLE_EQ(ret, 1.1);
}
// TEST_F(ECSClientRealworldFuncTests, GetSetting_String)
{
auto ret = client->GetSetting(agent, "string", std::string());
ASSERT_EQ(ret, std::string("str"));
}
// TEST_F(ECSClientRealworldFuncTests, GetSettingsAsInts)
{
auto ret = client->GetSettingsAsInts(agent, "intArray");
ASSERT_THAT(ret, ElementsAre(1, 2));
}
// TEST_F(ECSClientRealworldFuncTests, GetSettings)
{
auto ret = client->GetSettings(agent, "strArray");
ASSERT_THAT(ret, ElementsAre(std::string("hello")));
}
// TEST_F(ECSClientRealworldFuncTests, GetSettingsAsDbls)
{
auto ret = client->GetSettingsAsDbls(agent, "dblArray");
ASSERT_THAT(ret, ElementsAre(1.1));
}
// TEST_F(ECSClientRealworldFuncTests, TryGetSetting_String)
{
std::string val = "";
auto ret = client->TryGetSetting(agent, "string", val);
ASSERT_EQ(ret, true);
ASSERT_EQ(val, "str");
}
// TEST_F(ECSClientRealworldFuncTests, TryGetSetting_Long)
{
long val = 0;
auto ret = client->TryGetLongSetting(agent, "int", val);
ASSERT_EQ(ret, true);
ASSERT_EQ(val, 123);
}
// TEST_F(ECSClientRealworldFuncTests, TryGetSetting_Bool)
{
bool val = 0;
auto ret = client->TryGetBoolSetting(agent, "bool", val);
ASSERT_EQ(ret, true);
ASSERT_EQ(val, true);
}
// TEST_F(ECSClientRealworldFuncTests, TryGetSetting_Int)
{
int val = 0;
auto ret = client->TryGetIntSetting(agent, "int", val);
ASSERT_EQ(ret, true);
ASSERT_EQ(val, 123);
}
// TEST_F(ECSClientRealworldFuncTests, TryGetSetting_Double)
{
double val = 0;
auto ret = client->TryGetDoubleSetting(agent, "double", val);
ASSERT_EQ(ret, true);
EXPECT_DOUBLE_EQ(val, 1.1);
}
// TEST_F(ECSClientRealworldFuncTests, GetKeys)
{
auto ret = client->GetKeys(agent, "");
for (auto& key: std::vector<std::string>{"bool", "dblArray", "double", "int", "intArray", "null", "object", "strArray", "string", "hit"})
{
ASSERT_NE(std::find(ret.begin(), ret.end(), key), ret.end());
}
}
});
}
TEST_F(ECSClientRealworldFuncTests, SetUserId)
{
auto initCallback = [](ECSClient* client){
client->SetUserId("testuserid");
};
InitilizeAndStartECSClientThen(
GetECSClientConfiguration(),
[](ECSClient* client){
auto ret = client->GetSetting(agent, "hit", std::string());
ASSERT_EQ(ret, std::string("userId"));
}, initCallback);
}
TEST_F(ECSClientRealworldFuncTests, SetRequestParameters)
{
auto initCallback = [](ECSClient* client){
client->SetRequestParameters(std::map<std::string, std::string>{{"projectTeam","1DS"}});
};
InitilizeAndStartECSClientThen(
GetECSClientConfiguration(),
[](ECSClient* client){
auto ret = client->GetSetting(agent, "hit", std::string());
ASSERT_EQ(ret, std::string("filter"));
}, initCallback);
}
}
#endif

Просмотреть файл

@ -0,0 +1,41 @@
// Copyright (c) Microsoft. All rights reserved.
#include "mat/config.h"
#ifdef HAVE_MAT_EXP
#include "common/Common.hpp"
#include "utils/Utils.hpp"
#include "modules/exp/ecs/ecsclient/ECSConfigCache.hpp"
using namespace testing;
using namespace MAT;
using namespace Microsoft::Applications::Experimentation::ECS;
TEST(ECSConfigCacheFuncTests, SaveConfig)
{
const std::string storagePath = "storagePath";
const std::string requestName = "requestName";
auto configCache = std::make_unique<ECSConfigCache>(storagePath);
ECSConfig config;
config.requestName = requestName;
config.etag = "etag";
auto addedConfig = configCache->AddConfig(config);
ASSERT_EQ(addedConfig->etag, configCache->GetConfigByRequestName(requestName)->etag);
ASSERT_EQ(true, configCache->SaveConfig(config));
}
TEST(ECSConfigCacheFuncTests, LoadConfig)
{
const std::string storagePath = "storagePath";
const std::string requestName = "requestName";
auto configCache = std::make_unique<ECSConfigCache>(storagePath);
ECSConfig config;
config.requestName = requestName;
config.etag = "etag";
auto addedConfig = configCache->AddConfig(config);
ASSERT_EQ(addedConfig->etag, configCache->GetConfigByRequestName(requestName)->etag);
ASSERT_EQ(true, configCache->SaveConfig(config));
configCache->LoadConfig();
}
#endif

Просмотреть файл

@ -39,6 +39,9 @@
<ProjectReference Include="..\..\zlib\contrib\vstudio\vc14\zlibvc.vcxproj">
<Project>{8fd826f8-3739-44e6-8cc8-997122e53b8d}</Project>
</ProjectReference>
<ProjectReference Include="..\..\Solutions\win32-lib\win32-lib.vcxproj">
<Project>{216a8e97-21f7-4bef-9e52-7f772c177c32}</Project>
</ProjectReference>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGUID>{FE79FB3A-B3EF-38DF-B7A4-11277DB72B39}</ProjectGUID>
@ -423,6 +426,10 @@
<ClCompile Include="BondDecoderTests.cpp" />
<ClCompile Include="EventDecoderListener.cpp" />
<ClCompile Include="LogSessionDataFuncTests.cpp" />
<ClCompile Include="ECSConfigCacheFuncTests.cpp" />
<ClInclude Include="ECSClientCommon.hpp" />
<ClCompile Include="ECSClientFuncTests.cpp" />
<ClCompile Include="ECSClientRealworldFuncTests.cpp" />
<ClInclude Include="$(ProjectDir)..\common\Common.hpp" />
<ClInclude Include="$(ProjectDir)..\common\HttpServer.hpp" />
<ClCompile Include="$(ProjectDir)..\common\Reactor.cpp" />

Просмотреть файл

@ -14,6 +14,10 @@
<ClCompile Include="BondDecoderTests.cpp" />
<ClCompile Include="EventDecoderListener.cpp" />
<ClCompile Include="LogSessionDataFuncTests.cpp" />
<ClInclude Include="ECSClientCommon.hpp" />
<ClCompile Include="ECSConfigCacheFuncTests.cpp" />
<ClCompile Include="ECSClientFuncTests.cpp" />
<ClCompile Include="ECSClientRealworldFuncTests.cpp" />
<ClCompile Include="$(ProjectDir)..\common\Reactor.cpp" />
<ClCompile Include="AISendTests.cpp" />
</ItemGroup>

Просмотреть файл

@ -42,6 +42,9 @@ set(SRCS
TransmitProfileRuleTests.cpp
TransmitProfilesTests.cpp
UtilsTests.cpp
ECSClientTests.cpp
ECSClientUtilsTests.cpp
ECSConfigCacheTests.cpp
)
if (APPLE)

Просмотреть файл

@ -0,0 +1,131 @@
// Copyright (c) Microsoft. All rights reserved.
#include "mat/config.h"
#ifdef HAVE_MAT_EXP
#include <memory>
#include "common/Common.hpp"
#include "utils/Utils.hpp"
#include "modules/exp/ecs/ecsclient/ECSClient.hpp"
using namespace testing;
using namespace MAT;
using namespace Microsoft::Applications::Experimentation::ECS;
std::unique_ptr<ECSClient> GetInitializedECSClient()
{
auto client = std::make_unique<ECSClient>();
auto config = ECSClientConfiguration();
config.clientName = "Test";
config.clientVersion = "1.0";
config.cacheFilePathName = "cacheFilePathName";
client->Initialize(config);
return client;
}
class ECSClientCallback : public IECSClientCallback
{
std::function<void()> callback;
public:
ECSClientCallback(std::function<void()> callback = nullptr):callback(callback){ }
virtual void OnECSClientEvent(ECSClientEventType evtType, ECSClientEventContext evtContext)
{
if (evtType == ECSClientEventType::ET_CONFIG_UPDATE_SUCCEEDED)
{
callback();
}
}
};
TEST(ECSClientTests, CreateInstance_OK_DestroyInstance_OK)
{
auto client = IECSClient::CreateInstance();
IECSClient::DestroyInstance(&client);
}
TEST(ECSClientTests, DestroyInstance_ArgsIsNullptr)
{
auto client = IECSClient::CreateInstance();
IECSClient::DestroyInstance(&client);
IECSClient::DestroyInstance(&client);
}
TEST(ECSClientTests, Start_Failed_NotInitialized)
{
auto client = std::make_unique<ECSClient>();
auto ret = client->Start();
ASSERT_EQ(ret, false);
}
TEST(ECSClientTests, Start_Failed_AlreadyStarted)
{
auto client = std::make_shared<ECSClient>();
auto config = ECSClientConfiguration();
config.clientName = "Test";
config.clientVersion = "1.0";
config.cacheFilePathName = "cacheFilePathName";
client->Initialize(config);
client->Start();
auto ret = client->Start();
ASSERT_EQ(ret, false);
}
TEST(ECSClientTests, Start_OK)
{
auto client = GetInitializedECSClient();
auto ret = client->Start();
ASSERT_EQ(ret, true);
}
TEST(ECSClientTests, Stop_OK)
{
auto client = GetInitializedECSClient();
auto ret = client->Start();
ASSERT_EQ(ret, true);
ret = client->Stop();
ASSERT_EQ(ret, true);
}
TEST(ECSClientTests, Suspend_OK)
{
auto client = GetInitializedECSClient();
auto ret = client->Start();
ASSERT_EQ(ret, true);
ret = client->Suspend();
ASSERT_EQ(ret, true);
}
TEST(ECSClientTests, Resume_OK)
{
auto client = GetInitializedECSClient();
auto ret = client->Start();
ASSERT_EQ(ret, true);
ret = client->Suspend();
ASSERT_EQ(ret, true);
ret = client->Resume();
ASSERT_EQ(ret, true);
}
TEST(ECSClientTests, AddListener)
{
auto client = GetInitializedECSClient();
auto callback = std::make_unique<ECSClientCallback>();
auto ret = client->AddListener(callback.get());
ASSERT_EQ(ret, true);
ret = client->AddListener(callback.get());
ASSERT_EQ(ret, false);
}
TEST(ECSClientTests, RemoveListener)
{
auto client = GetInitializedECSClient();
auto callback = std::make_unique<ECSClientCallback>();
auto ret = client->RemoveListener(callback.get());
ASSERT_EQ(ret, false);
client->AddListener(callback.get());
ret = client->RemoveListener(callback.get());
ASSERT_EQ(ret, true);
}
#endif

Просмотреть файл

@ -0,0 +1,30 @@
// Copyright (c) Microsoft. All rights reserved.
#include "mat/config.h"
#ifdef HAVE_MAT_EXP
#include "common/Common.hpp"
#include "utils/Utils.hpp"
#include "modules/exp/ecs/ecsclient/ECSClientUtils.hpp"
using namespace testing;
using namespace MAT;
using namespace Microsoft::Applications::Experimentation::ECS;
TEST(ECSClientUtilsTests, CreateServerUrl)
{
const std::string serverUrl = "https://this.is.a.fake.endpoint.com/config/v1";
const std::string clientName = "ATM";
const std::string clientVersion = "1.0.0.0";
const auto ret = CreateServerUrl(serverUrl, clientName, clientVersion);
ASSERT_EQ(ret, "https://this.is.a.fake.endpoint.com/config/v1/ATM/1.0.0.0");
}
TEST(ECSClientUtilsTests, CreateServerUrl_EmptyClientVersion)
{
const std::string serverUrl = "https://this.is.a.fake.endpoint.com/config/v1";
const std::string clientName = "ATM";
const std::string clientVersion = "";
const auto ret = CreateServerUrl(serverUrl, clientName, clientVersion);
ASSERT_EQ(ret, "https://this.is.a.fake.endpoint.com/config/v1/ATM");
}
#endif

Просмотреть файл

@ -0,0 +1,44 @@
// Copyright (c) Microsoft. All rights reserved.
#include "mat/config.h"
#ifdef HAVE_MAT_EXP
#include "common/Common.hpp"
#include "utils/Utils.hpp"
#include "modules/exp/ecs/ecsclient/ECSConfigCache.hpp"
using namespace testing;
using namespace MAT;
using namespace Microsoft::Applications::Experimentation::ECS;
TEST(ECSConfigCacheTests, Constrcut_OK_RelativePath)
{
const std::string storagePath = "path";
std::make_unique<ECSConfigCache>(storagePath);
}
TEST(ECSConfigCacheTests, Constrcut_OK_AbsolutePath)
{
const std::string storagePath = std::string("parentfolder") + PATH_SEPARATOR_CHAR + "childfolder";
std::make_unique<ECSConfigCache>(storagePath);
}
TEST(ECSConfigCacheTests, AddConfig)
{
const std::string storagePath = "path";
auto configCache = std::make_unique<ECSConfigCache>(storagePath);
const std::string requestName = "requestName";
ECSConfig config;
config.requestName = requestName;
config.etag = "etag";
auto addedConfig = configCache->AddConfig(config);
ASSERT_EQ(addedConfig->etag, configCache->GetConfigByRequestName(requestName)->etag);
}
TEST(ECSConfigCacheTests, GetConfigByRequestName_NotExistConfig)
{
const std::string storagePath = "path";
auto configCache = std::make_unique<ECSConfigCache>(storagePath);
ASSERT_EQ(NULL, configCache->GetConfigByRequestName("requestName"));
}
#endif

Просмотреть файл

@ -33,6 +33,9 @@
<ProjectReference Include="..\..\googletest\googletest\msvc\gtest.vcxproj">
<Project>{c8f6c172-56f2-4e76-b5fa-c3b423b31be7}</Project>
</ProjectReference>
<ProjectReference Include="..\..\Solutions\win32-lib\win32-lib.vcxproj">
<Project>{216a8e97-21f7-4bef-9e52-7f772c177c32}</Project>
</ProjectReference>
<ProjectReference Include="..\..\sqlite\sqlite.vcxproj">
<Project>{2ebc7b3c-2af1-442c-9285-cab39bbb8c00}</Project>
</ProjectReference>
@ -460,6 +463,9 @@
<ClCompile Include="$(ProjectDir)\TransmitProfileRuleTests.cpp" />
<ClCompile Include="$(ProjectDir)\TransmitProfilesTests.cpp" />
<ClCompile Include="$(ProjectDir)\UtilsTests.cpp" />
<ClCompile Include="$(ProjectDir)\ECSClientUtilsTests.cpp" />
<ClCompile Include="$(ProjectDir)\ECSConfigCacheTests.cpp" />
<ClCompile Include="$(ProjectDir)\ECSClientTests.cpp" />
<ClInclude Include="$(ProjectDir)..\common\Common.hpp" />
<ClInclude Include="$(ProjectDir)..\common\HttpServer.hpp" />
<ClCompile Include="$(ProjectDir)..\common\Reactor.cpp" />

Просмотреть файл

@ -51,6 +51,9 @@
<ClCompile Include="$(ProjectDir)\LoggerTests.cpp" />
<ClCompile Include="$(ProjectDir)..\common\Reactor.cpp" />
<ClCompile Include="$(ProjectDir)\DeviceStateHandlerTests.cpp" />
<ClCompile Include="$(ProjectDir)\ECSClientTests.cpp" />
<ClCompile Include="$(ProjectDir)\ECSClientUtilsTests.cpp" />
<ClCompile Include="$(ProjectDir)\ECSConfigCacheTests.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="$(ProjectDir)..\common\MockIHttpClient.hpp">