4
4
from botocore .exceptions import ClientError
5
5
import boto3
6
6
7
- from sagemaker .hyperpod .cluster_management .hp_cluster_stack import HpClusterStack , CLUSTER_STACK_TEMPLATE_PACKAGE_NAME , CLUSTER_CREATION_TEMPLATE_FILE_NAME
8
-
7
+ from sagemaker .hyperpod .cluster_management .hp_cluster_stack import HpClusterStack
9
8
10
9
class TestHpClusterStack (unittest .TestCase ):
11
10
@patch ('uuid.uuid4' )
@@ -392,9 +391,134 @@ def test_create_parameters_preserves_other_fields(self):
392
391
393
392
# Should have the other fields
394
393
param_keys = [p ['ParameterKey' ] for p in other_params ]
395
- self .assertIn ('HyperpodClusterName ' , param_keys )
394
+ self .assertIn ('HyperPodClusterName ' , param_keys )
396
395
self .assertIn ('CreateVPCStack' , param_keys )
397
396
398
397
# Verify boolean conversion
399
398
vpc_param = next (p for p in other_params if p ['ParameterKey' ] == 'CreateVPCStack' )
400
- self .assertEqual (vpc_param ['ParameterValue' ], 'true' )
399
+ self .assertEqual (vpc_param ['ParameterValue' ], 'true' )
400
+
401
+ class TestHpClusterStackInit (unittest .TestCase ):
402
+ """Test HpClusterStack __init__ method array conversion"""
403
+
404
+ def test_init_converts_arrays_to_json_strings (self ):
405
+ """Test that __init__ converts array values to JSON strings"""
406
+ data = {
407
+ 'tags' : [{'Key' : 'Environment' , 'Value' : 'Test' }],
408
+ 'availability_zone_ids' : ['us-east-1a' , 'us-east-1b' ],
409
+ 'hyperpod_cluster_name' : 'test-cluster' ,
410
+ 'storage_capacity' : 1200
411
+ }
412
+
413
+ stack = HpClusterStack (** data )
414
+
415
+ # Arrays should be converted to JSON strings
416
+ self .assertEqual (stack .tags , '[{"Key": "Environment", "Value": "Test"}]' )
417
+ self .assertEqual (stack .availability_zone_ids , '["us-east-1a", "us-east-1b"]' )
418
+
419
+ # Other types should remain unchanged
420
+ self .assertEqual (stack .hyperpod_cluster_name , 'test-cluster' )
421
+ self .assertEqual (stack .storage_capacity , 1200 )
422
+
423
+ def test_init_handles_empty_arrays (self ):
424
+ """Test that empty arrays are converted to empty JSON arrays"""
425
+ data = {'tags' : []}
426
+
427
+ stack = HpClusterStack (** data )
428
+
429
+ self .assertEqual (stack .tags , '[]' )
430
+
431
+ def test_init_handles_no_arrays (self ):
432
+ """Test that __init__ works normally when no arrays are present"""
433
+ data = {
434
+ 'hyperpod_cluster_name' : 'test-cluster' ,
435
+ 'stage' : 'gamma'
436
+ }
437
+
438
+ stack = HpClusterStack (** data )
439
+
440
+ self .assertEqual (stack .hyperpod_cluster_name , 'test-cluster' )
441
+ self .assertEqual (stack .stage , 'gamma' )
442
+
443
+
444
+ class TestHpClusterStackParseTags (unittest .TestCase ):
445
+ """Test HpClusterStack _parse_tags method"""
446
+
447
+ def test_parse_tags_valid_json_array (self ):
448
+ """Test parsing valid JSON array of tags"""
449
+ tags_json = '[{"Key": "Environment", "Value": "Test"}, {"Key": "Project", "Value": "HyperPod"}]'
450
+ stack = HpClusterStack (tags = tags_json )
451
+
452
+ result = stack ._parse_tags ()
453
+
454
+ expected = [
455
+ {"Key" : "Environment" , "Value" : "Test" },
456
+ {"Key" : "Project" , "Value" : "HyperPod" }
457
+ ]
458
+ self .assertEqual (result , expected )
459
+
460
+ def test_parse_tags_empty_string (self ):
461
+ """Test parsing empty tags string returns empty list"""
462
+ stack = HpClusterStack (tags = "" )
463
+
464
+ result = stack ._parse_tags ()
465
+
466
+ self .assertEqual (result , [])
467
+
468
+ def test_parse_tags_none_value (self ):
469
+ """Test parsing None tags returns empty list"""
470
+ stack = HpClusterStack (tags = None )
471
+
472
+ result = stack ._parse_tags ()
473
+
474
+ self .assertEqual (result , [])
475
+
476
+ def test_parse_tags_invalid_json (self ):
477
+ """Test parsing invalid JSON returns empty list"""
478
+ stack = HpClusterStack (tags = "invalid json" )
479
+
480
+ result = stack ._parse_tags ()
481
+
482
+ self .assertEqual (result , [])
483
+
484
+ def test_parse_tags_empty_json_array (self ):
485
+ """Test parsing empty JSON array returns empty list"""
486
+ stack = HpClusterStack (tags = "[]" )
487
+
488
+ result = stack ._parse_tags ()
489
+
490
+ self .assertEqual (result , [])
491
+
492
+
493
+ class TestHpClusterStackGetTemplate (unittest .TestCase ):
494
+ """Test HpClusterStack get_template method using package instead of S3"""
495
+
496
+ @patch ('sagemaker.hyperpod.cluster_management.hp_cluster_stack.importlib.resources.read_text' )
497
+ @patch ('sagemaker.hyperpod.cluster_management.hp_cluster_stack.yaml.safe_load' )
498
+ def test_get_template_from_package (self , mock_yaml_load , mock_read_text ):
499
+ """Test get_template reads from package instead of S3"""
500
+ mock_yaml_content = "Parameters:\n TestParam:\n Type: String"
501
+ mock_read_text .return_value = mock_yaml_content
502
+
503
+ mock_yaml_data = {"Parameters" : {"TestParam" : {"Type" : "String" }}}
504
+ mock_yaml_load .return_value = mock_yaml_data
505
+
506
+ result = HpClusterStack .get_template ()
507
+
508
+ # Verify package resource was read
509
+ mock_read_text .assert_called_once_with ('hyperpod_cluster_stack_template' , 'creation_template.yaml' )
510
+ mock_yaml_load .assert_called_once_with (mock_yaml_content )
511
+
512
+ # Verify JSON output
513
+ expected_json = json .dumps (mock_yaml_data , indent = 2 , ensure_ascii = False )
514
+ self .assertEqual (result , expected_json )
515
+
516
+ @patch ('sagemaker.hyperpod.cluster_management.hp_cluster_stack.importlib.resources.read_text' )
517
+ def test_get_template_handles_package_error (self , mock_read_text ):
518
+ """Test get_template handles package read errors"""
519
+ mock_read_text .side_effect = FileNotFoundError ("Template not found" )
520
+
521
+ with self .assertRaises (RuntimeError ) as context :
522
+ HpClusterStack .get_template ()
523
+
524
+ self .assertIn ("Failed to load template from package" , str (context .exception ))
0 commit comments