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