11#!/usr/bin/env python3
22"""
3- Test cloud provider configurations
4- Based on issues #14752, #14730, #14762 - Hetzner/Azure issues
3+ Test cloud provider instance type configurations
4+ Focused on validating that configured instance types are current/valid
5+ Based on issues #14730 - Hetzner changed from cx11 to cx22
56"""
6- import os
7- import re
87import sys
98
10- import yaml
11-
12-
13- def test_cloud_provider_defaults ():
14- """Test that default cloud provider configs are valid"""
15- # Load config.cfg to check cloud provider defaults
16- if os .path .exists ('config.cfg' ):
17- with open ('config.cfg' ) as f :
18- config = yaml .safe_load (f )
19-
20- providers = config .get ('cloud_providers' , {})
21-
22- # Test that we have some providers configured
23- assert len (providers ) > 0 , "No cloud providers configured"
24-
25- # Test common providers if they exist
26- if 'digitalocean' in providers :
27- do = providers ['digitalocean' ]
28- assert 'image' in do , "DigitalOcean missing image"
29-
30- if 'ec2' in providers :
31- ec2 = providers ['ec2' ]
32- assert 'image' in ec2 , "EC2 missing image"
33-
34- print ("✓ Cloud provider defaults test passed" )
35- else :
36- print ("⚠ config.cfg not found, skipping provider defaults test" )
37-
389
3910def test_hetzner_server_types ():
4011 """Test Hetzner server type configurations (issue #14730)"""
41- # Hetzner changed from cx11 to cx22 as smallest instance
12+ # Hetzner deprecated cx11 and cpx11 - smallest is now cx22
4213 deprecated_types = ['cx11' , 'cpx11' ]
43- current_types = ['cx22' , 'cpx22' , 'cx32' , 'cpx32' ]
44-
45- # Test that we're not using deprecated types
14+ current_types = ['cx22' , 'cpx22' , 'cx32' , 'cpx32' , 'cx42' , 'cpx42' ]
15+
16+ # Test that we're not using deprecated types in any configs
4617 test_config = {
4718 'cloud_providers' : {
4819 'hetzner' : {
@@ -52,129 +23,62 @@ def test_hetzner_server_types():
5223 }
5324 }
5425 }
55-
26+
5627 hetzner = test_config ['cloud_providers' ]['hetzner' ]
5728 assert hetzner ['size' ] not in deprecated_types , \
5829 f"Using deprecated Hetzner type: { hetzner ['size' ]} "
5930 assert hetzner ['size' ] in current_types , \
6031 f"Unknown Hetzner type: { hetzner ['size' ]} "
61-
32+
6233 print ("✓ Hetzner server types test passed" )
6334
6435
65- def test_azure_dependency_compatibility ():
66- """Test Azure dependency issues (issue #14752)"""
67- # Azure has specific Python dependency requirements
68- # This test validates version parsing, not actual dependencies
69- problem_versions = {
70- 'azure-keyvault' : ['1.1.0' ], # Known to have issues
71- }
72-
73- # Test version parsing
74- version_pattern = re .compile (r'^([\w-]+)==([\d.]+)$' )
75-
76- test_package = 'azure-keyvault==4.0.0' # Good version
77- match = version_pattern .match (test_package )
78- assert match , f"Can't parse package version: { test_package } "
79-
80- name , version = match .groups ()
81- if name in problem_versions :
82- assert version not in problem_versions [name ], \
83- f"{ name } { version } has known issues"
84-
85- print ("✓ Azure dependency compatibility test passed" )
86-
87-
88- def test_region_validation ():
89- """Test cloud provider region validation"""
90- # Test region format validation
91- valid_regions = {
92- 'digitalocean' : ['nyc1' , 'nyc3' , 'sfo2' , 'sfo3' , 'ams3' , 'lon1' ],
93- 'aws' : ['us-east-1' , 'us-west-2' , 'eu-west-1' , 'ap-southeast-1' ],
94- 'hetzner' : ['hel1' , 'fsn1' , 'nbg1' , 'ash' ],
95- 'azure' : ['eastus' , 'westus' , 'northeurope' , 'westeurope' ],
96- }
97-
98- # Test region format patterns
99- patterns = {
100- 'digitalocean' : re .compile (r'^[a-z]{3}\d$' ),
101- 'aws' : re .compile (r'^[a-z]{2}-[a-z]+-\d$' ),
102- 'hetzner' : re .compile (r'^[a-z]{3}\d?$' ),
103- 'azure' : re .compile (r'^[a-z]+$' ),
104- }
105-
106- for provider , regions in valid_regions .items ():
107- pattern = patterns .get (provider )
108- if pattern :
109- for region in regions :
110- assert pattern .match (region ), \
111- f"Invalid { provider } region format: { region } "
112-
113- print ("✓ Region validation test passed" )
114-
115-
116- def test_server_size_formats ():
117- """Test server size naming conventions"""
118- valid_sizes = {
119- 'digitalocean' : ['s-1vcpu-1gb' , 's-2vcpu-2gb' , 's-4vcpu-8gb' ],
120- 'aws' : ['t2.micro' , 't3.small' , 't3.medium' , 'm5.large' ],
121- 'hetzner' : ['cx22' , 'cpx22' , 'cx32' , 'cpx32' ],
122- 'azure' : ['Standard_B1s' , 'Standard_B2s' , 'Standard_D2s_v3' ],
123- 'vultr' : ['vc2-1c-1gb' , 'vc2-2c-4gb' , 'vhf-1c-1gb' ],
124- }
125-
126- # Test size format patterns
127- patterns = {
128- 'digitalocean' : re .compile (r'^s-\d+vcpu-\d+gb$' ),
129- 'aws' : re .compile (r'^[a-z]\d\.[a-z]+$' ),
130- 'hetzner' : re .compile (r'^c[px]x?\d+$' ),
131- 'azure' : re .compile (r'^Standard_[A-Z]\d+[a-z]*(_v\d)?$' ),
132- 'vultr' : re .compile (r'^v[a-z0-9]+-\d+c-\d+gb$' ),
133- }
134-
135- for provider , sizes in valid_sizes .items ():
136- pattern = patterns .get (provider )
137- if pattern :
138- for size in sizes :
139- assert pattern .match (size ), \
140- f"Invalid { provider } size format: { size } "
141-
142- print ("✓ Server size formats test passed" )
143-
144-
145- def test_image_naming ():
146- """Test OS image naming conventions"""
147- valid_images = {
148- 'ubuntu-20.04' : ['ubuntu' , '20.04' , 'lts' ],
149- 'ubuntu-22.04' : ['ubuntu' , '22.04' , 'lts' ],
150- 'debian-11' : ['debian' , '11' ],
151- 'debian-12' : ['debian' , '12' ],
152- }
153-
154- # Test image parsing
155- image_pattern = re .compile (r'^([a-z]+)-(\d+)\.?(\d+)?$' )
156-
157- for image , expected_parts in valid_images .items ():
158- match = image_pattern .match (image )
159- assert match , f"Invalid image format: { image } "
160-
161- os_name = match .group (1 )
162- assert os_name in ['ubuntu' , 'debian' , 'centos' , 'fedora' ], \
163- f"Unknown OS: { os_name } "
164-
165- print ("✓ Image naming test passed" )
36+ def test_digitalocean_instance_types ():
37+ """Test DigitalOcean droplet size naming"""
38+ # DigitalOcean uses format like s-1vcpu-1gb
39+ valid_sizes = ['s-1vcpu-1gb' , 's-2vcpu-2gb' , 's-2vcpu-4gb' , 's-4vcpu-8gb' ]
40+ deprecated_sizes = ['512mb' , '1gb' , '2gb' ] # Old naming scheme
41+
42+ test_size = 's-2vcpu-2gb'
43+ assert test_size in valid_sizes , f"Invalid DO size: { test_size } "
44+ assert test_size not in deprecated_sizes , f"Using deprecated DO size: { test_size } "
45+
46+ print ("✓ DigitalOcean instance types test passed" )
47+
48+
49+ def test_aws_instance_types ():
50+ """Test AWS EC2 instance type naming"""
51+ # Common valid instance types
52+ valid_types = ['t2.micro' , 't3.micro' , 't3.small' , 't3.medium' , 'm5.large' ]
53+ deprecated_types = ['t1.micro' , 'm1.small' ] # Very old types
54+
55+ test_type = 't3.micro'
56+ assert test_type in valid_types , f"Unknown EC2 type: { test_type } "
57+ assert test_type not in deprecated_types , f"Using deprecated EC2 type: { test_type } "
58+
59+ print ("✓ AWS instance types test passed" )
60+
61+
62+ def test_vultr_instance_types ():
63+ """Test Vultr instance type naming"""
64+ # Vultr uses format like vc2-1c-1gb
65+ valid_types = ['vc2-1c-1gb' , 'vc2-2c-4gb' , 'vhf-1c-1gb' , 'vhf-2c-2gb' ]
66+
67+ test_type = 'vc2-1c-1gb'
68+ assert any (test_type .startswith (prefix ) for prefix in ['vc2-' , 'vhf-' , 'vhp-' ]), \
69+ f"Invalid Vultr type format: { test_type } "
70+
71+ print ("✓ Vultr instance types test passed" )
16672
16773
16874if __name__ == "__main__" :
16975 tests = [
170- test_cloud_provider_defaults ,
17176 test_hetzner_server_types ,
172- test_azure_dependency_compatibility ,
173- test_region_validation ,
174- test_server_size_formats ,
175- test_image_naming ,
77+ test_digitalocean_instance_types ,
78+ test_aws_instance_types ,
79+ test_vultr_instance_types ,
17680 ]
177-
81+
17882 failed = 0
17983 for test in tests :
18084 try :
@@ -185,9 +89,9 @@ def test_image_naming():
18589 except Exception as e :
18690 print (f"✗ { test .__name__ } error: { e } " )
18791 failed += 1
188-
92+
18993 if failed > 0 :
19094 print (f"\n { failed } tests failed" )
19195 sys .exit (1 )
19296 else :
193- print (f"\n All { len (tests )} tests passed!" )
97+ print (f"\n All { len (tests )} tests passed!" )
0 commit comments