Skip to content

Commit 72e6de4

Browse files
Fixed inconsistent value types populated for LKENodePool.nodes (#446)
* Updated The LKENodePool(...).nodes attribute to only be populated with LKENodePoolNode objects * Addressed PR comments
1 parent 0c0e649 commit 72e6de4

File tree

2 files changed

+116
-8
lines changed

2 files changed

+116
-8
lines changed

linode_api4/objects/lke.py

+23-8
Original file line numberDiff line numberDiff line change
@@ -146,14 +146,29 @@ def _populate(self, json):
146146
Parse Nodes into more useful LKENodePoolNode objects
147147
"""
148148
if json is not None and json != {}:
149-
new_nodes = [
150-
(
151-
LKENodePoolNode(self._client, c)
152-
if not isinstance(c, dict)
153-
else c
154-
)
155-
for c in json["nodes"]
156-
]
149+
new_nodes = []
150+
for c in json["nodes"]:
151+
if isinstance(c, LKENodePoolNode):
152+
new_nodes.append(c)
153+
elif isinstance(c, dict):
154+
node_id = c.get("id")
155+
if node_id is not None:
156+
new_nodes.append(LKENodePoolNode(self._client, c))
157+
else:
158+
raise ValueError(
159+
"Node dictionary does not contain 'id' key"
160+
)
161+
elif isinstance(c, str):
162+
node_details = self._client.get(
163+
LKENodePool.api_endpoint.format(
164+
cluster_id=self.id, id=c
165+
)
166+
)
167+
new_nodes.append(
168+
LKENodePoolNode(self._client, node_details)
169+
)
170+
else:
171+
raise TypeError("Unsupported node type: {}".format(type(c)))
157172
json["nodes"] = new_nodes
158173

159174
super()._populate(json)

test/unit/objects/lke_test.py

+93
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from datetime import datetime
22
from test.unit.base import ClientBaseCase
3+
from unittest.mock import MagicMock
34

45
from linode_api4 import InstanceDiskEncryptionType
56
from linode_api4.objects import (
@@ -9,6 +10,7 @@
910
LKEClusterControlPlaneOptions,
1011
LKENodePool,
1112
)
13+
from linode_api4.objects.lke import LKENodePoolNode
1214

1315

1416
class LKETest(ClientBaseCase):
@@ -262,3 +264,94 @@ def test_cluster_delete_acl(self):
262264

263265
assert m.call_url == "/lke/clusters/18881/control_plane_acl"
264266
assert m.method == "get"
267+
268+
def test_populate_with_node_objects(self):
269+
"""
270+
Tests that LKENodePool correctly handles a list of LKENodePoolNode objects.
271+
"""
272+
self.client = MagicMock()
273+
self.pool = LKENodePool(self.client, 456, 18881)
274+
275+
node1 = LKENodePoolNode(
276+
self.client, {"id": "node1", "instance_id": 101, "status": "active"}
277+
)
278+
node2 = LKENodePoolNode(
279+
self.client,
280+
{"id": "node2", "instance_id": 102, "status": "inactive"},
281+
)
282+
self.pool._populate({"nodes": [node1, node2]})
283+
284+
self.assertEqual(len(self.pool.nodes), 2)
285+
self.assertIsInstance(self.pool.nodes[0], LKENodePoolNode)
286+
self.assertIsInstance(self.pool.nodes[1], LKENodePoolNode)
287+
self.assertEqual(self.pool.nodes[0].id, "node1")
288+
self.assertEqual(self.pool.nodes[1].id, "node2")
289+
290+
def test_populate_with_node_dicts(self):
291+
"""
292+
Tests that LKENodePool correctly handles a list of node dictionaries.
293+
"""
294+
self.client = MagicMock()
295+
self.pool = LKENodePool(self.client, 456, 18881)
296+
297+
node_dict1 = {"id": "node3", "instance_id": 103, "status": "pending"}
298+
node_dict2 = {"id": "node4", "instance_id": 104, "status": "failed"}
299+
self.pool._populate({"nodes": [node_dict1, node_dict2]})
300+
301+
self.assertEqual(len(self.pool.nodes), 2)
302+
self.assertIsInstance(self.pool.nodes[0], LKENodePoolNode)
303+
self.assertIsInstance(self.pool.nodes[1], LKENodePoolNode)
304+
self.assertEqual(self.pool.nodes[0].id, "node3")
305+
self.assertEqual(self.pool.nodes[1].id, "node4")
306+
307+
def test_populate_with_node_ids(self):
308+
"""
309+
Tests that LKENodePool correctly handles a list of node IDs.
310+
"""
311+
self.client = MagicMock()
312+
self.pool = LKENodePool(self.client, 456, 18881)
313+
314+
node_id1 = "node5"
315+
node_id2 = "node6"
316+
# Mock instances creation
317+
self.client.get = MagicMock(
318+
side_effect=[
319+
{"id": "node5", "instance_id": 105, "status": "active"},
320+
{"id": "node6", "instance_id": 106, "status": "inactive"},
321+
]
322+
)
323+
self.pool._populate({"nodes": [node_id1, node_id2]})
324+
325+
self.assertEqual(len(self.pool.nodes), 2)
326+
self.assertIsInstance(self.pool.nodes[0], LKENodePoolNode)
327+
self.assertIsInstance(self.pool.nodes[1], LKENodePoolNode)
328+
self.assertEqual(self.pool.nodes[0].id, "node5")
329+
self.assertEqual(self.pool.nodes[1].id, "node6")
330+
331+
def test_populate_with_mixed_types(self):
332+
"""
333+
Tests that LKENodePool correctly handles a mixed list of node objects, dicts, and IDs.
334+
"""
335+
self.client = MagicMock()
336+
self.pool = LKENodePool(self.client, 456, 18881)
337+
338+
node1 = LKENodePoolNode(
339+
self.client, {"id": "node7", "instance_id": 107, "status": "active"}
340+
)
341+
node_dict = {"id": "node8", "instance_id": 108, "status": "inactive"}
342+
node_id = "node9"
343+
# Mock instances creation
344+
self.client.get = MagicMock(
345+
side_effect=[
346+
{"id": "node9", "instance_id": 109, "status": "pending"}
347+
]
348+
)
349+
self.pool._populate({"nodes": [node1, node_dict, node_id]})
350+
351+
self.assertEqual(len(self.pool.nodes), 3)
352+
self.assertIsInstance(self.pool.nodes[0], LKENodePoolNode)
353+
self.assertIsInstance(self.pool.nodes[1], LKENodePoolNode)
354+
self.assertIsInstance(self.pool.nodes[2], LKENodePoolNode)
355+
self.assertEqual(self.pool.nodes[0].id, "node7")
356+
self.assertEqual(self.pool.nodes[1].id, "node8")
357+
self.assertEqual(self.pool.nodes[2].id, "node9")

0 commit comments

Comments
 (0)