Exemple #1
0
Fichier : Test.cpp Projet : ktf/DDS
void check_topology_maps(const string& _topoName)
{
    CTopology topology;
    string topoFile(_topoName + ".xml");
    topology.init(topoFile, true);

    output_test_stream output1(_topoName + "_maps_1.txt", true);
    for (const auto& v : topology.getTopoIndexToTopoElementMap())
    {
        output1 << v.first.getPath() << " " << v.second->getPath() << "\n";
        // std::cout << v.first.getPath() << " " << v.second->getPath() << "\n";
    }
    BOOST_CHECK(output1.match_pattern());

    output_test_stream output2(_topoName + "_maps_2.txt", true);
    check_topology_map_task(topology.getHashToTaskInfoMap(), output2);

    output_test_stream output3(_topoName + "_maps_3.txt", true);
    check_topology_map(topology.getHashToTaskCollectionMap(), output3);

    output_test_stream output4(_topoName + "_maps_4.txt", true);
    check_topology_map(topology.getHashPathToTaskMap(), output4);

    output_test_stream output5(_topoName + "_maps_5.txt", true);
    check_topology_map(topology.getHashPathToTaskCollectionMap(), output5);
}
int main(int argc, char* argv[])
{
    try
    {
        chrono::high_resolution_clock::time_point t1 = chrono::high_resolution_clock::now();

        CUserDefaults::instance(); // Initialize user defaults
        Logger::instance().init(); // Initialize log

        size_t nInstances(0);
        size_t nMaxValue(g_maxValue);
        size_t type(0);
        size_t timeout(g_timeout);
        bool testErrors(true);

        // Generic options
        bpo::options_description options("task-test_key_value options");
        options.add_options()("help,h", "Produce help message");
        options.add_options()(
            "instances,i", bpo::value<size_t>(&nInstances)->default_value(0), "A number of instances");
        options.add_options()(
            "max-value", bpo::value<size_t>(&nMaxValue)->default_value(g_maxValue), "A max value of the property");
        options.add_options()("type,t", bpo::value<size_t>(&type)->default_value(0), "Type of task. Must be 0 or 1.");
        options.add_options()("test-errors",
                              "Indicates that taks will also put incorrect data and test the error messages.");
        options.add_options()("timeout",
                              bpo::value<size_t>(&timeout)->default_value(g_timeout),
                              "A max timeout for a task to get all properties.");

        // Parsing command-line
        bpo::variables_map vm;
        bpo::store(bpo::command_line_parser(argc, argv).options(options).run(), vm);
        bpo::notify(vm);

        if (vm.count("help") || vm.empty())
        {
            cout << options;
            return 0;
        }

        testErrors = vm.count("test-errors");

        LOG(info) << "Start task with type " << type;

        // Get list of READ and WRITE properties from topology
        CTopology topo;
        topo.init();
        uint64_t taskId = env_prop<EEnvProp::task_id>();
        const STopoRuntimeTask& runtimeTask = topo.getRuntimeTaskById(taskId);
        const CTopoProperty::PtrMap_t& properties = runtimeTask.m_task->getProperties();
        vector<string> readPropertyNames;
        vector<string> writePropertyNames;
        for (auto property : properties)
        {
            CTopoProperty::EAccessType accessType = property.second->getAccessType();
            string propertyName(property.first);
            if (accessType == CTopoProperty::EAccessType::READ)
            {
                readPropertyNames.push_back(propertyName);
            }
            else
            {
                writePropertyNames.push_back(propertyName);
            }
        }

        // DDS Intercom API
        CIntercomService service;
        CKeyValue keyValue(service);
        mutex keyMutex;
        condition_variable keyCondition;
        // on task done condition
        condition_variable onTaskDoneCondition;

        map<string, string> keyValueCache;
        size_t numWaits = 0;
        size_t numUpdateKeyValueCalls = 0;
        size_t currentIteration = (type == 0) ? 1 : 0;
        size_t numTaskDone = 0;

        // Subscribe on error events
        service.subscribeOnError([/*&keyCondition*/](EErrorCode _errorCode, const string& _msg) {
            LOG(error) << "Key-value error code: " << _errorCode << ", message: " << _msg;
        });

        // Subscribe on task done notifications
        service.subscribeOnTaskDone(
            [&numTaskDone, nInstances, &onTaskDoneCondition](uint64_t _taskID, uint32_t _exitCode) {
                ++numTaskDone;
                LOG(info) << "Task Done notification received for task " << _taskID << " with exit code " << _exitCode;
                // TODO: In order to properly account finished tasks, use taskID to get task's name
                if (numTaskDone >= nInstances)
                    onTaskDoneCondition.notify_all();
            });

        // Subscribe on key update events
        // DDS garantees that this callback function will not be called in parallel from multiple threads.
        // It is safe to update global data without locks inside the callback.
        keyValue.subscribe([&keyCondition, &currentIteration, &keyValueCache, &nInstances, &numUpdateKeyValueCalls](
                               const string& _propertyName, const string& _value, uint64_t _senderTaskID) {
            numUpdateKeyValueCalls++;

            string key = _propertyName + "." + to_string(_senderTaskID);
            keyValueCache[key] = _value;

            // Check that all values in the key-value cache have a correct value
            size_t counter = 0;
            string currentValue = to_string(currentIteration);
            for (const auto& v : keyValueCache)
            {
                if (v.second == currentValue)
                    counter++;
            }

            if (counter == nInstances * 5)
            {
                currentIteration += 2;
                keyCondition.notify_all();
            }
        });

        // Start listening to events we have subscribed on
        service.start();

        for (size_t i = 0; i < nMaxValue; ++i)
        {
            LOG(info) << "Start iteration " << i << ". Current value: " << currentIteration;

            // For tasks with type 0 we start with writing the properties.
            if ((i % 2 == 0 && type == 0) || (i % 2 == 1 && type == 1))
            {
                LOG(info) << "Iteration " << i << " start sending values.";

                string writePropValue = to_string(i);
                for (const auto& prop : writePropertyNames)
                {
                    keyValue.putValue(prop, writePropValue);
                }

                LOG(info) << "Iteration " << i << " all values have been sent.";

                // Writing non existing and readonly properties to test the errors
                if (testErrors)
                {
                    LOG(info) << "Iteration " << i << " sending wrong properties.";
                    keyValue.putValue("non_existing_property", "non_existing_property_name");
                    for (const auto& prop : readPropertyNames)
                    {
                        keyValue.putValue(prop, writePropValue);
                    }
                }
            }
            // For tasks with type 1 we start with subscribtion to properties.
            else if ((i % 2 == 0 && type == 1) || (i % 2 == 1 && type == 0))
            {
                LOG(info) << "Iteration " << i << " subscribe on property updates. Current value: " << currentIteration;

                unique_lock<mutex> lock(keyMutex);
                bool waitStatus = keyCondition.wait_for(
                    lock, chrono::seconds(timeout), [&currentIteration, &i] { return currentIteration > i; });

                // Timeout waiting for property updates
                if (waitStatus == false)
                {
                    LOG(error) << "Iteration " << i << " timed out waiting for property updates.";
                    LOG(error) << "Number of key-value update calls: " << numUpdateKeyValueCalls
                               << "; currentIteration: " << currentIteration << "; numWaits: " << numWaits;

                    LOG(error) << "Key value cache.\n" << map_to_string(keyValueCache);

                    if (currentIteration == nMaxValue - 1)
                    {
                        LOG(warning) << "Some properties of the LAST iteration are missing.";
                    }
                    else
                    {
                        LOG(fatal) << "Task failed: timeout wait for property updates.";
                        return EXIT_FAILURE;
                    }
                }

                LOG(info) << "Iteration " << i << " got all properties. Current value: " << currentIteration;
            }
        }

        if ((nMaxValue % 2 == 0 && type == 0) || (nMaxValue % 2 == 1 && type == 1))
        {
            unique_lock<mutex> lock(keyMutex);
            bool waitStatus = onTaskDoneCondition.wait_for(
                lock, chrono::seconds(timeout), [&numTaskDone, &nInstances] { return numTaskDone >= nInstances; });
            if (waitStatus == false)
            {
                LOG(error) << "Task failed: Timed out on waiting Task Done.";
                LOG(error) << "Finished tasks: " << numTaskDone << " expected: " << nInstances;
                return EXIT_FAILURE;
            }
        }

        LOG(info) << "Key value cache.\n" << map_to_string(keyValueCache);
        LOG(info) << "Task successfully done";

        chrono::high_resolution_clock::time_point t2 = chrono::high_resolution_clock::now();
        auto duration = chrono::duration_cast<chrono::seconds>(t2 - t1).count();
        LOG(info) << "Calculation time: " << duration << " seconds";
    }
    catch (exception& _e)
    {
        LOG(fatal) << "USER TASK Error: " << _e.what() << endl;
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}