test_graph.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  1. /*************************************************************************
  2. * Copyright (C) [2021] by Cambricon, Inc. All rights reserved
  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. * The above copyright notice and this permission notice shall be included in
  11. * all copies or substantial portions of the Software.
  12. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  13. * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  14. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  15. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  16. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  17. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  18. * THE SOFTWARE.
  19. *************************************************************************/
  20. #include <gtest/gtest.h>
  21. #include <fstream>
  22. #include <memory>
  23. #include <string>
  24. #include <vector>
  25. #include "cnstream_graph.hpp"
  26. #include "test_base.hpp"
  27. namespace cnstream {
  28. TEST(CoreDAGAlgorithm, AddVertex) {
  29. DAGAlgorithm dag;
  30. dag.Reserve(3);
  31. for (int i = 0; i < 3; ++i)
  32. EXPECT_EQ(i, dag.AddVertex());
  33. for (int i = 0; i < 3; ++i) {
  34. EXPECT_EQ(dag.GetIndegree(i), 0);
  35. EXPECT_EQ(dag.GetOutdegree(i), 0);
  36. }
  37. }
  38. TEST(CoreDAGAlgorithm, AddEdge) {
  39. DAGAlgorithm dag;
  40. for (int i = 0; i < 3; ++i)
  41. dag.AddVertex();
  42. // case1: add success
  43. EXPECT_TRUE(dag.AddEdge(1, 2));
  44. // case2: vertex out of range
  45. EXPECT_FALSE(dag.AddEdge(0, 3));
  46. EXPECT_FALSE(dag.AddEdge(5, 1));
  47. // case3: add the same edge twice
  48. EXPECT_FALSE(dag.AddEdge(1, 2));
  49. }
  50. TEST(CoreDAGAlgorithm, GetIndegree) {
  51. DAGAlgorithm dag;
  52. for (int i = 0; i < 3; ++i)
  53. dag.AddVertex();
  54. ASSERT_TRUE(dag.AddEdge(0, 2));
  55. ASSERT_TRUE(dag.AddEdge(1, 2));
  56. // case1: success
  57. EXPECT_EQ(2, dag.GetIndegree(2));
  58. // case2: vertex out of range
  59. EXPECT_EQ(-1, dag.GetIndegree(3));
  60. }
  61. TEST(CoreDAGAlgorithm, GetOutdegree) {
  62. DAGAlgorithm dag;
  63. for (int i = 0; i < 3; ++i)
  64. dag.AddVertex();
  65. ASSERT_TRUE(dag.AddEdge(1, 2));
  66. ASSERT_TRUE(dag.AddEdge(1, 0));
  67. // case1: success
  68. EXPECT_EQ(2, dag.GetOutdegree(1));
  69. // case2: vertex out of range
  70. EXPECT_EQ(-1, dag.GetOutdegree(3));
  71. }
  72. TEST(CoreDAGAlgorithm, GetHeads) {
  73. DAGAlgorithm dag;
  74. for (int i = 0; i < 5; ++i)
  75. dag.AddVertex();
  76. ASSERT_TRUE(dag.AddEdge(0, 1));
  77. ASSERT_TRUE(dag.AddEdge(0, 2));
  78. ASSERT_TRUE(dag.AddEdge(2, 3));
  79. ASSERT_TRUE(dag.AddEdge(4, 2));
  80. EXPECT_EQ(dag.GetHeads().size(), 2);
  81. EXPECT_EQ(dag.GetHeads()[0], 0);
  82. EXPECT_EQ(dag.GetHeads()[1], 4);
  83. }
  84. TEST(CoreDAGAlgorithm, GetTails) {
  85. DAGAlgorithm dag;
  86. for (int i = 0; i < 5; ++i)
  87. dag.AddVertex();
  88. ASSERT_TRUE(dag.AddEdge(0, 1));
  89. ASSERT_TRUE(dag.AddEdge(0, 2));
  90. ASSERT_TRUE(dag.AddEdge(2, 3));
  91. ASSERT_TRUE(dag.AddEdge(4, 2));
  92. EXPECT_EQ(dag.GetTails().size(), 2);
  93. EXPECT_EQ(dag.GetTails()[0], 1);
  94. EXPECT_EQ(dag.GetTails()[1], 3);
  95. }
  96. TEST(CoreDAGAlgorithm, TopoSort) {
  97. // case1: no ring
  98. DAGAlgorithm dag;
  99. for (int i = 0; i < 5; ++i)
  100. dag.AddVertex();
  101. ASSERT_TRUE(dag.AddEdge(0, 1));
  102. ASSERT_TRUE(dag.AddEdge(0, 2));
  103. ASSERT_TRUE(dag.AddEdge(2, 3));
  104. ASSERT_TRUE(dag.AddEdge(4, 2));
  105. std::vector<int> expected_ret = {0, 1, 4, 2, 3};
  106. auto ret = dag.TopoSort();
  107. EXPECT_EQ(5, ret.first.size());
  108. EXPECT_EQ(0, ret.second.size());
  109. for (int i = 0; i < 5; ++i)
  110. EXPECT_EQ(ret.first[i], expected_ret[i]);
  111. // case2: with ring
  112. dag = DAGAlgorithm();
  113. for (int i = 0; i < 5; ++i)
  114. dag.AddVertex();
  115. ASSERT_TRUE(dag.AddEdge(0, 1));
  116. ASSERT_TRUE(dag.AddEdge(0, 2));
  117. ASSERT_TRUE(dag.AddEdge(2, 3));
  118. ASSERT_TRUE(dag.AddEdge(4, 2));
  119. ASSERT_TRUE(dag.AddEdge(3, 4));
  120. std::vector<int> expected_sorted = {0, 1};
  121. std::vector<int> expected_unsorted = {2, 3, 4};
  122. ret = dag.TopoSort();
  123. EXPECT_EQ(2, ret.first.size());
  124. EXPECT_EQ(3, ret.second.size());
  125. for (int i = 0; i < 2; ++i)
  126. EXPECT_EQ(ret.first[i], expected_sorted[i]);
  127. for (int i = 0; i < 3; ++i)
  128. EXPECT_EQ(ret.second[i], expected_unsorted[i]);
  129. }
  130. TEST(CoreDAGAlgorithm, DFSBegin) {
  131. DAGAlgorithm dag;
  132. for (int i = 0; i < 3; ++i)
  133. dag.AddVertex();
  134. ASSERT_TRUE(dag.AddEdge(1, 2));
  135. ASSERT_TRUE(dag.AddEdge(2, 0));
  136. EXPECT_EQ(*dag.DFSBegin(), 1);
  137. }
  138. TEST(CoreDAGAlgorithm, DFSBeginFrom) {
  139. DAGAlgorithm dag;
  140. for (int i = 0; i < 3; ++i)
  141. dag.AddVertex();
  142. ASSERT_TRUE(dag.AddEdge(1, 2));
  143. ASSERT_TRUE(dag.AddEdge(2, 0));
  144. // case1: right
  145. EXPECT_EQ(*dag.DFSBeginFrom(2), 2);
  146. // case2: vertex out of range
  147. EXPECT_EQ(dag.DFSBeginFrom(3), dag.DFSEnd());
  148. }
  149. TEST(CoreDAGAlgorithm, DFSEnd) {
  150. DAGAlgorithm dag;
  151. for (int i = 0; i < 3; ++i)
  152. dag.AddVertex();
  153. EXPECT_EQ(-1, *dag.DFSEnd());
  154. }
  155. TEST(CoreDAGAlgorithm, DFSOrder) {
  156. DAGAlgorithm dag;
  157. for (int i = 0; i < 5; ++i)
  158. dag.AddVertex();
  159. ASSERT_TRUE(dag.AddEdge(0, 1));
  160. ASSERT_TRUE(dag.AddEdge(0, 2));
  161. ASSERT_TRUE(dag.AddEdge(2, 3));
  162. ASSERT_TRUE(dag.AddEdge(4, 2));
  163. // based on multiple heads
  164. // case1: begin
  165. std::vector<int> expected_order = {4, 2, 3, 0, 1};
  166. auto iter = dag.DFSBegin();
  167. for (int i = 0; i < 5; ++i, ++iter)
  168. EXPECT_EQ(expected_order[i], *iter);
  169. // case2: begin from vertex
  170. expected_order = {0, 1, 2, 3};
  171. iter = dag.DFSBeginFrom(0);
  172. for (int i = 0; i < 4; ++i, ++iter)
  173. EXPECT_EQ(expected_order[i], *iter);
  174. expected_order = {4, 2};
  175. iter = dag.DFSBeginFrom(4);
  176. for (int i = 0; i < 2; ++i, ++iter)
  177. EXPECT_EQ(expected_order[i], *iter);
  178. }
  179. TEST(CoreDAGAlgorithm, DFSIterNE) {
  180. DAGAlgorithm dag;
  181. for (int i = 0; i < 5; ++i)
  182. dag.AddVertex();
  183. ASSERT_TRUE(dag.AddEdge(0, 1));
  184. ASSERT_TRUE(dag.AddEdge(0, 2));
  185. ASSERT_TRUE(dag.AddEdge(2, 3));
  186. ASSERT_TRUE(dag.AddEdge(4, 2));
  187. // case: multiple heads, stack size not the same, stack top is the same
  188. auto iter1 = dag.DFSBegin();
  189. auto iter2 = dag.DFSBeginFrom(4);
  190. EXPECT_NE(iter1, iter2);
  191. }
  192. TEST(CoreCNGraph, InitNormalSimpleGraph) {
  193. // no subgraph, no ring
  194. /**
  195. * two source
  196. * 0 7
  197. * / \ /
  198. * 1 2
  199. * / / \
  200. * 3 4 5
  201. * \ /
  202. * \ /
  203. * 6
  204. **/
  205. CNGraphConfig graph_config;
  206. graph_config.name = "test_graph";
  207. CNModuleConfig config0;
  208. config0.name = "0";
  209. config0.next = {"1", "2"};
  210. graph_config.module_configs.push_back(config0);
  211. CNModuleConfig config1;
  212. config1.name = "1";
  213. config1.next = {"3"};
  214. graph_config.module_configs.push_back(config1);
  215. CNModuleConfig config2;
  216. config2.name = "2";
  217. config2.next = {"4", "5"};
  218. graph_config.module_configs.push_back(config2);
  219. CNModuleConfig config3;
  220. config3.name = "3";
  221. config3.next = {"6"};
  222. graph_config.module_configs.push_back(config3);
  223. CNModuleConfig config4;
  224. config4.name = "4";
  225. config4.next = {};
  226. graph_config.module_configs.push_back(config4);
  227. CNModuleConfig config5;
  228. config5.name = "5";
  229. config5.next = {"6"};
  230. graph_config.module_configs.push_back(config5);
  231. CNModuleConfig config6;
  232. config6.name = "6";
  233. config6.next = {};
  234. graph_config.module_configs.push_back(config6);
  235. CNModuleConfig config7;
  236. config7.name = "7";
  237. config7.next = {"2"};
  238. graph_config.module_configs.push_back(config7);
  239. CNGraph<int> graph(graph_config);
  240. EXPECT_TRUE(graph.Init());
  241. // check heads
  242. std::vector<std::string> expected_head_names = {"0", "7"};
  243. EXPECT_EQ(2, graph.GetHeads().size());
  244. for (int i = 0; i < 2; ++i)
  245. EXPECT_EQ(expected_head_names[i], graph.GetHeads()[i]->GetName());
  246. // check tails
  247. std::vector<std::string> expected_tail_names = {"4", "6"};
  248. EXPECT_EQ(2, graph.GetTails().size());
  249. for (int i = 0; i < 2; ++i)
  250. EXPECT_EQ(expected_tail_names[i], graph.GetTails()[i]->GetName());
  251. // check dfs order
  252. std::vector<std::string> expected_dfs_order = {"7", "2", "4", "5", "6", "0", "1", "3"};
  253. auto iter = graph.DFSBegin();
  254. for (size_t i = 0; i < expected_dfs_order.size(); ++i, ++iter) {
  255. EXPECT_NE(iter, graph.DFSEnd());
  256. EXPECT_EQ(iter->GetName(), expected_dfs_order[i]);
  257. }
  258. }
  259. TEST(CoreCNGraph, InitGraphWithRing) {
  260. // no subgraph, has ring
  261. /**
  262. * 0 7
  263. * / \ /|\ ring: 7->2->5->7
  264. * 1 2 |
  265. * / / \|
  266. * 3 4 5
  267. * \ /
  268. * \ /
  269. * 6
  270. **/
  271. CNGraphConfig graph_config;
  272. graph_config.name = "test_graph";
  273. CNModuleConfig config0;
  274. config0.name = "0";
  275. config0.next = {"1", "2"};
  276. graph_config.module_configs.push_back(config0);
  277. CNModuleConfig config1;
  278. config1.name = "1";
  279. config1.next = {"3"};
  280. graph_config.module_configs.push_back(config1);
  281. CNModuleConfig config2;
  282. config2.name = "2";
  283. config2.next = {"4", "5"};
  284. graph_config.module_configs.push_back(config2);
  285. CNModuleConfig config3;
  286. config3.name = "3";
  287. config3.next = {"6"};
  288. graph_config.module_configs.push_back(config3);
  289. CNModuleConfig config4;
  290. config4.name = "4";
  291. config4.next = {};
  292. graph_config.module_configs.push_back(config4);
  293. CNModuleConfig config5;
  294. config5.name = "5";
  295. config5.next = {"6", "7"};
  296. graph_config.module_configs.push_back(config5);
  297. CNModuleConfig config6;
  298. config6.name = "6";
  299. config6.next = {};
  300. graph_config.module_configs.push_back(config6);
  301. CNModuleConfig config7;
  302. config7.name = "7";
  303. config7.next = {"2"};
  304. graph_config.module_configs.push_back(config7);
  305. CNGraph<int> graph(graph_config);
  306. EXPECT_FALSE(graph.Init());
  307. }
  308. TEST(CoreCNGraph, InitWithSubgraph) {
  309. /**
  310. * // 1 is subgraph1, the same with parent graph, node named 1 is not subgraph, 2 is the same with subgraph2
  311. * // 2 is subgraph2: 0->1, 0->2, 1->3
  312. * 0
  313. * / \
  314. * 1 2
  315. * /
  316. * 3
  317. **/
  318. auto subgraph1_config_file = CreateTempFile("subgraph1");
  319. auto subgraph2_config_file = CreateTempFile("subgraph2");
  320. std::ofstream ofs_subgraph1(subgraph1_config_file.second);
  321. ofs_subgraph1 << "{\n"
  322. "\"0\" : {\n"
  323. " \"class_name\" : \"test\",\n"
  324. " \"next_modules\" : [\"1\", \"subgraph:2\"]\n"
  325. "},\n"
  326. "\"1\" : {\n"
  327. " \"class_name\" : \"test\",\n"
  328. " \"next_modules\" : [\"3\"]\n"
  329. "},\n"
  330. "\"subgraph:2\" : {\n"
  331. " \"config_path\" : \"" + subgraph2_config_file.second + "\"\n" +
  332. "},\n"
  333. "\"3\" : {\n"
  334. " \"class_name\" : \"test\"\n"
  335. "}\n"
  336. "}\n";
  337. ofs_subgraph1.close();
  338. std::ofstream ofs_subgraph2(subgraph2_config_file.second);
  339. ofs_subgraph2 << "{\n"
  340. "\"0\" : {\n"
  341. " \"class_name\" : \"test\",\n"
  342. " \"next_modules\" : [\"1\", \"2\"]\n"
  343. "},\n"
  344. "\"1\" : {\n"
  345. " \"class_name\" : \"test\",\n"
  346. " \"next_modules\" : [\"3\"]\n"
  347. "},\n"
  348. "\"2\" : {\n"
  349. " \"class_name\" : \"test\"\n"
  350. "},\n"
  351. "\"3\" : {\n"
  352. " \"class_name\" : \"test\"\n"
  353. "}\n"
  354. "}\n";
  355. ofs_subgraph2.close();
  356. CNGraphConfig graph_config;
  357. graph_config.name = "test_graph";
  358. CNModuleConfig config0;
  359. config0.name = "0";
  360. config0.next = {"subgraph:1", "subgraph:2"};
  361. graph_config.module_configs.push_back(config0);
  362. CNSubgraphConfig config1;
  363. config1.name = "subgraph:1";
  364. config1.config_path = subgraph1_config_file.second;
  365. config1.next = {"3"};
  366. graph_config.subgraph_configs.push_back(config1);
  367. CNSubgraphConfig config2;
  368. config2.name = "subgraph:2";
  369. config2.config_path = subgraph2_config_file.second;
  370. graph_config.subgraph_configs.push_back(config2);
  371. CNModuleConfig config3;
  372. config3.name = "3";
  373. graph_config.module_configs.push_back(config3);
  374. CNGraph<int> graph(graph_config);
  375. EXPECT_TRUE(graph.Init());
  376. // check heads
  377. std::vector<std::string> expected_head_names = {"test_graph/0"};
  378. EXPECT_EQ(1, graph.GetHeads().size());
  379. for (int i = 0; i < 1; ++i)
  380. EXPECT_EQ(expected_head_names[i], graph.GetHeads()[i]->GetFullName());
  381. // check tails
  382. std::vector<std::string> expected_tail_names = {"test_graph/3", "test_graph/2/2", "test_graph/2/3"};
  383. EXPECT_EQ(3, graph.GetTails().size());
  384. for (int i = 0; i < 3; ++i)
  385. EXPECT_EQ(expected_tail_names[i], graph.GetTails()[i]->GetFullName());
  386. // check dfs order
  387. std::vector<std::string> expected_dfs_order = {"test_graph/0", "test_graph/1/0", "test_graph/1/1",
  388. "test_graph/1/3", "test_graph/1/2/0", "test_graph/1/2/1", "test_graph/1/2/3", "test_graph/1/2/2",
  389. "test_graph/3", "test_graph/2/0", "test_graph/2/1", "test_graph/2/3", "test_graph/2/2"};
  390. auto iter = graph.DFSBegin();
  391. for (size_t i = 0; i < expected_dfs_order.size(); ++i, ++iter) {
  392. EXPECT_NE(iter, graph.DFSEnd());
  393. EXPECT_EQ(iter->GetFullName(), expected_dfs_order[i]);
  394. }
  395. // check GetNodeByName, no subgraph prefix, the first node named 2 by dfs order
  396. EXPECT_EQ(graph.GetNodeByName("2")->GetFullName(), "test_graph/1/2/2");
  397. EXPECT_EQ(graph.GetNodeByName("6").get(), nullptr);
  398. // check GetNodeByName, with subgraph prefix
  399. EXPECT_EQ(graph.GetNodeByName("test_graph/2/1")->GetFullName(), "test_graph/2/1");
  400. EXPECT_EQ(graph.GetNodeByName("test_graph/2/5").get(), nullptr);
  401. // check GetNodeByName, with subgraph prefix, but miss subgraph
  402. EXPECT_EQ(graph.GetNodeByName("test_graph/7/0").get(), nullptr);
  403. unlink(subgraph1_config_file.second.c_str());
  404. close(subgraph1_config_file.first);
  405. unlink(subgraph2_config_file.second.c_str());
  406. close(subgraph2_config_file.first);
  407. }
  408. TEST(CoreCNGraph, InitWithSubgraphAnalysisLoopConfig) {
  409. auto subgraph1_config_file = CreateTempFile("subgraph1");
  410. std::ofstream ofs_subgraph1(subgraph1_config_file.second);
  411. ofs_subgraph1 << "{\n"
  412. "\"0\" : {\n"
  413. " \"class_name\" : \"test\",\n"
  414. " \"next_modules\" : [\"1\", \"subgraph:2\"]\n"
  415. "},\n"
  416. "\"1\" : {\n"
  417. " \"class_name\" : \"test\",\n"
  418. " \"next_modules\" : [\"3\"]\n"
  419. "},\n"
  420. "\"subgraph:2\" : {\n"
  421. " \"config_path\" : \"" + subgraph1_config_file.second + "\"\n" + // ring
  422. "},\n"
  423. "\"3\" : {\n"
  424. " \"class_name\" : \"test\"\n"
  425. "}\n"
  426. "}\n";
  427. ofs_subgraph1.close();
  428. CNGraphConfig graph_config;
  429. graph_config.name = "test_graph";
  430. CNSubgraphConfig config0;
  431. config0.name = "subgraph:0";
  432. config0.config_path = subgraph1_config_file.second;
  433. graph_config.subgraph_configs.push_back(config0);
  434. CNGraph<int> graph;
  435. EXPECT_FALSE(graph.Init(graph_config));
  436. unlink(subgraph1_config_file.second.c_str());
  437. close(subgraph1_config_file.first);
  438. }
  439. TEST(CoreCNGraph, SubgraphParseFailed) {
  440. CNGraphConfig graph_config;
  441. graph_config.name = "test_graph";
  442. CNSubgraphConfig config0;
  443. config0.name = "subgraph:0";
  444. config0.config_path = "wrong_path";
  445. graph_config.subgraph_configs.push_back(config0);
  446. CNGraph<int> graph;
  447. EXPECT_FALSE(graph.Init(graph_config));
  448. }
  449. TEST(CoreCNGraph, ModuleNodeNameInvalid) {
  450. CNGraphConfig graph_config;
  451. graph_config.name = "test_graph";
  452. CNModuleConfig config0;
  453. config0.name = "0:0"; // : is not allow
  454. graph_config.module_configs.push_back(config0);
  455. CNGraph<int> graph;
  456. EXPECT_FALSE(graph.Init(graph_config));
  457. graph_config.module_configs[0].name = "0/0"; // / is not allow
  458. EXPECT_FALSE(graph.Init(graph_config));
  459. }
  460. TEST(CoreCNGraph, SubgraphNodeNameInvalid) {
  461. CNGraphConfig graph_config;
  462. graph_config.name = "test_graph";
  463. CNSubgraphConfig config0;
  464. config0.name = "subgraph:0:0"; // : is not allow
  465. graph_config.subgraph_configs.push_back(config0);
  466. CNGraph<int> graph;
  467. EXPECT_FALSE(graph.Init(graph_config));
  468. graph_config.subgraph_configs[0].name = "subgraph:0/0"; // / is not allow
  469. EXPECT_FALSE(graph.Init(graph_config));
  470. }
  471. TEST(CoreCNGraph, WrongEdge) {
  472. {
  473. CNGraphConfig graph_config;
  474. graph_config.name = "test_graph";
  475. // module->module
  476. CNModuleConfig config0;
  477. config0.name = "0";
  478. config0.next = {"1"};
  479. graph_config.module_configs.push_back(config0);
  480. CNGraph<int> graph;
  481. EXPECT_FALSE(graph.Init(graph_config));
  482. // module->subgraph
  483. graph_config.module_configs[0].next = {"subgraph:1"};
  484. EXPECT_FALSE(graph.Init(graph_config));
  485. }
  486. {
  487. CNGraphConfig graph_config;
  488. graph_config.name = "test_graph";
  489. auto subgraph_config_file = CreateTempFile("subgraph_empty");
  490. std::ofstream ofs(subgraph_config_file.second);
  491. ofs << "{}";
  492. ofs.close();
  493. // subgraph->module
  494. CNSubgraphConfig config0;
  495. config0.name = "subgraph:0";
  496. config0.next = {"1"};
  497. config0.config_path = subgraph_config_file.second;
  498. graph_config.subgraph_configs.push_back(config0);
  499. CNGraph<int> graph;
  500. EXPECT_FALSE(graph.Init(graph_config));
  501. // subgraph->subgraph
  502. graph_config.subgraph_configs[0].next = {"subgraph:1"};
  503. EXPECT_FALSE(graph.Init(graph_config));
  504. unlink(subgraph_config_file.second.c_str());
  505. close(subgraph_config_file.first);
  506. }
  507. }
  508. } // namespace cnstream