LCOV - code coverage report
Current view: top level - model - MockClientData.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 79.7 % 79 63
Test Date: 2026-10-04 17:31:08 Functions: 80.0 % 10 8

            Line data    Source code
       1              : /*
       2              :  ___________________________________________
       3              : |    _     ___                        _     |
       4              : |   | |   |__ \                      | |    |
       5              : |   | |__    ) |__ _  __ _  ___ _ __ | |_   |
       6              : |   | '_ \  / // _` |/ _` |/ _ \ '_ \| __|  |  HTTP/2 AGENT FOR MOCK TESTING
       7              : |   | | | |/ /| (_| | (_| |  __/ | | | |_   |  Version 0.0.z
       8              : |   |_| |_|____\__,_|\__, |\___|_| |_|\__|  |  https://github.com/testillano/h2agent
       9              : |                     __/ |                 |
      10              : |                    |___/                  |
      11              : |___________________________________________|
      12              : 
      13              : Licensed under the MIT License <http://opensource.org/licenses/MIT>.
      14              : SPDX-License-Identifier: MIT
      15              : Copyright (c) 2021 Eduardo Ramos
      16              : 
      17              : Permission is hereby  granted, free of charge, to any  person obtaining a copy
      18              : of this software and associated  documentation files (the "Software"), to deal
      19              : in the Software  without restriction, including without  limitation the rights
      20              : to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
      21              : copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
      22              : furnished to do so, subject to the following conditions:
      23              : 
      24              : The above copyright notice and this permission notice shall be included in all
      25              : copies or substantial portions of the Software.
      26              : 
      27              : THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
      28              : IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
      29              : FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
      30              : AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
      31              : LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      32              : OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
      33              : SOFTWARE.
      34              : */
      35              : 
      36              : #include <string>
      37              : #include <algorithm>
      38              : 
      39              : #include <ert/tracing/Logger.hpp>
      40              : 
      41              : #include <MockClientData.hpp>
      42              : #include <MockClientEvent.hpp>
      43              : 
      44              : 
      45              : namespace h2agent
      46              : {
      47              : namespace model
      48              : {
      49              : 
      50          230 : void MockClientData::loadEvent(const DataKey &dataKey, const std::string &clientProvisionId, const std::string &previousState, const std::string &state, const std::chrono::microseconds &sendingTimestampUs, const std::chrono::microseconds &receptionTimestampUs, int responseStatusCode, const nghttp2::asio_http2::header_map &requestHeaders, const nghttp2::asio_http2::header_map &responseHeaders, const std::string &requestBody, DataPart &responseBodyDataPart, std::uint64_t sendSeq, std::int64_t sequence, unsigned int requestDelayMs, unsigned int timeoutMs, bool historyEnabled) {
      51              : 
      52          230 :     modifyOrInsert(dataKey.getKey(), [&](std::shared_ptr<MockEventsHistory> &entry) {
      53          230 :         if (!entry) entry = std::make_shared<MockClientEventsHistory>(dataKey);
      54          230 :         std::static_pointer_cast<MockClientEventsHistory>(entry)->loadEvent(clientProvisionId, previousState, state, sendingTimestampUs, receptionTimestampUs, responseStatusCode, requestHeaders, responseHeaders, requestBody, responseBodyDataPart, sendSeq, sequence, requestDelayMs, timeoutMs, historyEnabled);
      55          230 :     });
      56          230 : }
      57              : 
      58            0 : bool MockClientData::removeEventBySendSeq(const DataKey &dataKey, std::uint64_t sendSeq) {
      59              : 
      60            0 :     bool exists{};
      61            0 :     auto events = std::static_pointer_cast<MockClientEventsHistory>(get(dataKey.getKey(), exists));
      62            0 :     if (!exists) return false;
      63              : 
      64            0 :     bool deleted = events->removeEventBySendSeq(sendSeq);
      65              : 
      66              :     // Cleanup empty map entry:
      67            0 :     if (deleted && events->size() == 0) {
      68            0 :         bool aux{};
      69            0 :         remove(dataKey.getKey(), aux);
      70              :     }
      71              : 
      72            0 :     return deleted;
      73            0 : }
      74              : 
      75            0 : std::shared_ptr<MockEvent> MockClientData::getEventBySendSeq(const DataKey &dataKey, std::uint64_t sendSeq) {
      76              : 
      77            0 :     bool exists{};
      78            0 :     auto events = std::static_pointer_cast<MockClientEventsHistory>(get(dataKey.getKey(), exists));
      79            0 :     if (!exists) return nullptr;
      80              : 
      81            0 :     return events->getEventBySendSeq(sendSeq);
      82            0 : }
      83              : 
      84           11 : std::shared_ptr<MockEvent> MockClientData::getEventByUriStartsWith(const std::string &clientEndpointId, const std::string &requestMethod, const std::string &uriPrefix, const std::string &eventNumber) const {
      85              : 
      86              :     // Decode the requested position (1..N, or -1 for the latest):
      87           11 :     std::uint64_t uNumber{};
      88           11 :     bool reverse{};
      89           11 :     if (!h2agent::model::string2uint64andSign(eventNumber, uNumber, reverse) || uNumber == 0) {
      90            2 :         LOGDEBUG(ert::tracing::Logger::debug(ert::tracing::Logger::asString("Invalid event number '%s' for URI-prefix client event addressing", eventNumber.c_str()), ERT_FILE_LOCATION));
      91            2 :         return nullptr;
      92              :     }
      93              : 
      94              :     // Collect all events whose key matches 'clientEndpointId'+'method' exactly and whose URI starts with
      95              :     // 'uriPrefix' (literal), tagging each with its sending timestamp (always present for client events) to
      96              :     // build a single chronologically ordered set across keys:
      97              :     struct Entry {
      98              :         std::uint64_t timestampUs;
      99              :         std::shared_ptr<MockEvent> event;
     100              :     };
     101            9 :     std::vector<Entry> entries;
     102              : 
     103            9 :     forEach([&](const mock_events_key_t&, const std::shared_ptr<MockEventsHistory> &history) {
     104           18 :         const auto &key = history->getKey();
     105           27 :         if (key.getClientEndpointId() != clientEndpointId) return;
     106           16 :         if (key.getMethod() != requestMethod) return;
     107              :         // Literal 'startsWith' (no regex): the prefix is compared verbatim against the normalized URI:
     108           14 :         if (key.getUri().rfind(uriPrefix, 0) != 0) return;
     109              : 
     110            7 :         read_guard_t guard(history->getMutex());
     111           14 :         for (const auto &ev : history->getEvents()) {
     112           21 :             std::uint64_t sendTs = std::static_pointer_cast<MockClientEvent>(ev)->getJson()["sendingTimestampUs"].get<std::uint64_t>();
     113            7 :             entries.push_back({sendTs, ev});
     114              :         }
     115           14 :     });
     116              : 
     117            9 :     if (entries.empty() || uNumber > entries.size()) return nullptr;
     118              : 
     119            3 :     std::sort(entries.begin(), entries.end(), [](const Entry &a, const Entry &b) {
     120            2 :         return a.timestampUs < b.timestampUs;
     121              :     });
     122              : 
     123              :     // 'reverse' selects from the tail (most recent); otherwise from the head:
     124            3 :     return reverse ? entries[entries.size() - uNumber].event : entries[uNumber - 1].event;
     125            9 : }
     126              : 
     127            4 : std::string MockClientData::getSequence(std::uint64_t fromTimestampUs, std::uint64_t toTimestampUs, const std::string &requestMethod, const std::regex *uriRegex) const {
     128              : 
     129              :     struct Entry {
     130              :         std::uint64_t timestampUs;
     131              :         std::string direction;
     132              :         std::string method;
     133              :         std::string uri;
     134              :         std::string clientProvisionId;
     135              :     };
     136            4 :     std::vector<Entry> entries;
     137              : 
     138            4 :     forEach([&](const mock_events_key_t&, const std::shared_ptr<MockEventsHistory> &history) {
     139            6 :         const auto &key = history->getKey();
     140            6 :         const std::string &method = key.getMethod();
     141            6 :         const std::string &uri = key.getUri();
     142              : 
     143            7 :         if (!requestMethod.empty() && method != requestMethod) return;
     144            4 :         if (uriRegex && !std::regex_search(uri, *uriRegex)) return;
     145              : 
     146            3 :         read_guard_t guard(history->getMutex());
     147            6 :         for (const auto &ev : history->getEvents()) {
     148            3 :             auto clientEv = std::static_pointer_cast<MockClientEvent>(ev);
     149            6 :             const auto &json = clientEv->getJson();
     150            3 :             std::uint64_t sendTs = json["sendingTimestampUs"].get<std::uint64_t>();
     151            3 :             std::uint64_t recvTs = json.contains("receptionTimestampUs") ? json["receptionTimestampUs"].get<std::uint64_t>() : 0;
     152            3 :             std::string provId = json.contains("clientProvisionId") ? json["clientProvisionId"].get<std::string>() : "";
     153              : 
     154              :             // Send entry:
     155            3 :             if ((!fromTimestampUs || sendTs >= fromTimestampUs) && (!toTimestampUs || sendTs <= toTimestampUs)) {
     156            3 :                 entries.push_back({sendTs, "send", method, uri, provId});
     157              :             }
     158              :             // Recv entry:
     159            3 :             if (recvTs && (!fromTimestampUs || recvTs >= fromTimestampUs) && (!toTimestampUs || recvTs <= toTimestampUs)) {
     160            3 :                 entries.push_back({recvTs, "recv", method, uri, provId});
     161              :             }
     162            3 :         }
     163           21 :     });
     164              : 
     165            4 :     std::sort(entries.begin(), entries.end(), [](const Entry &a, const Entry &b) {
     166            8 :         return a.timestampUs < b.timestampUs;
     167              :     });
     168              : 
     169            4 :     nlohmann::json result = nlohmann::json::array();
     170           10 :     for (const auto &e : entries) {
     171            6 :         nlohmann::json obj;
     172            6 :         obj["direction"] = e.direction;
     173            6 :         obj["method"] = e.method;
     174            6 :         obj["uri"] = e.uri;
     175            6 :         obj["timestampUs"] = e.timestampUs;
     176            6 :         if (!e.clientProvisionId.empty()) obj["clientProvisionId"] = e.clientProvisionId;
     177            6 :         result.push_back(std::move(obj));
     178            6 :     }
     179              : 
     180            8 :     return result.dump();
     181            4 : }
     182              : 
     183              : }
     184              : }
     185              : 
        

Generated by: LCOV version 2.0-1