Skip to content

Commit ebe07f2

Browse files
Spike CurtisShaun Crampton
authored andcommitted
Fix EtcdResult.get_subtree(leaves_only=False)
EtcdResult.get_subtree(leaves_only=False) was returning each leaf node twice, and didn't return the top level node at all. This commit fixes it and provides a UT.
1 parent d07c027 commit ebe07f2

2 files changed

Lines changed: 151 additions & 6 deletions

File tree

src/etcd/__init__.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,14 @@ def get_subtree(self, leaves_only=False):
7676
#if the current result is a leaf, return itself
7777
yield self
7878
return
79-
for n in self._children:
80-
node = EtcdResult(None, n)
79+
else:
80+
# node is not a leaf
8181
if not leaves_only:
82-
#Return also dirs, not just value nodes
83-
yield node
84-
for child in node.get_subtree(leaves_only=leaves_only):
85-
yield child
82+
yield self
83+
for n in self._children:
84+
node = EtcdResult(None, n)
85+
for child in node.get_subtree(leaves_only=leaves_only):
86+
yield child
8687
return
8788

8889
@property

src/etcd/tests/unit/test_result.py

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
import etcd
2+
import unittest
3+
import json
4+
import urllib3
5+
6+
try:
7+
import mock
8+
except ImportError:
9+
from unittest import mock
10+
11+
class TestEtcdResult(unittest.TestCase):
12+
13+
def test_get_subtree_1_level(self):
14+
"""
15+
Test get_subtree() for a read with tree 1 level deep.
16+
"""
17+
response = {"node": {
18+
'key': "/test",
19+
'value': "hello",
20+
'expiration': None,
21+
'ttl': None,
22+
'modifiedIndex': 5,
23+
'createdIndex': 1,
24+
'newKey': False,
25+
'dir': False,
26+
}}
27+
result = etcd.EtcdResult(**response)
28+
self.assertEqual(result.key, response["node"]["key"])
29+
self.assertEqual(result.value, response["node"]["value"])
30+
31+
# Get subtree returns itself, whether or not leaves_only
32+
subtree = list(result.get_subtree(leaves_only=True))
33+
self.assertListEqual([result], subtree)
34+
subtree = list(result.get_subtree(leaves_only=False))
35+
self.assertListEqual([result], subtree)
36+
37+
def test_get_subtree_2_level(self):
38+
"""
39+
Test get_subtree() for a read with tree 2 levels deep.
40+
"""
41+
leaf0 = {
42+
'key': "/test/leaf0",
43+
'value': "hello1",
44+
'expiration': None,
45+
'ttl': None,
46+
'modifiedIndex': 5,
47+
'createdIndex': 1,
48+
'newKey': False,
49+
'dir': False,
50+
}
51+
leaf1 = {
52+
'key': "/test/leaf1",
53+
'value': "hello2",
54+
'expiration': None,
55+
'ttl': None,
56+
'modifiedIndex': 6,
57+
'createdIndex': 2,
58+
'newKey': False,
59+
'dir': False,
60+
}
61+
testnode = {"node": {
62+
'key': "/test/",
63+
'expiration': None,
64+
'ttl': None,
65+
'modifiedIndex': 6,
66+
'createdIndex': 2,
67+
'newKey': False,
68+
'dir': True,
69+
'nodes': [leaf0, leaf1]
70+
}}
71+
result = etcd.EtcdResult(**testnode)
72+
self.assertEqual(result.key, "/test/")
73+
self.assertTrue(result.dir)
74+
75+
# Get subtree returns just two leaves for leaves only.
76+
subtree = list(result.get_subtree(leaves_only=True))
77+
self.assertEqual(subtree[0].key, "/test/leaf0")
78+
self.assertEqual(subtree[1].key, "/test/leaf1")
79+
self.assertEqual(len(subtree), 2)
80+
81+
# Get subtree returns leaves and directory.
82+
subtree = list(result.get_subtree(leaves_only=False))
83+
self.assertEqual(subtree[0].key, "/test/")
84+
self.assertEqual(subtree[1].key, "/test/leaf0")
85+
self.assertEqual(subtree[2].key, "/test/leaf1")
86+
self.assertEqual(len(subtree), 3)
87+
88+
def test_get_subtree_3_level(self):
89+
"""
90+
Test get_subtree() for a read with tree 3 levels deep.
91+
"""
92+
leaf0 = {
93+
'key': "/test/mid0/leaf0",
94+
'value': "hello1",
95+
}
96+
leaf1 = {
97+
'key': "/test/mid0/leaf1",
98+
'value': "hello2",
99+
}
100+
leaf2 = {
101+
'key': "/test/mid1/leaf2",
102+
'value': "hello1",
103+
}
104+
leaf3 = {
105+
'key': "/test/mid1/leaf3",
106+
'value': "hello2",
107+
}
108+
mid0 = {
109+
'key': "/test/mid0/",
110+
'dir': True,
111+
'nodes': [leaf0, leaf1]
112+
}
113+
mid1 = {
114+
'key': "/test/mid1/",
115+
'dir': True,
116+
'nodes': [leaf2, leaf3]
117+
}
118+
testnode = {"node": {
119+
'key': "/test/",
120+
'dir': True,
121+
'nodes': [mid0, mid1]
122+
}}
123+
result = etcd.EtcdResult(**testnode)
124+
self.assertEqual(result.key, "/test/")
125+
self.assertTrue(result.dir)
126+
127+
# Get subtree returns just two leaves for leaves only.
128+
subtree = list(result.get_subtree(leaves_only=True))
129+
self.assertEqual(subtree[0].key, "/test/mid0/leaf0")
130+
self.assertEqual(subtree[1].key, "/test/mid0/leaf1")
131+
self.assertEqual(subtree[2].key, "/test/mid1/leaf2")
132+
self.assertEqual(subtree[3].key, "/test/mid1/leaf3")
133+
self.assertEqual(len(subtree), 4)
134+
135+
# Get subtree returns leaves and directory.
136+
subtree = list(result.get_subtree(leaves_only=False))
137+
self.assertEqual(subtree[0].key, "/test/")
138+
self.assertEqual(subtree[1].key, "/test/mid0/")
139+
self.assertEqual(subtree[2].key, "/test/mid0/leaf0")
140+
self.assertEqual(subtree[3].key, "/test/mid0/leaf1")
141+
self.assertEqual(subtree[4].key, "/test/mid1/")
142+
self.assertEqual(subtree[5].key, "/test/mid1/leaf2")
143+
self.assertEqual(subtree[6].key, "/test/mid1/leaf3")
144+
self.assertEqual(len(subtree), 7)

0 commit comments

Comments
 (0)