美文网首页
使用C++11动态解析json并使用DataFrame进行结果对

使用C++11动态解析json并使用DataFrame进行结果对

作者: FredricZhu | 来源:发表于2021-10-26 20:39 被阅读0次

    本例特点,

    1. 使用Debug::DeathHandler类来进行异常trace打印。
      注意Google GTest框架默认会捕获所有异常,导致C++的SIG_TERM信号无法被捕捉。
      所以需要设置环境变量 ENV GTEST_CATCH_EXCEPTIONS 0
      2.使用nlohmann::json做中间字典转换。类似一个python的万能dict类型。 nlohmann::json本身做了类型擦除,可以存储任意类型的变量。
      3.使用hosseinmoein DataFrame进行数据比对,得出结果。
      整体思路和Python类似。
      有了Debug::DeathHandler以后,效率大幅提升,类似不需要打断点了,几乎一看就知道什么异常。
      程序目录如下,


      image.png

    代码如下,
    CMakeLists.txt

    cmake_minimum_required(VERSION 2.6)
    
    if(APPLE)
        message(STATUS "This is Apple, do nothing.")
    elseif(UNIX)
        message(STATUS "This is linux, set CMAKE_PREFIX_PATH.")
        set(CMAKE_PREFIX_PATH /vcpkg/ports/cppwork/vcpkg_installed/x64-linux/share)
    endif(APPLE)
    
    project(app_perf_test)
    
    add_definitions(-std=c++17)
    add_definitions(-g)
    
    find_package(ZLIB)
    
    find_package(glog REQUIRED)
    
    find_package(OpenCV REQUIRED )
    
    find_package(Boost REQUIRED COMPONENTS
        system
        filesystem
        serialization
        program_options
        thread
        )
    
    find_package(DataFrame REQUIRED)
    
    if(APPLE)
        MESSAGE(STATUS "This is APPLE, set INCLUDE_DIRS")
    set(INCLUDE_DIRS ${Boost_INCLUDE_DIRS} /usr/local/include /usr/local/iODBC/include /opt/snowflake/snowflakeodbc/include/ ${CMAKE_CURRENT_SOURCE_DIR}/../../)
    elseif(UNIX)
        MESSAGE(STATUS "This is linux, set INCLUDE_DIRS")
        set(INCLUDE_DIRS ${Boost_INCLUDE_DIRS} /usr/local/include ${CMAKE_CURRENT_SOURCE_DIR}/../../)
    endif(APPLE)
    
    
    if(APPLE)
        MESSAGE(STATUS "This is APPLE, set LINK_DIRS")
        set(LINK_DIRS /usr/local/lib /usr/local/iODBC/lib /opt/snowflake/snowflakeodbc/lib/universal)
    elseif(UNIX)
        MESSAGE(STATUS "This is linux, set LINK_DIRS")
        set(LINK_DIRS ${Boost_INCLUDE_DIRS} /usr/local/lib /vcpkg/ports/cppwork/vcpkg_installed/x64-linux/lib)
    endif(APPLE)
    
    if(APPLE)
        MESSAGE(STATUS "This is APPLE, set ODBC_LIBS")
        set(ODBC_LIBS iodbc iodbcinst)
    elseif(UNIX)
        MESSAGE(STATUS "This is linux, set LINK_DIRS")
        set(ODBC_LIBS odbc odbcinst ltdl)
    endif(APPLE)
    
    include_directories(${INCLUDE_DIRS})
    LINK_DIRECTORIES(${LINK_DIRS})
    
    
    file( GLOB APP_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../impl/*.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../utils/*.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../cases/*.cpp ${CMAKE_CURRENT_SOURCE_DIR}/*.h ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp  ${CMAKE_CURRENT_SOURCE_DIR}/../../http/impl/*.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../yaml/impl/*.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../df/impl/*.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../death_handler/impl/*.cpp)
    foreach( sourcefile ${APP_SOURCES} )
            file(RELATIVE_PATH filename ${CMAKE_CURRENT_SOURCE_DIR} ${sourcefile})
        
            string(FIND "${filename}"  "test.cpp" "TEMP")
        if( NOT "${TEMP}" STREQUAL "-1" )
            string(REPLACE ".cpp" "" file ${filename})
            add_executable(${file}  ${APP_SOURCES})
            target_link_libraries(${file} ${Boost_LIBRARIES} ZLIB::ZLIB glog::glog DataFrame::DataFrame ${OpenCV_LIBS})
            target_link_libraries(${file}  ssl crypto libgtest.a pystring libyaml-cpp.a libgmock.a ${ODBC_LIBS} libnanodbc.a pthread dl backtrace)
        endif()
    endforeach( sourcefile ${APP_SOURCES})
    

    test_cfg.h

    #ifndef _FREDRIC_TEST_CFG_H_
    #define _FREDRIC_TEST_CFG_H_
    
    #include <string>
    #include <map>
    
    extern std::string v2_query_path;
    extern int max_compare_count;
    
    extern std::string www_host;
    extern std::string api_host;
    
    extern std::string www_company_path;
    
    extern std::map<std::string, std::string> www_headers;
    
    extern std::map<std::string, std::string> api_headers;
    extern bool use_file;
    
    // App Performance related json files
    
    extern std::string apps_meta_file;
    
    extern std::string test_dim_parse_data_file;
    
    #endif
    

    utils/req.h

    #ifndef _FREDRIC_REQ_H_
    #define _FREDRIC_REQ_H_
    
    #include <string>
    
    struct Req {
        static std::string make_a_www_query(const std::string& path, const std::string& body);
        static std::string make_a_api_query(const std::string& path); 
    };
    #endif
    

    utils/req.cpp

    #include "api_accuracy/utils/req.h"
    #include "http/http_util.h"
    #include "api_accuracy/test_cfg.h"
    
    #include <glog/logging.h>
    
    std::string Req::make_a_www_query(const std::string& path, const std::string& body) {
        std::string www_res{};
        bool get_www_res = HttpUtil::post_and_get_str(www_host, path, www_headers, body, www_res);
        if(!get_www_res) {
            LOG(ERROR) << "Get WWW result failure" << "\n";
            return "";
        }
        return std::move(www_res);
    }
    
    std::string Req::make_a_api_query(const std::string& path) {
        std::string api_res{};
        bool get_api_res = HttpUtil::get_str(api_host, path, api_headers, api_res);
        if(!get_api_res) {
            LOG(ERROR) << "Get api result failure" << "\n";
            return "";
        }
        return std::move(api_res);
    }
    

    utils/io_util.h

    #ifndef _FREDRIC_IO_UTIL_H_
    #define _FREDRIC_IO_UTIL_H_
    
    #include <string>
    
    struct IOUtil {
        static std::string read_file(const std::string& file_name);
        static bool write_file(const std::string& file_name, const std::string& content);
    };
    
    #endif
    

    utils/io_util.cpp

    #include "api_accuracy/utils/io_util.h"
    
    #include <glog/logging.h>
    #include <fstream>
    
    std::string IOUtil::read_file(const std::string& file_name)  {
            std::fstream fs{file_name};
            if(!fs.is_open()) {
                LOG(ERROR) << "Open file [" << file_name << "] failed" << "\n";
                return "";
            }
            std::stringstream ss {};
            ss << fs.rdbuf();
            return std::move(ss.str());
    }
    
    bool IOUtil::write_file(const std::string& file_name, const std::string& content) {
        std::fstream fs{file_name, std::ios::out | std::ios::trunc};
        if(!fs.is_open()) {
            LOG(ERROR) << "Open file [" << file_name << "] failed" << "\n";
            return false;
        }
    
        fs << content;
        fs.close();
        return true;
    }
    

    utils/funcs.h

    #ifndef _FREDRIC_FUNCS_H_
    #define _FREDRIC_FUNCS_H_
    
    #include "json/json.hpp"
    
    #include <vector>
    #include <string>
    #include <map>
    
    using json = nlohmann::json;
    
    std::vector<std::string> get_map_keys(const std::map<std::string, std::string>& field_mapping);
    std::vector<std::string> get_map_values(const std::map<std::string, std::string>& field_mapping);
    std::string read_query_file_and_replace_consts(const json& prod, const std::string& www_query_file_name);
    json parse_dim_product_fields(const json& result_json, const std::vector<std::string>& dim_keys_);
    json convert_dim_values_to_api_values(const json& values, const std::map<std::string, std::string>& api_dim_mapping);
    bool find_diff_and_save_f(const json& values_, const json& act_www_values_, const std::string& api_data_field_name);
    #endif
    

    utils/funcs.cpp

    #include "api_accuracy/utils/funcs.h"
    #include "api_accuracy/utils/io_util.h"
    #include "df/df.h"
    
    #include <pystring/pystring.h>
    
    #include <cstddef>
    #include <algorithm>
    
    std::vector<std::string> get_map_keys(const std::map<std::string, std::string>& field_mapping) {
        std::vector<std::string> keys{};
        std::for_each(field_mapping.begin(), field_mapping.end(), [&keys](const auto& item){
            keys.push_back(item.first);
        });
        return keys;
    }
    
    std::vector<std::string> get_map_values(const std::map<std::string, std::string>& field_mapping) {
        std::vector<std::string> values{};
        std::for_each(field_mapping.begin(), field_mapping.end(), [&values](const auto& item){
            values.push_back(item.second);
        });
        return values;
    }
    
    
    std::string read_query_file_and_replace_consts(const json& prod, const std::string& www_query_file_name) {
        auto product_id = prod["product_id"].get<int64_t>();
        auto market_code = prod["market_code"].get<std::string>();
        auto start_date = prod["start_date"].get<std::string>();
        auto end_date = prod["end_date"].get<std::string>();
        auto country_code = prod["countries"].get<std::string>();
        auto device_code = prod["devices"].get<std::string>();
        auto granularity = prod["granularity"].get<std::string>();
    
        auto file_content = IOUtil::read_file(www_query_file_name);
    
        file_content = pystring::replace(file_content, "${product_id}", std::to_string(product_id));
        file_content = pystring::replace(file_content, "${market_code}", market_code);
        file_content = pystring::replace(file_content, "${start_date}", start_date);
        file_content = pystring::replace(file_content, "${end_date}", end_date);
        std::vector<std::string> country_list{};
        pystring::split(country_code, country_list, ",");
        json country_js = country_list;
        file_content = pystring::replace(file_content, "${country_code}", country_js.dump());
        file_content = pystring::replace(file_content, "${granularity}", granularity);
    
        if(country_list[0] == "all_supported") {
            auto content_js = json::parse(file_content);
            content_js["filters"].erase("country_code");
            file_content = content_js.dump();
        }
    
        std::vector<std::string> device_list{};
        pystring::split(device_code, device_list, ",");
        if(device_list[0] != "all_supported") {
            auto content_js = json::parse(file_content);
            content_js["filters"]["device_code"] = {
                {"in", device_list}
            };
            file_content = content_js.dump();
        }
    
        return file_content;
    }
    
    
    json parse_dim_product_fields(const json& result_json, const std::vector<std::string>& dim_keys_) {
        json values;
        auto facets = result_json["data"]["facets"];
        auto dims = result_json["data"]["dimensions"];
        for(auto&& facet_: facets) {
            json value;
            for(auto&& dim_key_: dim_keys_) {
                if(dim_key_.find("/") == std::string::npos) {
                    value[dim_key_] = facet_[dim_key_];
                } else {
                    json tmp_val;
                    std::string tmp_key = "";
                    std::vector<std::string> one_dim_keys {};
                    pystring::split(dim_key_, one_dim_keys, "/");
                    for(int i=0; i<one_dim_keys.size(); ++i) {
                        if(i==0) {
                            tmp_key = one_dim_keys[0];
                            if(!facet_[tmp_key].is_null()) {
                                tmp_val = std::to_string(facet_[tmp_key].get<int64_t>());
                            }else {
                                break;
                            }
                        }else {
                            for(auto&& begin=dims.begin(), end = dims.end(); begin!=end; ++begin) {
                                auto in_dim_key = begin.key();
                                auto in_dim_val = begin.value();
    
                                if(one_dim_keys[i-1] == in_dim_key) {
                                    for(auto&& ii_begin=in_dim_val.begin(), ii_end=in_dim_val.end(); ii_begin!=ii_end; ++ii_begin) {
                                        auto ii_dim_key = ii_begin.key();
                                        auto ii_dim_val = ii_begin.value();
                                        if(ii_dim_key == tmp_val.get<std::string>()) {
                                            if(i == (one_dim_keys.size() - 1)){
                                                 tmp_val = ii_dim_val[one_dim_keys[i]];
                                            }else {
                                                if(!ii_dim_val[one_dim_keys[i]].is_null()) {
                                                    tmp_val = std::to_string(ii_dim_val[one_dim_keys[i]].get<int64_t>());
                                                } else {
                                                    break;
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                    value[dim_key_] = tmp_val;
                }
            }
            values.emplace_back(std::move(value));
        }
        return std::move(values);
    }
    
    json convert_dim_values_to_api_values(const json& values, const std::map<std::string, std::string>& api_dim_mapping) {
        json new_values;
        for(auto&& value: values) {
            json new_value;
            for(auto&& api_dim_item: api_dim_mapping) {
                auto api_key = api_dim_item.first; 
                auto dim_key = api_dim_item.second;
                new_value[api_key] = value[dim_key];
            }
            new_values.emplace_back(std::move(new_value));
        }
        return std::move(new_values);
    }
    
    bool find_diff_and_save_f(const json& values_, const json& act_www_values_, const std::string& api_data_field_name) {
        std::vector<std::string> pri_keys_{};
        auto df1 = df_op::convert_json_to_df(values_, pri_keys_);
        auto df2 = df_op::convert_json_to_df(act_www_values_, pri_keys_);
        std::string res_csv_path = "../result/" + api_data_field_name + "_res.csv";
        if(values_.size() == 0 && act_www_values_.size() == 0) {
            return false;
        }else if(values_.size() == 0 && act_www_values_.size()!=0) {
            df_op::write_to_csv(df2, res_csv_path);
            return true;
        }else if(values_.size() != 0 && act_www_values_.size() == 0) {
            df_op::write_to_csv(df1, res_csv_path);
            return true;
        }else {
            auto df3 = df1.concat<decltype(df2), json>(df2, concat_policy::all_columns);
            std::vector<std::string> keys_{Keys};
            auto df4 = df_op::remove_duplicate(df3, keys_);
            auto df_rows = df4.shape().first;
            if(df_rows == 0) {
                return false;
            }
    
            df_op::write_to_csv(df3, res_csv_path);
            return true;
        }
    }
    

    utils/compare.h

    #ifndef _FREDRIC_COMPARE_H_
    #define _FREDRIC_COMPARE_H_
    
    #include <json/json.hpp>
    
    #include <map>
    #include <string>
    
    using json = nlohmann::json;
    
    struct Compare {
        Compare(const json& app_perf_result);
    
        json get_api_products_fields(const std::map<std::string, std::string>& field_mapping);
    
        json get_www_product_fields(const json& prod, const std::string& www_request_file_name, const std::map<std::string, std::string>& field_mapping);
    
        bool compare_api_and_www_meta_equal(const std::map<std::string, std::string>& field_mappings, const std::string& www_query_file);
    
        json  app_perf_result_;
    };
    #endif
    

    utils/compare.cpp

    #include "api_accuracy/utils/compare.h"
    #include "api_accuracy/utils/funcs.h"
    #include "api_accuracy/utils/req.h"
    #include "api_accuracy/test_cfg.h"
    
    #include "glog/logging.h"
    
    Compare::Compare(const json& app_perf_result) {
        app_perf_result_ = app_perf_result;
    }
    
    
    json Compare::get_api_products_fields(const std::map<std::string, std::string>& field_mapping) {
        auto start_date = app_perf_result_["start_date"];
        auto end_date = app_perf_result_["end_date"];
        auto countries = app_perf_result_["countries"];
        auto granularity = app_perf_result_["granularity"];
        auto devices = app_perf_result_["devices"];
        auto products = app_perf_result_["products"];
        auto api_fields = get_map_keys(field_mapping);
    
        json api_values {};
        for(auto&& product_: products) {
            json api_value {};
            auto product_id = product_["product_id"];
            auto market_code = product_["market_code"];
            json prod_{
                {"product_id", product_id},
                {"market_code", market_code},
                {"granularity", granularity},
                {"start_date", start_date},
                {"end_date", end_date},
                {"countries", countries},
                {"devices", devices}
            };
            api_value["product"] = prod_;
            json values {};
            json value {};
            for(auto api_field: api_fields) {
                value[api_field] = product_[api_field];
            }
            values.emplace_back(std::move(value));
            api_value["values"] = values;
            api_values.push_back(std::move(api_value));
        }
        return api_values;
    }
    
    
    json Compare::get_www_product_fields(const json& prod, const std::string& www_request_file_name, const std::map<std::string, std::string>& field_mapping) {
        auto dar_query_str = read_query_file_and_replace_consts(prod, www_request_file_name);
        LOG(ERROR) << dar_query_str << "\n";
        auto dar_query_res_str = Req::make_a_www_query(v2_query_path, dar_query_str);
        auto dar_query_res = json::parse(dar_query_res_str);
        auto field_values = get_map_values(field_mapping);
        auto www_query_tmp_res = parse_dim_product_fields(dar_query_res, field_values);
        auto www_query_res = convert_dim_values_to_api_values(www_query_tmp_res, field_mapping);
    
        return www_query_res;
    }
    
    
    bool Compare::compare_api_and_www_meta_equal(const std::map<std::string, std::string>& field_mappings, const std::string& www_query_file) {
        auto api_products_ = get_api_products_fields(field_mappings);
        bool is_value_equal = true;
        int i = 0;
    
        for(auto&& api_prod_: api_products_) {
            auto prod_ = api_prod_["product"];
            auto values_ = api_prod_["values"];
            ++i;
            // 对比前max_compare_count条,退出
            if(i > max_compare_count) {
                    LOG(INFO) << "Hit " << max_compare_count << " records, return." << "\n";
                    break;
            }
            
            auto www_values_ = get_www_product_fields(prod_, www_query_file, field_mappings);
            LOG(INFO) << values_.dump() << "\n";
            LOG(INFO) << www_values_.dump() << "\n";
    
            std::sort(values_.begin(), values_.end());
            std::sort(www_values_.begin(), www_values_.end());
            bool has_diff = find_diff_and_save_f(values_, www_values_, "www_meta_info");
            is_value_equal = !has_diff;
            if(!is_value_equal) {
                LOG(ERROR) << "API and www values are not equals\n";
                LOG(ERROR) << "API : www_meta_info\n"; 
                LOG(ERROR) << values_ << "\n";
                LOG(ERROR) << "WWW : www_meta_info\n";
                LOG(ERROR) << www_values_ << "\n";
                break;
            }
        }
        return is_value_equal;
    }
    

    utils/case.h

    #ifndef _FREDRIC_CASE_H_
    #define _FREDRIC_CASE_H_
    #include <string>
    
    struct Case {
        std::string name;
        std::string url;
        int expect_code;
    };
    
    #endif
    

    utils/beans.h

    #ifndef _FREDRIC_BEANS_H_
    #define _FREDRIC_BEANS_H_
    
    #include <map>
    #include <string>
    
    extern std::map<std::string, std::string> DimProductMapping;
    
    #endif
    

    utils/beans.cpp

    #include "api_accuracy/utils/beans.h"
    
    std::map<std::string, std::string> DimProductMapping {
        {"product_id", "product_id"},
        {"product_name", "name"},
        {"product_description", "description"},
        {"category_id", "category_id"},
        {"unified_product_id", "unified_product_id"},
        {"category_name", "category_id/name"},
        {"category_slug", "category_id/slug"},
        {"market_code", "market_code"},
        {"publisher_name", "publisher_id/name"},
        {"publisher_market", "publisher_id/market_code"},
        {"company_name", "publisher_id/company_id/name"},
        {"company_exchange", "publisher_id/company_id/exchange"},
        {"company_stock_symbol", "publisher_id/company_id/ticker_symbol"},
        {"company_website", "publisher_id/company_id/website"},
        {"company_is_public", "publisher_id/company_id/is_public_company"}
    };
    

    test/app_perf_test.cpp

    #include "api_accuracy/cases/app_perf_cases.h"
    #include "api_accuracy/test_cfg.h"
    #include "api_accuracy/utils/req.h"
    #include "api_accuracy/utils/io_util.h"
    #include "api_accuracy/utils/funcs.h"
    #include "api_accuracy/utils/beans.h"
    #include "api_accuracy/utils/compare.h"
    
    #include "pystring/pystring.h"
    #include "json/json.hpp"
    #include "death_handler/death_handler.h"
    
    #include <glog/logging.h>
    #include <boost/filesystem.hpp>
    
    
    #include <gtest/gtest.h>
    
    
    using json = nlohmann::json;
    
    int main(int argc, char** argv) {
        FLAGS_log_dir = "./";
        FLAGS_alsologtostderr = true;
    
        Debug::DeathHandler dh;
    
        google::InitGoogleLogging("./logs.log");
        testing::InitGoogleTest(&argc, argv);
        int ret = RUN_ALL_TESTS();
        return ret;
    }
    
    class AppPerfTests: public testing::Test {
        protected:
        virtual void SetUp(){
            for(auto&& case_: app_perf_pos_cases) {
                auto case_name = case_.name;
                auto case_url = case_.url;
    
                if(!use_file) {
                    auto case_result_ = Req::make_a_api_query(case_url);
                    bool write_res = IOUtil::write_file(case_name, case_result_);
                    if(!write_res) {
                        // Write case result failed
                        ASSERT_TRUE(false);
                    }
                }
                auto content_ = IOUtil::read_file(case_name);
                app_perf_results[case_name] = json::parse(content_);
            }
        }
    
        virtual void TearDown(){
           
        }
    
        std::map<std::string, json> app_perf_results;
    };
    
    TEST_F(AppPerfTests, ReadFile) {
        auto query_str = IOUtil::read_file(app_perf_pos_cases[0].name);
        LOG(INFO) << query_str << "\n";
        ASSERT_TRUE(query_str!="");
    }
    
    TEST_F(AppPerfTests, GetMapKeys) { 
        auto keys = get_map_keys(DimProductMapping);
        LOG(INFO) << keys.size() << "\n";
        ASSERT_EQ(15, keys.size());
    }
    
    TEST_F(AppPerfTests, GetMapValues) { 
        auto values = get_map_values(DimProductMapping);
        LOG(INFO) << values.size() << "\n";
        ASSERT_EQ(15, values.size());
    }
    
    
    TEST_F(AppPerfTests, GetApiProductFields) { 
        auto app_perf_result = app_perf_results.begin()->second;
        std::cerr << app_perf_result["start_date"] << std::endl;
        Compare c {app_perf_result};
        auto values = c.get_api_products_fields(DimProductMapping);
        ASSERT_TRUE(values.size() > 0);
    }
    
    TEST_F(AppPerfTests, JsonDumpStdVector) {
        std::string country_code = "US,CN,JP,CA";
        std::vector<std::string> results_{}; 
        pystring::split(country_code, results_, ",");
        json js = results_;
        ASSERT_EQ(4, js.size());
    }
    
    TEST_F(AppPerfTests, JsonDelInnerKey) {
        auto js_str = R"(
            {
                "person": {
                    "name": "Zhangsan",
                    "age": 34
                },
                "grade": 3
            }
        )";
        json js = json::parse(js_str);
        js["person"].erase("age");
        LOG(INFO) << js.dump() << "\n";
    }
    
    TEST_F(AppPerfTests, ReadQueryFileAndReplaceConsts) {
        json prod = json::parse(R"({
            "product_id": 1111,
            "market_code": "google-play",
            "start_date": "2021-01-01",
            "end_date": "2021-01-31",
            "countries": "CN,US,JP",
            "devices": "android-all,android-tv",
            "granularity": "monthly"
            })");
        auto apps_meta_query_str = read_query_file_and_replace_consts(prod, apps_meta_file);
        LOG(INFO) << apps_meta_query_str << "\n";
    }
    
    TEST_F(AppPerfTests, ReadQueryFileAndReplaceConstsAllCountries) {
        json prod = json::parse(R"({
            "product_id": 1111,
            "market_code": "google-play",
            "start_date": "2021-01-01",
            "end_date": "2021-01-31",
            "countries": "all_supported",
            "devices": "android-all,android-tv",
            "granularity": "monthly"
            })");
        auto apps_meta_query_str = read_query_file_and_replace_consts(prod, apps_meta_file);
        LOG(INFO) << apps_meta_query_str << "\n";
    }
    
    
    TEST_F(AppPerfTests, ParseDimProductFields) {
        auto dim_file_str = IOUtil::read_file(test_dim_parse_data_file);
        auto dim_file = json::parse(dim_file_str);
        auto dim_keys_ = get_map_values(DimProductMapping);
        auto dim_values = parse_dim_product_fields(dim_file, dim_keys_);
        auto api_values = convert_dim_values_to_api_values(dim_values, DimProductMapping);
        LOG(INFO) << api_values << "\n";
    }
    
    TEST_F(AppPerfTests, TestProductMetadata) {
        bool is_case_pass = true;
        for(auto&& case_item: app_perf_results) {
            auto app_perf_file = case_item.first;
            auto app_perf_result = case_item.second;
            auto comp_ = Compare(app_perf_result);
            auto is_value_equal = comp_.compare_api_and_www_meta_equal(DimProductMapping, apps_meta_file); 
            if(!is_value_equal) {
                LOG(ERROR) << "[" << app_perf_file  << "] test [test_product_metadata] failed!\n"; 
                is_case_pass = false;
            }
        }
        ASSERT_TRUE(is_case_pass);
    }
    

    test/datas/app_perf/apps_meta_data.json

    {
        "facets": ["product_id"],
        "filters": {
            "product_id": {
                "equal": ${product_id}
            },
            "granularity": {
                "equal": "${granularity}"
            },
            "date": {
                "between": [
                  "${start_date}",
                  "${end_date}"
                ]
            },
            "country_code": {
                "in": ${country_code}
            }
        },
        "fields": {
            "product_id": {
                "fields": [
                    "name",
                    "market_code",
                    "device_code",
                    "description",
                    "price",
                    "has_iap",
                    "unified_product_id",
                    "category_id",
                    "publisher_id"
                ],
                "publisher_id": {
                    "fields": [
                        "name",
                        "market_code",
                        "website",
                        "company_id"
                    ],
                    "company_id": {
                        "fields": [
                            "name",
                            "exchange",
                            "ticker_symbol",
                            "website",
                            "is_public_company",
                            "country_code"
                        ]
                    }
                },
                "category_id": {"fields": ["name", "slug"]}
            }
        }
    }
    

    impl/test_cfg.cpp

    #include "api_accuracy/test_cfg.h"
    
    std::string api_host = "tai4-api.appannie.com";
    std::string www_host = "api2.appannie.com";
    
    std::string v2_query_path = "/v2/query";
    int max_compare_count = 10; 
    
    std::map<std::string, std::string> www_headers{
        {"Authorization", "Bearer 501b0ae76f7732aa7335564e7795ad9bb8ffe493"},
        {"Content-Type", "application/json"}
    };
    
    std::map<std::string, std::string> api_headers{
        {"Authorization", "Bearer cb5685cc45423934256c893cff23408b1a50208c"},
        {"Content-Type", "application/json"}
    };
    
    bool use_file = true;
    
    std::string apps_meta_file = "../datas/app_perf/apps_meta_data.json";
    std::string test_dim_parse_data_file = "../datas/app_perf/test_dim_parse_data.json";
    

    cases/app_perf_cases.h

    #ifndef _FREDRIC_APP_PERF_CASES_H_
    #define _FREDRIC_APP_PERF_CASES_H_
    #include "api_accuracy/utils/case.h"
    
    #include <vector>
    
    extern std::vector<Case> app_perf_pos_cases;
    
    #endif
    

    cases/app_perf_cases.cpp

    #include "api_accuracy/cases/app_perf_cases.h"
    
    std::vector<Case> app_perf_pos_cases {
        {"../datas/app_perf/test545__200_ok_monthly_api_response", "/v1.3/portfolio/app-performance/less?company_id=1000200000000034&granularity=monthly&start_date=2020-01-01&end_date=2020-03-31&countries=US,CN,JP,GB", 0}
    };
    

    程序输出如下,


    image.png

    相关文章

      网友评论

          本文标题:使用C++11动态解析json并使用DataFrame进行结果对

          本文链接:https://www.haomeiwen.com/subject/eyvyaltx.html