|
| 1 | +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. |
| 2 | +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. |
| 3 | +// All rights not expressly granted are reserved. |
| 4 | +// |
| 5 | +// This software is distributed under the terms of the GNU General Public |
| 6 | +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". |
| 7 | +// |
| 8 | +// In applying this license CERN does not waive the privileges and immunities |
| 9 | +// granted to it by virtue of its status as an Intergovernmental Organization |
| 10 | +// or submit itself to any jurisdiction. |
| 11 | +#define BOOST_TEST_MODULE Test Framework MermaidHelpers |
| 12 | +#define BOOST_TEST_MAIN |
| 13 | +#define BOOST_TEST_DYN_LINK |
| 14 | + |
| 15 | +#include "Mocking.h" |
| 16 | +#include "../src/ComputingResourceHelpers.h" |
| 17 | +#include "../src/DeviceSpecHelpers.h" |
| 18 | +#include "../src/MermaidHelpers.h" |
| 19 | +#include "../src/SimpleResourceManager.h" |
| 20 | +#include "Framework/DeviceSpec.h" |
| 21 | +#include "Framework/WorkflowSpec.h" |
| 22 | +#include "Headers/DataHeader.h" |
| 23 | + |
| 24 | +#include <boost/test/unit_test.hpp> |
| 25 | +#include <sstream> |
| 26 | +#include <iostream> |
| 27 | + |
| 28 | +using namespace o2::framework; |
| 29 | + |
| 30 | +// because comparing the whole thing is a pain. |
| 31 | +void lineByLineComparison(const std::string& as, const std::string& bs) |
| 32 | +{ |
| 33 | + std::istringstream a(as); |
| 34 | + std::istringstream b(bs); |
| 35 | + |
| 36 | + char bufferA[1024]; |
| 37 | + char bufferB[1024]; |
| 38 | + while (a.good() && b.good()) { |
| 39 | + a.getline(bufferA, 1024); |
| 40 | + b.getline(bufferB, 1024); |
| 41 | + BOOST_CHECK_EQUAL(std::string(bufferA), std::string(bufferB)); |
| 42 | + } |
| 43 | + BOOST_CHECK(a.eof()); |
| 44 | + BOOST_CHECK(b.eof()); |
| 45 | +} |
| 46 | + |
| 47 | +// This is how you can define your processing in a declarative way |
| 48 | +WorkflowSpec defineDataProcessing() |
| 49 | +{ |
| 50 | + return {{"A", Inputs{}, |
| 51 | + Outputs{OutputSpec{"TST", "A1"}, |
| 52 | + OutputSpec{"TST", "A2"}}}, |
| 53 | + {"B", |
| 54 | + {InputSpec{"x", "TST", "A1"}}, |
| 55 | + Outputs{OutputSpec{"TST", "B1"}}}, |
| 56 | + {"C", Inputs{InputSpec{"x", "TST", "A2"}}, |
| 57 | + Outputs{OutputSpec{"TST", "C1"}}}, |
| 58 | + {"D", |
| 59 | + Inputs{InputSpec{"i1", "TST", "B1"}, |
| 60 | + InputSpec{"i2", "TST", "C1"}}, |
| 61 | + Outputs{}}}; |
| 62 | +} |
| 63 | + |
| 64 | +WorkflowSpec defineDataProcessing2() |
| 65 | +{ |
| 66 | + return { |
| 67 | + {"A", |
| 68 | + {}, |
| 69 | + { |
| 70 | + OutputSpec{"TST", "A"}, |
| 71 | + }}, |
| 72 | + timePipeline({"B", |
| 73 | + {InputSpec{"a", "TST", "A"}}, |
| 74 | + {OutputSpec{"TST", "B"}}}, |
| 75 | + 3), |
| 76 | + timePipeline({"C", |
| 77 | + {InputSpec{"b", "TST", "B"}}, |
| 78 | + {OutputSpec{"TST", "C"}}}, |
| 79 | + 2), |
| 80 | + }; |
| 81 | +} |
| 82 | + |
| 83 | +BOOST_AUTO_TEST_CASE(TestMermaid) |
| 84 | +{ |
| 85 | + auto workflow = defineDataProcessing(); |
| 86 | + std::ostringstream str; |
| 87 | + std::vector<DeviceSpec> devices; |
| 88 | + for (auto& device : devices) { |
| 89 | + BOOST_CHECK(device.id != ""); |
| 90 | + } |
| 91 | + auto configContext = makeEmptyConfigContext(); |
| 92 | + auto channelPolicies = ChannelConfigurationPolicy::createDefaultPolicies(*configContext); |
| 93 | + auto completionPolicies = CompletionPolicy::createDefaultPolicies(); |
| 94 | + auto callbacksPolicies = CallbacksPolicy::createDefaultPolicies(); |
| 95 | + std::vector<ComputingResource> resources = {ComputingResourceHelpers::getLocalhostResource()}; |
| 96 | + SimpleResourceManager rm(resources); |
| 97 | + DeviceSpecHelpers::dataProcessorSpecs2DeviceSpecs(workflow, channelPolicies, completionPolicies, callbacksPolicies, devices, rm, "workflow-id", *configContext); |
| 98 | + str.str(""); |
| 99 | + MermaidHelpers::dumpDeviceSpec2Mermaid(str, devices); |
| 100 | + lineByLineComparison(str.str(), R"EXPECTED(flowchart TD |
| 101 | + A |
| 102 | + B |
| 103 | + C |
| 104 | + D |
| 105 | + A-- 22000:from_A_to_B -->B |
| 106 | + A-- 22001:from_A_to_C -->C |
| 107 | + B-- 22002:from_B_to_D -->D |
| 108 | + C-- 22003:from_C_to_D -->D |
| 109 | +)EXPECTED"); |
| 110 | +} |
| 111 | + |
| 112 | +BOOST_AUTO_TEST_CASE(TestMermaidWithPipeline) |
| 113 | +{ |
| 114 | + auto workflow = defineDataProcessing2(); |
| 115 | + std::ostringstream str; |
| 116 | + std::vector<DeviceSpec> devices; |
| 117 | + for (auto& device : devices) { |
| 118 | + BOOST_CHECK(device.id != ""); |
| 119 | + } |
| 120 | + auto configContext = makeEmptyConfigContext(); |
| 121 | + auto channelPolicies = ChannelConfigurationPolicy::createDefaultPolicies(*configContext); |
| 122 | + auto completionPolicies = CompletionPolicy::createDefaultPolicies(); |
| 123 | + auto callbacksPolicies = CallbacksPolicy::createDefaultPolicies(); |
| 124 | + std::vector<ComputingResource> resources = {ComputingResourceHelpers::getLocalhostResource()}; |
| 125 | + SimpleResourceManager rm(resources); |
| 126 | + DeviceSpecHelpers::dataProcessorSpecs2DeviceSpecs(workflow, channelPolicies, completionPolicies, callbacksPolicies, devices, rm, "workflow-id", *configContext); |
| 127 | + str.str(""); |
| 128 | + MermaidHelpers::dumpDeviceSpec2Mermaid(str, devices); |
| 129 | + lineByLineComparison(str.str(), R"EXPECTED(flowchart TD |
| 130 | + A |
| 131 | + B_t0 |
| 132 | + B_t1 |
| 133 | + B_t2 |
| 134 | + C_t0 |
| 135 | + C_t1 |
| 136 | + A-- 22000:from_A_to_B_t0 -->B_t0 |
| 137 | + A-- 22001:from_A_to_B_t1 -->B_t1 |
| 138 | + A-- 22002:from_A_to_B_t2 -->B_t2 |
| 139 | + B_t0-- 22003:from_B_t0_to_C_t0 -->C_t0 |
| 140 | + B_t1-- 22005:from_B_t1_to_C_t0 -->C_t0 |
| 141 | + B_t2-- 22007:from_B_t2_to_C_t0 -->C_t0 |
| 142 | + B_t0-- 22004:from_B_t0_to_C_t1 -->C_t1 |
| 143 | + B_t1-- 22006:from_B_t1_to_C_t1 -->C_t1 |
| 144 | + B_t2-- 22008:from_B_t2_to_C_t1 -->C_t1 |
| 145 | +)EXPECTED"); |
| 146 | +} |
0 commit comments