test_state.py 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949
  1. # -*- coding: utf-8 -*-
  2. """
  3. Unit Tests for functions located in salt.utils.state.py.
  4. """
  5. # Import python libs
  6. from __future__ import absolute_import, print_function, unicode_literals
  7. import copy
  8. import textwrap
  9. import salt.utils.odict
  10. import salt.utils.state
  11. # Import Salt libs
  12. from salt.ext import six
  13. # Import Salt Testing libs
  14. from tests.support.unit import TestCase
  15. class StateUtilTestCase(TestCase):
  16. """
  17. Test case for state util.
  18. """
  19. def test_check_result(self):
  20. self.assertFalse(
  21. salt.utils.state.check_result(None),
  22. "Failed to handle None as an invalid data type.",
  23. )
  24. self.assertFalse(
  25. salt.utils.state.check_result([]), "Failed to handle an invalid data type."
  26. )
  27. self.assertFalse(
  28. salt.utils.state.check_result({}), "Failed to handle an empty dictionary."
  29. )
  30. self.assertFalse(
  31. salt.utils.state.check_result({"host1": []}),
  32. "Failed to handle an invalid host data structure.",
  33. )
  34. test_valid_state = {"host1": {"test_state": {"result": "We have liftoff!"}}}
  35. self.assertTrue(salt.utils.state.check_result(test_valid_state))
  36. test_valid_false_states = {
  37. "test1": salt.utils.odict.OrderedDict(
  38. [
  39. (
  40. "host1",
  41. salt.utils.odict.OrderedDict(
  42. [
  43. ("test_state0", {"result": True}),
  44. ("test_state", {"result": False}),
  45. ]
  46. ),
  47. ),
  48. ]
  49. ),
  50. "test2": salt.utils.odict.OrderedDict(
  51. [
  52. (
  53. "host1",
  54. salt.utils.odict.OrderedDict(
  55. [
  56. ("test_state0", {"result": True}),
  57. ("test_state", {"result": True}),
  58. ]
  59. ),
  60. ),
  61. (
  62. "host2",
  63. salt.utils.odict.OrderedDict(
  64. [
  65. ("test_state0", {"result": True}),
  66. ("test_state", {"result": False}),
  67. ]
  68. ),
  69. ),
  70. ]
  71. ),
  72. "test3": ["a"],
  73. "test4": salt.utils.odict.OrderedDict(
  74. [
  75. (
  76. "asup",
  77. salt.utils.odict.OrderedDict(
  78. [
  79. (
  80. "host1",
  81. salt.utils.odict.OrderedDict(
  82. [
  83. ("test_state0", {"result": True}),
  84. ("test_state", {"result": True}),
  85. ]
  86. ),
  87. ),
  88. (
  89. "host2",
  90. salt.utils.odict.OrderedDict(
  91. [
  92. ("test_state0", {"result": True}),
  93. ("test_state", {"result": False}),
  94. ]
  95. ),
  96. ),
  97. ]
  98. ),
  99. )
  100. ]
  101. ),
  102. "test5": salt.utils.odict.OrderedDict(
  103. [
  104. (
  105. "asup",
  106. salt.utils.odict.OrderedDict(
  107. [
  108. (
  109. "host1",
  110. salt.utils.odict.OrderedDict(
  111. [
  112. ("test_state0", {"result": True}),
  113. ("test_state", {"result": True}),
  114. ]
  115. ),
  116. ),
  117. ("host2", salt.utils.odict.OrderedDict([])),
  118. ]
  119. ),
  120. )
  121. ]
  122. ),
  123. }
  124. for test, data in six.iteritems(test_valid_false_states):
  125. self.assertFalse(
  126. salt.utils.state.check_result(data), msg="{0} failed".format(test)
  127. )
  128. test_valid_true_states = {
  129. "test1": salt.utils.odict.OrderedDict(
  130. [
  131. (
  132. "host1",
  133. salt.utils.odict.OrderedDict(
  134. [
  135. ("test_state0", {"result": True}),
  136. ("test_state", {"result": True}),
  137. ]
  138. ),
  139. ),
  140. ]
  141. ),
  142. "test3": salt.utils.odict.OrderedDict(
  143. [
  144. (
  145. "host1",
  146. salt.utils.odict.OrderedDict(
  147. [
  148. ("test_state0", {"result": True}),
  149. ("test_state", {"result": True}),
  150. ]
  151. ),
  152. ),
  153. (
  154. "host2",
  155. salt.utils.odict.OrderedDict(
  156. [
  157. ("test_state0", {"result": True}),
  158. ("test_state", {"result": True}),
  159. ]
  160. ),
  161. ),
  162. ]
  163. ),
  164. "test4": salt.utils.odict.OrderedDict(
  165. [
  166. (
  167. "asup",
  168. salt.utils.odict.OrderedDict(
  169. [
  170. (
  171. "host1",
  172. salt.utils.odict.OrderedDict(
  173. [
  174. ("test_state0", {"result": True}),
  175. ("test_state", {"result": True}),
  176. ]
  177. ),
  178. ),
  179. (
  180. "host2",
  181. salt.utils.odict.OrderedDict(
  182. [
  183. ("test_state0", {"result": True}),
  184. ("test_state", {"result": True}),
  185. ]
  186. ),
  187. ),
  188. ]
  189. ),
  190. )
  191. ]
  192. ),
  193. "test2": salt.utils.odict.OrderedDict(
  194. [
  195. (
  196. "host1",
  197. salt.utils.odict.OrderedDict(
  198. [
  199. ("test_state0", {"result": None}),
  200. ("test_state", {"result": True}),
  201. ]
  202. ),
  203. ),
  204. (
  205. "host2",
  206. salt.utils.odict.OrderedDict(
  207. [
  208. ("test_state0", {"result": True}),
  209. ("test_state", {"result": "abc"}),
  210. ]
  211. ),
  212. ),
  213. ]
  214. ),
  215. }
  216. for test, data in six.iteritems(test_valid_true_states):
  217. self.assertTrue(
  218. salt.utils.state.check_result(data), msg="{0} failed".format(test)
  219. )
  220. test_invalid_true_ht_states = {
  221. "test_onfail_simple2": (
  222. salt.utils.odict.OrderedDict(
  223. [
  224. (
  225. "host1",
  226. salt.utils.odict.OrderedDict(
  227. [
  228. ("test_vstate0", {"result": False}),
  229. ("test_vstate1", {"result": True}),
  230. ]
  231. ),
  232. ),
  233. ]
  234. ),
  235. {
  236. "test_vstate0": {
  237. "__env__": "base",
  238. "__sls__": "a",
  239. "cmd": [
  240. salt.utils.odict.OrderedDict([("name", "/bin/true")]),
  241. "run",
  242. {"order": 10002},
  243. ],
  244. },
  245. "test_vstate1": {
  246. "__env__": "base",
  247. "__sls__": "a",
  248. "cmd": [
  249. salt.utils.odict.OrderedDict([("name", "/bin/true")]),
  250. salt.utils.odict.OrderedDict(
  251. [
  252. ("onfail_stop", True),
  253. (
  254. "onfail",
  255. [
  256. salt.utils.odict.OrderedDict(
  257. [("cmd", "test_vstate0")]
  258. )
  259. ],
  260. ),
  261. ]
  262. ),
  263. "run",
  264. {"order": 10004},
  265. ],
  266. },
  267. },
  268. ),
  269. "test_onfail_integ2": (
  270. salt.utils.odict.OrderedDict(
  271. [
  272. (
  273. "host1",
  274. salt.utils.odict.OrderedDict(
  275. [
  276. (
  277. "t_|-test_ivstate0_|-echo_|-run",
  278. {"result": False},
  279. ),
  280. (
  281. "cmd_|-test_ivstate0_|-echo_|-run",
  282. {"result": False},
  283. ),
  284. (
  285. "cmd_|-test_ivstate1_|-echo_|-run",
  286. {"result": False},
  287. ),
  288. ]
  289. ),
  290. ),
  291. ]
  292. ),
  293. {
  294. "test_ivstate0": {
  295. "__env__": "base",
  296. "__sls__": "a",
  297. "cmd": [
  298. salt.utils.odict.OrderedDict([("name", "/bin/true")]),
  299. "run",
  300. {"order": 10002},
  301. ],
  302. "t": [
  303. salt.utils.odict.OrderedDict([("name", "/bin/true")]),
  304. "run",
  305. {"order": 10002},
  306. ],
  307. },
  308. "test_ivstate1": {
  309. "__env__": "base",
  310. "__sls__": "a",
  311. "cmd": [
  312. salt.utils.odict.OrderedDict([("name", "/bin/true")]),
  313. salt.utils.odict.OrderedDict(
  314. [
  315. ("onfail_stop", False),
  316. (
  317. "onfail",
  318. [
  319. salt.utils.odict.OrderedDict(
  320. [("cmd", "test_ivstate0")]
  321. )
  322. ],
  323. ),
  324. ]
  325. ),
  326. "run",
  327. {"order": 10004},
  328. ],
  329. },
  330. },
  331. ),
  332. "test_onfail_integ3": (
  333. salt.utils.odict.OrderedDict(
  334. [
  335. (
  336. "host1",
  337. salt.utils.odict.OrderedDict(
  338. [
  339. (
  340. "t_|-test_ivstate0_|-echo_|-run",
  341. {"result": True},
  342. ),
  343. (
  344. "cmd_|-test_ivstate0_|-echo_|-run",
  345. {"result": False},
  346. ),
  347. (
  348. "cmd_|-test_ivstate1_|-echo_|-run",
  349. {"result": False},
  350. ),
  351. ]
  352. ),
  353. ),
  354. ]
  355. ),
  356. {
  357. "test_ivstate0": {
  358. "__env__": "base",
  359. "__sls__": "a",
  360. "cmd": [
  361. salt.utils.odict.OrderedDict([("name", "/bin/true")]),
  362. "run",
  363. {"order": 10002},
  364. ],
  365. "t": [
  366. salt.utils.odict.OrderedDict([("name", "/bin/true")]),
  367. "run",
  368. {"order": 10002},
  369. ],
  370. },
  371. "test_ivstate1": {
  372. "__env__": "base",
  373. "__sls__": "a",
  374. "cmd": [
  375. salt.utils.odict.OrderedDict([("name", "/bin/true")]),
  376. salt.utils.odict.OrderedDict(
  377. [
  378. ("onfail_stop", False),
  379. (
  380. "onfail",
  381. [
  382. salt.utils.odict.OrderedDict(
  383. [("cmd", "test_ivstate0")]
  384. )
  385. ],
  386. ),
  387. ]
  388. ),
  389. "run",
  390. {"order": 10004},
  391. ],
  392. },
  393. },
  394. ),
  395. "test_onfail_integ4": (
  396. salt.utils.odict.OrderedDict(
  397. [
  398. (
  399. "host1",
  400. salt.utils.odict.OrderedDict(
  401. [
  402. (
  403. "t_|-test_ivstate0_|-echo_|-run",
  404. {"result": False},
  405. ),
  406. (
  407. "cmd_|-test_ivstate0_|-echo_|-run",
  408. {"result": False},
  409. ),
  410. (
  411. "cmd_|-test_ivstate1_|-echo_|-run",
  412. {"result": True},
  413. ),
  414. ]
  415. ),
  416. ),
  417. ]
  418. ),
  419. {
  420. "test_ivstate0": {
  421. "__env__": "base",
  422. "__sls__": "a",
  423. "cmd": [
  424. salt.utils.odict.OrderedDict([("name", "/bin/true")]),
  425. "run",
  426. {"order": 10002},
  427. ],
  428. "t": [
  429. salt.utils.odict.OrderedDict([("name", "/bin/true")]),
  430. "run",
  431. {"order": 10002},
  432. ],
  433. },
  434. "test_ivstate1": {
  435. "__env__": "base",
  436. "__sls__": "a",
  437. "cmd": [
  438. salt.utils.odict.OrderedDict([("name", "/bin/true")]),
  439. salt.utils.odict.OrderedDict(
  440. [
  441. ("onfail_stop", False),
  442. (
  443. "onfail",
  444. [
  445. salt.utils.odict.OrderedDict(
  446. [("cmd", "test_ivstate0")]
  447. )
  448. ],
  449. ),
  450. ]
  451. ),
  452. "run",
  453. {"order": 10004},
  454. ],
  455. },
  456. "test_ivstate2": {
  457. "__env__": "base",
  458. "__sls__": "a",
  459. "cmd": [
  460. salt.utils.odict.OrderedDict([("name", "/bin/true")]),
  461. salt.utils.odict.OrderedDict(
  462. [
  463. ("onfail_stop", True),
  464. (
  465. "onfail",
  466. [
  467. salt.utils.odict.OrderedDict(
  468. [("cmd", "test_ivstate0")]
  469. )
  470. ],
  471. ),
  472. ]
  473. ),
  474. "run",
  475. {"order": 10004},
  476. ],
  477. },
  478. },
  479. ),
  480. "test_onfail": (
  481. salt.utils.odict.OrderedDict(
  482. [
  483. (
  484. "host1",
  485. salt.utils.odict.OrderedDict(
  486. [
  487. ("test_state0", {"result": False}),
  488. ("test_state", {"result": True}),
  489. ]
  490. ),
  491. ),
  492. ]
  493. ),
  494. None,
  495. ),
  496. "test_onfail_d": (
  497. salt.utils.odict.OrderedDict(
  498. [
  499. (
  500. "host1",
  501. salt.utils.odict.OrderedDict(
  502. [
  503. ("test_state0", {"result": False}),
  504. ("test_state", {"result": True}),
  505. ]
  506. ),
  507. ),
  508. ]
  509. ),
  510. {},
  511. ),
  512. }
  513. for test, testdata in six.iteritems(test_invalid_true_ht_states):
  514. data, ht = testdata
  515. for t_ in [a for a in data["host1"]]:
  516. tdata = data["host1"][t_]
  517. if "_|-" in t_:
  518. t_ = t_.split("_|-")[1]
  519. tdata["__id__"] = t_
  520. self.assertFalse(
  521. salt.utils.state.check_result(data, highstate=ht),
  522. msg="{0} failed".format(test),
  523. )
  524. test_valid_true_ht_states = {
  525. "test_onfail_integ": (
  526. salt.utils.odict.OrderedDict(
  527. [
  528. (
  529. "host1",
  530. salt.utils.odict.OrderedDict(
  531. [
  532. (
  533. "cmd_|-test_ivstate0_|-echo_|-run",
  534. {"result": False},
  535. ),
  536. (
  537. "cmd_|-test_ivstate1_|-echo_|-run",
  538. {"result": True},
  539. ),
  540. ]
  541. ),
  542. ),
  543. ]
  544. ),
  545. {
  546. "test_ivstate0": {
  547. "__env__": "base",
  548. "__sls__": "a",
  549. "cmd": [
  550. salt.utils.odict.OrderedDict([("name", "/bin/true")]),
  551. "run",
  552. {"order": 10002},
  553. ],
  554. },
  555. "test_ivstate1": {
  556. "__env__": "base",
  557. "__sls__": "a",
  558. "cmd": [
  559. salt.utils.odict.OrderedDict([("name", "/bin/true")]),
  560. salt.utils.odict.OrderedDict(
  561. [
  562. ("onfail_stop", False),
  563. (
  564. "onfail",
  565. [
  566. salt.utils.odict.OrderedDict(
  567. [("cmd", "test_ivstate0")]
  568. )
  569. ],
  570. ),
  571. ]
  572. ),
  573. "run",
  574. {"order": 10004},
  575. ],
  576. },
  577. },
  578. ),
  579. "test_onfail_intega3": (
  580. salt.utils.odict.OrderedDict(
  581. [
  582. (
  583. "host1",
  584. salt.utils.odict.OrderedDict(
  585. [
  586. (
  587. "t_|-test_ivstate0_|-echo_|-run",
  588. {"result": True},
  589. ),
  590. (
  591. "cmd_|-test_ivstate0_|-echo_|-run",
  592. {"result": False},
  593. ),
  594. (
  595. "cmd_|-test_ivstate1_|-echo_|-run",
  596. {"result": True},
  597. ),
  598. ]
  599. ),
  600. ),
  601. ]
  602. ),
  603. {
  604. "test_ivstate0": {
  605. "__env__": "base",
  606. "__sls__": "a",
  607. "cmd": [
  608. salt.utils.odict.OrderedDict([("name", "/bin/true")]),
  609. "run",
  610. {"order": 10002},
  611. ],
  612. "t": [
  613. salt.utils.odict.OrderedDict([("name", "/bin/true")]),
  614. "run",
  615. {"order": 10002},
  616. ],
  617. },
  618. "test_ivstate1": {
  619. "__env__": "base",
  620. "__sls__": "a",
  621. "cmd": [
  622. salt.utils.odict.OrderedDict([("name", "/bin/true")]),
  623. salt.utils.odict.OrderedDict(
  624. [
  625. ("onfail_stop", False),
  626. (
  627. "onfail",
  628. [
  629. salt.utils.odict.OrderedDict(
  630. [("cmd", "test_ivstate0")]
  631. )
  632. ],
  633. ),
  634. ]
  635. ),
  636. "run",
  637. {"order": 10004},
  638. ],
  639. },
  640. },
  641. ),
  642. "test_onfail_simple": (
  643. salt.utils.odict.OrderedDict(
  644. [
  645. (
  646. "host1",
  647. salt.utils.odict.OrderedDict(
  648. [
  649. ("test_vstate0", {"result": False}),
  650. ("test_vstate1", {"result": True}),
  651. ]
  652. ),
  653. ),
  654. ]
  655. ),
  656. {
  657. "test_vstate0": {
  658. "__env__": "base",
  659. "__sls__": "a",
  660. "cmd": [
  661. salt.utils.odict.OrderedDict([("name", "/bin/true")]),
  662. "run",
  663. {"order": 10002},
  664. ],
  665. },
  666. "test_vstate1": {
  667. "__env__": "base",
  668. "__sls__": "a",
  669. "cmd": [
  670. salt.utils.odict.OrderedDict([("name", "/bin/true")]),
  671. salt.utils.odict.OrderedDict(
  672. [
  673. ("onfail_stop", False),
  674. (
  675. "onfail",
  676. [
  677. salt.utils.odict.OrderedDict(
  678. [("cmd", "test_vstate0")]
  679. )
  680. ],
  681. ),
  682. ]
  683. ),
  684. "run",
  685. {"order": 10004},
  686. ],
  687. },
  688. },
  689. ), # order is different
  690. "test_onfail_simple_rev": (
  691. salt.utils.odict.OrderedDict(
  692. [
  693. (
  694. "host1",
  695. salt.utils.odict.OrderedDict(
  696. [
  697. ("test_vstate0", {"result": False}),
  698. ("test_vstate1", {"result": True}),
  699. ]
  700. ),
  701. ),
  702. ]
  703. ),
  704. {
  705. "test_vstate0": {
  706. "__env__": "base",
  707. "__sls__": "a",
  708. "cmd": [
  709. salt.utils.odict.OrderedDict([("name", "/bin/true")]),
  710. "run",
  711. {"order": 10002},
  712. ],
  713. },
  714. "test_vstate1": {
  715. "__env__": "base",
  716. "__sls__": "a",
  717. "cmd": [
  718. salt.utils.odict.OrderedDict([("name", "/bin/true")]),
  719. salt.utils.odict.OrderedDict(
  720. [
  721. (
  722. "onfail",
  723. [
  724. salt.utils.odict.OrderedDict(
  725. [("cmd", "test_vstate0")]
  726. )
  727. ],
  728. )
  729. ]
  730. ),
  731. salt.utils.odict.OrderedDict([("onfail_stop", False)]),
  732. "run",
  733. {"order": 10004},
  734. ],
  735. },
  736. },
  737. ),
  738. }
  739. for test, testdata in six.iteritems(test_valid_true_ht_states):
  740. data, ht = testdata
  741. for t_ in [a for a in data["host1"]]:
  742. tdata = data["host1"][t_]
  743. if "_|-" in t_:
  744. t_ = t_.split("_|-")[1]
  745. tdata["__id__"] = t_
  746. self.assertTrue(
  747. salt.utils.state.check_result(data, highstate=ht),
  748. msg="{0} failed".format(test),
  749. )
  750. test_valid_false_state = {"host1": {"test_state": {"result": False}}}
  751. self.assertFalse(salt.utils.state.check_result(test_valid_false_state))
  752. class UtilStateMergeSubreturnTestcase(TestCase):
  753. """
  754. Test cases for salt.utils.state.merge_subreturn function.
  755. """
  756. main_ret = {
  757. "name": "primary",
  758. # result may be missing, as primarysalt.utils.state is still in progress
  759. "comment": "",
  760. "changes": {},
  761. }
  762. sub_ret = {
  763. "name": "secondary",
  764. "result": True,
  765. "comment": "",
  766. "changes": {},
  767. }
  768. def test_merge_result(self):
  769. # result not created if not needed
  770. for no_effect_result in [True, None]:
  771. m = copy.deepcopy(self.main_ret)
  772. s = copy.deepcopy(self.sub_ret)
  773. s["result"] = no_effect_result
  774. res = salt.utils.state.merge_subreturn(m, s)
  775. self.assertNotIn("result", res)
  776. # False subresult is propagated to existing result
  777. for original_result in [True, None, False]:
  778. m = copy.deepcopy(self.main_ret)
  779. m["result"] = original_result
  780. s = copy.deepcopy(self.sub_ret)
  781. s["result"] = False
  782. res = salt.utils.state.merge_subreturn(m, s)
  783. self.assertFalse(res["result"])
  784. # False result cannot be overridden
  785. for any_result in [True, None, False]:
  786. m = copy.deepcopy(self.main_ret)
  787. m["result"] = False
  788. s = copy.deepcopy(self.sub_ret)
  789. s["result"] = any_result
  790. res = salt.utils.state.merge_subreturn(m, s)
  791. self.assertFalse(res["result"])
  792. def test_merge_changes(self):
  793. # The main changes dict should always already exist,
  794. # and there should always be a changes dict in the secondary.
  795. primary_changes = {"old": None, "new": "my_resource"}
  796. secondary_changes = {"old": None, "new": ["alarm-1", "alarm-2"]}
  797. # No changes case
  798. m = copy.deepcopy(self.main_ret)
  799. s = copy.deepcopy(self.sub_ret)
  800. res = salt.utils.state.merge_subreturn(m, s)
  801. self.assertDictEqual(res["changes"], {})
  802. # New changes don't get rid of existing changes
  803. m = copy.deepcopy(self.main_ret)
  804. m["changes"] = copy.deepcopy(primary_changes)
  805. s = copy.deepcopy(self.sub_ret)
  806. s["changes"] = copy.deepcopy(secondary_changes)
  807. res = salt.utils.state.merge_subreturn(m, s)
  808. self.assertDictEqual(
  809. res["changes"],
  810. {"old": None, "new": "my_resource", "secondary": secondary_changes},
  811. )
  812. # The subkey parameter is respected
  813. m = copy.deepcopy(self.main_ret)
  814. m["changes"] = copy.deepcopy(primary_changes)
  815. s = copy.deepcopy(self.sub_ret)
  816. s["changes"] = copy.deepcopy(secondary_changes)
  817. res = salt.utils.state.merge_subreturn(m, s, subkey="alarms")
  818. self.assertDictEqual(
  819. res["changes"],
  820. {"old": None, "new": "my_resource", "alarms": secondary_changes},
  821. )
  822. def test_merge_comments(self):
  823. main_comment_1 = "First primary comment."
  824. main_comment_2 = "Second primary comment."
  825. sub_comment_1 = "First secondary comment,\nwhich spans two lines."
  826. sub_comment_2 = "Second secondary comment: {0}".format(
  827. "some error\n And a traceback",
  828. )
  829. final_comment = textwrap.dedent(
  830. """\
  831. First primary comment.
  832. Second primary comment.
  833. First secondary comment,
  834. which spans two lines.
  835. Second secondary comment: some error
  836. And a traceback
  837. """.rstrip()
  838. )
  839. # Joining two strings
  840. m = copy.deepcopy(self.main_ret)
  841. m["comment"] = main_comment_1 + "\n" + main_comment_2
  842. s = copy.deepcopy(self.sub_ret)
  843. s["comment"] = sub_comment_1 + "\n" + sub_comment_2
  844. res = salt.utils.state.merge_subreturn(m, s)
  845. self.assertMultiLineEqual(res["comment"], final_comment)
  846. # Joining string and a list
  847. m = copy.deepcopy(self.main_ret)
  848. m["comment"] = main_comment_1 + "\n" + main_comment_2
  849. s = copy.deepcopy(self.sub_ret)
  850. s["comment"] = [sub_comment_1, sub_comment_2]
  851. res = salt.utils.state.merge_subreturn(m, s)
  852. self.assertMultiLineEqual(res["comment"], final_comment)
  853. # For tests where output is a list,
  854. # also test that final joined output will match
  855. # Joining list and a string
  856. m = copy.deepcopy(self.main_ret)
  857. m["comment"] = [main_comment_1, main_comment_2]
  858. s = copy.deepcopy(self.sub_ret)
  859. s["comment"] = sub_comment_1 + "\n" + sub_comment_2
  860. res = salt.utils.state.merge_subreturn(m, s)
  861. self.assertEqual(
  862. res["comment"],
  863. [main_comment_1, main_comment_2, sub_comment_1 + "\n" + sub_comment_2],
  864. )
  865. self.assertMultiLineEqual("\n".join(res["comment"]), final_comment)
  866. # Joining two lists
  867. m = copy.deepcopy(self.main_ret)
  868. m["comment"] = [main_comment_1, main_comment_2]
  869. s = copy.deepcopy(self.sub_ret)
  870. s["comment"] = [sub_comment_1, sub_comment_2]
  871. res = salt.utils.state.merge_subreturn(m, s)
  872. self.assertEqual(
  873. res["comment"],
  874. [main_comment_1, main_comment_2, sub_comment_1, sub_comment_2],
  875. )
  876. self.assertMultiLineEqual("\n".join(res["comment"]), final_comment)
  877. def test_merge_empty_comments(self):
  878. # Since the primarysalt.utils.state is in progress,
  879. # the main comment may be empty, either '' or [].
  880. # Note that [''] is a degenerate case and should never happen,
  881. # hence the behavior is left unspecified in that case.
  882. # The secondary comment should never be empty,
  883. # because thatsalt.utils.state has already returned,
  884. # so we leave the behavior unspecified in that case.
  885. sub_comment_1 = "Secondary comment about changes:"
  886. sub_comment_2 = "A diff that goes with the previous comment"
  887. # No contributions from primary
  888. final_comment = sub_comment_1 + "\n" + sub_comment_2
  889. # Joining empty string and a string
  890. m = copy.deepcopy(self.main_ret)
  891. m["comment"] = ""
  892. s = copy.deepcopy(self.sub_ret)
  893. s["comment"] = sub_comment_1 + "\n" + sub_comment_2
  894. res = salt.utils.state.merge_subreturn(m, s)
  895. self.assertEqual(res["comment"], final_comment)
  896. # Joining empty string and a list
  897. m = copy.deepcopy(self.main_ret)
  898. m["comment"] = ""
  899. s = copy.deepcopy(self.sub_ret)
  900. s["comment"] = [sub_comment_1, sub_comment_2]
  901. res = salt.utils.state.merge_subreturn(m, s)
  902. self.assertEqual(res["comment"], final_comment)
  903. # For tests where output is a list,
  904. # also test that final joined output will match
  905. # Joining empty list and a string
  906. m = copy.deepcopy(self.main_ret)
  907. m["comment"] = []
  908. s = copy.deepcopy(self.sub_ret)
  909. s["comment"] = sub_comment_1 + "\n" + sub_comment_2
  910. res = salt.utils.state.merge_subreturn(m, s)
  911. self.assertEqual(res["comment"], [final_comment])
  912. self.assertEqual("\n".join(res["comment"]), final_comment)
  913. # Joining empty list and a list
  914. m = copy.deepcopy(self.main_ret)
  915. m["comment"] = []
  916. s = copy.deepcopy(self.sub_ret)
  917. s["comment"] = [sub_comment_1, sub_comment_2]
  918. res = salt.utils.state.merge_subreturn(m, s)
  919. self.assertEqual(res["comment"], [sub_comment_1, sub_comment_2])
  920. self.assertEqual("\n".join(res["comment"]), final_comment)