Skip to content
This repository was archived by the owner on Jan 23, 2026. It is now read-only.

Commit e7a1c79

Browse files
add --all to "get leases"
this indicates to the server that we want to see ended leases as well. Default behavior is to only get non-ended leases (pending or currently active) (cherry picked from commit 6d94924)
1 parent 005dd95 commit e7a1c79

4 files changed

Lines changed: 121 additions & 3 deletions

File tree

packages/jumpstarter-cli/jumpstarter_cli/get.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,19 @@ def get_exporters(config, selector: str | None, output: OutputType, with_options
4141
@opt_config(exporter=False)
4242
@opt_selector
4343
@opt_output_all
44+
@click.option(
45+
"--all",
46+
"show_all",
47+
is_flag=True,
48+
default=False,
49+
help="Show all leases including expired ones"
50+
)
4451
@handle_exceptions_with_reauthentication(relogin_client)
45-
def get_leases(config, selector: str | None, output: OutputType):
52+
def get_leases(config, selector: str | None, output: OutputType, show_all: bool):
4653
"""
4754
Display one or many leases
4855
"""
4956

50-
leases = config.list_leases(filter=selector)
57+
leases = config.list_leases(filter=selector, only_active=not show_all)
5158

5259
model_print(leases, output)

packages/jumpstarter-cli/jumpstarter_cli/get_test.py

Lines changed: 108 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1+
from datetime import datetime, timedelta
12
from unittest.mock import Mock
23

34
import click
45
import pytest
56
from jumpstarter_cli_common.opt import parse_comma_separated
67

7-
from jumpstarter.client.grpc import Exporter, ExporterList, Lease
8+
from jumpstarter.client.grpc import Exporter, ExporterList, Lease, LeaseList
89
from jumpstarter.config.client import ClientConfigV1Alpha1
910

1011

@@ -239,3 +240,109 @@ def test_exporter_to_exporter_list_flow(self):
239240
assert exporter_list.exporters[1].name == "server-001"
240241
assert exporter_list.include_online is True
241242
assert exporter_list.include_leases is False
243+
244+
245+
class TestGetLeasesLogic:
246+
"""Tests for get leases command logic (simulating server-side filtering)"""
247+
248+
def create_test_lease(self, namespace="default", name="lease-1", status="In-Use",
249+
effective_begin_time=None, effective_end_time=None,
250+
duration=timedelta(hours=1)):
251+
"""Create a mock lease for testing"""
252+
lease = Mock(spec=Lease)
253+
lease.namespace = namespace
254+
lease.name = name
255+
lease.client = "test-client"
256+
lease.exporter = "test-exporter"
257+
lease.get_status.return_value = status
258+
lease.effective_begin_time = effective_begin_time
259+
lease.effective_end_time = effective_end_time
260+
lease.duration = duration
261+
lease.effective_duration = timedelta(minutes=30) if effective_begin_time else None
262+
lease.begin_time = None
263+
return lease
264+
265+
def test_only_active_excludes_expired_leases(self):
266+
"""Test that server returns only active leases when only_active=True"""
267+
# When only_active=True, server returns only active lease
268+
active_lease = self.create_test_lease(
269+
name="active-lease",
270+
status="In-Use",
271+
effective_begin_time=datetime(2023, 1, 1, 10, 0, 0)
272+
)
273+
274+
leases_from_server = LeaseList(leases=[active_lease], next_page_token=None)
275+
276+
assert len(leases_from_server.leases) == 1
277+
assert leases_from_server.leases[0].name == "active-lease"
278+
assert leases_from_server.leases[0].get_status() == "In-Use"
279+
280+
def test_show_all_includes_expired_leases(self):
281+
"""Test that server returns all leases including expired when only_active=False"""
282+
# When only_active=False, server returns both active and expired
283+
active_lease = self.create_test_lease(
284+
name="active-lease",
285+
status="In-Use",
286+
effective_begin_time=datetime(2023, 1, 1, 10, 0, 0)
287+
)
288+
expired_lease = self.create_test_lease(
289+
name="expired-lease",
290+
status="Expired",
291+
effective_begin_time=datetime(2023, 1, 1, 8, 0, 0),
292+
effective_end_time=datetime(2023, 1, 1, 9, 0, 0)
293+
)
294+
295+
leases_from_server = LeaseList(leases=[active_lease, expired_lease], next_page_token=None)
296+
297+
assert len(leases_from_server.leases) == 2
298+
assert leases_from_server.leases[0].name == "active-lease"
299+
assert leases_from_server.leases[1].name == "expired-lease"
300+
301+
def test_multiple_active_leases_returned(self):
302+
"""Test that server returns all active leases when only_active=True"""
303+
# Server returns multiple active leases (different statuses but all non-expired)
304+
lease1 = self.create_test_lease(
305+
name="lease-1",
306+
status="In-Use",
307+
effective_begin_time=datetime(2023, 1, 1, 10, 0, 0)
308+
)
309+
lease2 = self.create_test_lease(
310+
name="lease-2",
311+
status="Waiting",
312+
effective_begin_time=datetime(2023, 1, 1, 11, 0, 0)
313+
)
314+
lease3 = self.create_test_lease(
315+
name="lease-3",
316+
status="In-Use",
317+
effective_begin_time=datetime(2023, 1, 1, 12, 0, 0)
318+
)
319+
320+
leases_from_server = LeaseList(leases=[lease1, lease2, lease3], next_page_token=None)
321+
322+
assert len(leases_from_server.leases) == 3
323+
assert all(lease.get_status() != "Expired" for lease in leases_from_server.leases)
324+
325+
def test_all_expired_when_show_all(self):
326+
"""Test that server can return only expired leases when only_active=False"""
327+
# When only_active=False and all leases happen to be expired
328+
expired1 = self.create_test_lease(
329+
name="expired-1",
330+
status="Expired",
331+
effective_end_time=datetime(2023, 1, 1, 8, 0, 0)
332+
)
333+
expired2 = self.create_test_lease(
334+
name="expired-2",
335+
status="Expired",
336+
effective_end_time=datetime(2023, 1, 1, 9, 0, 0)
337+
)
338+
339+
leases_from_server = LeaseList(leases=[expired1, expired2], next_page_token=None)
340+
341+
assert len(leases_from_server.leases) == 2
342+
assert all(lease.get_status() == "Expired" for lease in leases_from_server.leases)
343+
344+
def test_empty_lease_list(self):
345+
"""Test that server can return empty lease list"""
346+
leases_from_server = LeaseList(leases=[], next_page_token=None)
347+
348+
assert len(leases_from_server.leases) == 0

packages/jumpstarter/jumpstarter/client/grpc.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,7 @@ async def ListLeases(
370370
page_size: int | None = None,
371371
page_token: str | None = None,
372372
filter: str | None = None,
373+
only_active: bool = True,
373374
):
374375
with translate_grpc_exceptions():
375376
leases = await self.stub.ListLeases(
@@ -378,6 +379,7 @@ async def ListLeases(
378379
page_size=page_size,
379380
page_token=page_token,
380381
filter=filter,
382+
only_active=only_active,
381383
)
382384
)
383385
return LeaseList.from_protobuf(leases)

packages/jumpstarter/jumpstarter/config/client.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,12 +227,14 @@ async def list_leases(
227227
page_size: int | None = None,
228228
page_token: str | None = None,
229229
filter: str | None = None,
230+
only_active: bool = True,
230231
):
231232
svc = ClientService(channel=await self.channel(), namespace=self.metadata.namespace)
232233
return await svc.ListLeases(
233234
page_size=page_size,
234235
page_token=page_token,
235236
filter=filter,
237+
only_active=only_active,
236238
)
237239

238240
@_blocking_compat

0 commit comments

Comments
 (0)