1*51c0b2f7Stbbdev /* 2*51c0b2f7Stbbdev Copyright (c) 2020 Intel Corporation 3*51c0b2f7Stbbdev 4*51c0b2f7Stbbdev Licensed under the Apache License, Version 2.0 (the "License"); 5*51c0b2f7Stbbdev you may not use this file except in compliance with the License. 6*51c0b2f7Stbbdev You may obtain a copy of the License at 7*51c0b2f7Stbbdev 8*51c0b2f7Stbbdev http://www.apache.org/licenses/LICENSE-2.0 9*51c0b2f7Stbbdev 10*51c0b2f7Stbbdev Unless required by applicable law or agreed to in writing, software 11*51c0b2f7Stbbdev distributed under the License is distributed on an "AS IS" BASIS, 12*51c0b2f7Stbbdev WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*51c0b2f7Stbbdev See the License for the specific language governing permissions and 14*51c0b2f7Stbbdev limitations under the License. 15*51c0b2f7Stbbdev */ 16*51c0b2f7Stbbdev 17*51c0b2f7Stbbdev 18*51c0b2f7Stbbdev #include "common/test.h" 19*51c0b2f7Stbbdev 20*51c0b2f7Stbbdev #include "common/utils.h" 21*51c0b2f7Stbbdev #include "common/graph_utils.h" 22*51c0b2f7Stbbdev 23*51c0b2f7Stbbdev #include "tbb/flow_graph.h" 24*51c0b2f7Stbbdev #include "tbb/task_arena.h" 25*51c0b2f7Stbbdev #include "tbb/global_control.h" 26*51c0b2f7Stbbdev 27*51c0b2f7Stbbdev #include "conformance_flowgraph.h" 28*51c0b2f7Stbbdev 29*51c0b2f7Stbbdev //! \file conformance_join_node.cpp 30*51c0b2f7Stbbdev //! \brief Test for [flow_graph.join_node] specification 31*51c0b2f7Stbbdev 32*51c0b2f7Stbbdev /* 33*51c0b2f7Stbbdev TODO: implement missing conformance tests for join_node: 34*51c0b2f7Stbbdev - [ ] Check that `OutputTuple' is an instantiation of a tuple. 35*51c0b2f7Stbbdev - [ ] The copy constructor and copy assignment are called for each type within the `OutputTuple'. 36*51c0b2f7Stbbdev - [ ] Check all possible policies of the node: `reserving', `key_matching', `queueing', 37*51c0b2f7Stbbdev `tag_matching'. Check the semantics the node has with each policy separately. 38*51c0b2f7Stbbdev - [ ] Check that corresponding methods are invoked in specified `KHash' type. 39*51c0b2f7Stbbdev - [ ] Improve test for constructors, including their availability based on used Policy for the 40*51c0b2f7Stbbdev node. 41*51c0b2f7Stbbdev - [ ] Unify code style in the test by extracting the implementation from the `TEST_CASE' scope 42*51c0b2f7Stbbdev into separate functions. 43*51c0b2f7Stbbdev - [ ] Check that corresponding methods mentioned in the requirements are called for `Bi' types. 44*51c0b2f7Stbbdev - [ ] Explicitly check that `input_ports_type' is defined, accessible and is a tuple of 45*51c0b2f7Stbbdev corresponding to `OutputTuple' receivers. 46*51c0b2f7Stbbdev - [ ] Explicitly check the method `join_node::input_ports()' exists, is accessible and it returns 47*51c0b2f7Stbbdev a reference to the `input_ports_type' type. 48*51c0b2f7Stbbdev - [ ] Implement `test_buffering' (for node policy). 49*51c0b2f7Stbbdev - [ ] Check `try_get()' copies the generated tuple into passed argument and returns `true'. If 50*51c0b2f7Stbbdev node is empty returns `false'. 51*51c0b2f7Stbbdev - [ ] Check `tag_value' is defined and has properties specified. 52*51c0b2f7Stbbdev - [ ] Add test for CTAD. 53*51c0b2f7Stbbdev */ 54*51c0b2f7Stbbdev 55*51c0b2f7Stbbdev using namespace tbb::flow; 56*51c0b2f7Stbbdev using namespace std; 57*51c0b2f7Stbbdev 58*51c0b2f7Stbbdev template<typename T> 59*51c0b2f7Stbbdev void test_inheritance(){ 60*51c0b2f7Stbbdev CHECK_MESSAGE( (std::is_base_of<graph_node, join_node<std::tuple<T, T>>>::value), "join_node should be derived from graph_node"); 61*51c0b2f7Stbbdev CHECK_MESSAGE( (std::is_base_of<sender<std::tuple<T, T>>, join_node<std::tuple<T, T>>>::value), "join_node should be derived from graph_node"); 62*51c0b2f7Stbbdev } 63*51c0b2f7Stbbdev 64*51c0b2f7Stbbdev void test_copies(){ 65*51c0b2f7Stbbdev using namespace tbb::flow; 66*51c0b2f7Stbbdev 67*51c0b2f7Stbbdev graph g; 68*51c0b2f7Stbbdev join_node<std::tuple<int, int>> n(g); 69*51c0b2f7Stbbdev join_node<std::tuple<int, int>> n2(n); 70*51c0b2f7Stbbdev 71*51c0b2f7Stbbdev join_node <std::tuple<int, int, tbb::flow::reserving>> nr(g); 72*51c0b2f7Stbbdev join_node <std::tuple<int, int, tbb::flow::reserving>> nr2(nr); 73*51c0b2f7Stbbdev } 74*51c0b2f7Stbbdev 75*51c0b2f7Stbbdev void test_forwarding(){ 76*51c0b2f7Stbbdev tbb::flow::graph g; 77*51c0b2f7Stbbdev 78*51c0b2f7Stbbdev join_node<std::tuple<int, int>> node1(g); 79*51c0b2f7Stbbdev 80*51c0b2f7Stbbdev using output_t = join_node<std::tuple<int, int>>::output_type; 81*51c0b2f7Stbbdev 82*51c0b2f7Stbbdev test_push_receiver<output_t> node2(g); 83*51c0b2f7Stbbdev test_push_receiver<output_t> node3(g); 84*51c0b2f7Stbbdev 85*51c0b2f7Stbbdev tbb::flow::make_edge(node1, node2); 86*51c0b2f7Stbbdev tbb::flow::make_edge(node1, node3); 87*51c0b2f7Stbbdev 88*51c0b2f7Stbbdev input_port<0>(node1).try_put(1); 89*51c0b2f7Stbbdev input_port<1>(node1).try_put(1); 90*51c0b2f7Stbbdev 91*51c0b2f7Stbbdev g.wait_for_all(); 92*51c0b2f7Stbbdev 93*51c0b2f7Stbbdev CHECK_MESSAGE( (get_count(node2) == 1), "Descendant of the node needs to be receive N messages"); 94*51c0b2f7Stbbdev CHECK_MESSAGE( (get_count(node3) == 1), "Descendant of the node must receive one message."); 95*51c0b2f7Stbbdev } 96*51c0b2f7Stbbdev 97*51c0b2f7Stbbdev //! Test broadcast 98*51c0b2f7Stbbdev //! \brief \ref interface 99*51c0b2f7Stbbdev TEST_CASE("join_node broadcast") { 100*51c0b2f7Stbbdev test_forwarding(); 101*51c0b2f7Stbbdev } 102*51c0b2f7Stbbdev 103*51c0b2f7Stbbdev 104*51c0b2f7Stbbdev //! Test copy constructor 105*51c0b2f7Stbbdev //! \brief \ref interface 106*51c0b2f7Stbbdev TEST_CASE("join_node copy constructor") { 107*51c0b2f7Stbbdev test_copies(); 108*51c0b2f7Stbbdev } 109*51c0b2f7Stbbdev 110*51c0b2f7Stbbdev //! Test inheritance relations 111*51c0b2f7Stbbdev //! \brief \ref interface 112*51c0b2f7Stbbdev TEST_CASE("join_node inheritance"){ 113*51c0b2f7Stbbdev test_inheritance<int>(); 114*51c0b2f7Stbbdev } 115*51c0b2f7Stbbdev 116*51c0b2f7Stbbdev //! Test join_node behavior 117*51c0b2f7Stbbdev //! \brief \ref requirement 118*51c0b2f7Stbbdev TEST_CASE("join_node") { 119*51c0b2f7Stbbdev graph g; 120*51c0b2f7Stbbdev function_node<int,int> 121*51c0b2f7Stbbdev f1( g, unlimited, [](const int &i) { return 2*i; } ); 122*51c0b2f7Stbbdev function_node<float,float> 123*51c0b2f7Stbbdev f2( g, unlimited, [](const float &f) { return f/2; } ); 124*51c0b2f7Stbbdev 125*51c0b2f7Stbbdev join_node< std::tuple<int,float> > j(g); 126*51c0b2f7Stbbdev 127*51c0b2f7Stbbdev function_node< std::tuple<int,float> > 128*51c0b2f7Stbbdev f3( g, unlimited, 129*51c0b2f7Stbbdev []( const std::tuple<int,float> &t ) { 130*51c0b2f7Stbbdev CHECK_MESSAGE( (std::get<0>(t) == 6), "Expected to receive 6" ); 131*51c0b2f7Stbbdev CHECK_MESSAGE( (std::get<1>(t) == 1.5), "Expected to receive 1.5" ); 132*51c0b2f7Stbbdev } ); 133*51c0b2f7Stbbdev 134*51c0b2f7Stbbdev make_edge( f1, input_port<0>( j ) ); 135*51c0b2f7Stbbdev make_edge( f2, input_port<1>( j ) ); 136*51c0b2f7Stbbdev make_edge( j, f3 ); 137*51c0b2f7Stbbdev 138*51c0b2f7Stbbdev f1.try_put( 3 ); 139*51c0b2f7Stbbdev f2.try_put( 3 ); 140*51c0b2f7Stbbdev g.wait_for_all( ); 141*51c0b2f7Stbbdev } 142*51c0b2f7Stbbdev 143*51c0b2f7Stbbdev //! Test join_node key matching behavior 144*51c0b2f7Stbbdev //! \brief \ref requirement 145*51c0b2f7Stbbdev TEST_CASE("remove edge to join_node"){ 146*51c0b2f7Stbbdev graph g; 147*51c0b2f7Stbbdev continue_node<int> c(g, [](const continue_msg&){ return 1; }); 148*51c0b2f7Stbbdev join_node<tuple<int> > jn(g); 149*51c0b2f7Stbbdev queue_node<tuple<int> > q(g); 150*51c0b2f7Stbbdev 151*51c0b2f7Stbbdev make_edge(jn, q); 152*51c0b2f7Stbbdev 153*51c0b2f7Stbbdev make_edge(c, jn); 154*51c0b2f7Stbbdev 155*51c0b2f7Stbbdev c.try_put(continue_msg()); 156*51c0b2f7Stbbdev g.wait_for_all(); 157*51c0b2f7Stbbdev 158*51c0b2f7Stbbdev tuple<int> tmp = tuple<int>(0); 159*51c0b2f7Stbbdev CHECK_MESSAGE( (q.try_get(tmp)== true), "Message should pass when edge exists"); 160*51c0b2f7Stbbdev CHECK_MESSAGE( (tmp == tuple<int>(1) ), "Message should pass when edge exists"); 161*51c0b2f7Stbbdev CHECK_MESSAGE( (q.try_get(tmp)== false), "Message should not pass after item is consumed"); 162*51c0b2f7Stbbdev 163*51c0b2f7Stbbdev remove_edge(c, jn); 164*51c0b2f7Stbbdev 165*51c0b2f7Stbbdev c.try_put(continue_msg()); 166*51c0b2f7Stbbdev g.wait_for_all(); 167*51c0b2f7Stbbdev 168*51c0b2f7Stbbdev tmp = tuple<int>(0); 169*51c0b2f7Stbbdev CHECK_MESSAGE( (q.try_get(tmp)== false), "Message should not pass when edge doesn't exist"); 170*51c0b2f7Stbbdev CHECK_MESSAGE( (tmp == tuple<int>(0)), "Value should not be altered"); 171*51c0b2f7Stbbdev } 172*51c0b2f7Stbbdev 173*51c0b2f7Stbbdev //! Test join_node key matching behavior 174*51c0b2f7Stbbdev //! \brief \ref requirement 175*51c0b2f7Stbbdev TEST_CASE("join_node key_matching"){ 176*51c0b2f7Stbbdev graph g; 177*51c0b2f7Stbbdev auto body1 = [](const continue_msg &) -> int { return 1; }; 178*51c0b2f7Stbbdev auto body2 = [](const double &val) -> int { return int(val); }; 179*51c0b2f7Stbbdev 180*51c0b2f7Stbbdev join_node<std::tuple<continue_msg, double>, key_matching<int>> jn(g, body1, body2); 181*51c0b2f7Stbbdev 182*51c0b2f7Stbbdev input_port<0>(jn).try_put(continue_msg()); 183*51c0b2f7Stbbdev input_port<1>(jn).try_put(1.3); 184*51c0b2f7Stbbdev 185*51c0b2f7Stbbdev g.wait_for_all( ); 186*51c0b2f7Stbbdev 187*51c0b2f7Stbbdev tuple<continue_msg, double> tmp; 188*51c0b2f7Stbbdev CHECK_MESSAGE( (jn.try_get(tmp) == true), "Mapped keys should match"); 189*51c0b2f7Stbbdev } 190