@@ -59,23 +59,35 @@ def test_delete(self, stack, store):
5959 h .wait (h .SHORT_DELAY )
6060
6161
62- def _environment_names (stack ):
63- resp = stack .environments ().find ()
64- h .assert_status (resp , 200 )
65- return [env ["name" ] for env in h .body (resp ).get ("environments" , [])]
62+ def _create_branch (stack , uid , environments = None ):
63+ branch = {"uid" : uid , "source" : "main" }
64+ if environments is not None :
65+ branch ["publish_config" ] = {"environments" : environments }
66+ return stack .branch ().create ({"branch" : branch })
6667
6768
68- def _create_with_environments (stack , uid , environments ):
69- data = {"branch" : {"uid" : uid , "source" : "main" , "publish_config" : {"environments" : environments }}}
70- return stack .branch ().create (data )
69+ def _branch (response ):
70+ return h .body (response ).get ("branch" , {})
7171
7272
7373def _branch_environments (response ):
74- return h .body (response ).get ("branch" , {}).get ("publish_config" , {}).get ("environments" )
74+ return (_branch (response ).get ("publish_config" ) or {}).get ("environments" )
75+
76+
77+ def _fetch_when_ready (stack , uid ):
78+ # Branch provisioning is async: poll until the fetch succeeds
79+ resp = None
80+ for _ in range (10 ):
81+ resp = stack .branch (uid ).fetch ()
82+ if resp .status_code == 200 :
83+ return resp
84+ h .wait (h .SHORT_DELAY )
85+ return resp
7586
7687
7788def _delete_created_branch (stack , uid ):
7889 # Same retry as TestBranchDelete: a freshly created branch can briefly be "not valid" (422, code 905).
90+ resp = None
7991 for _ in range (4 ):
8092 branch = stack .branch (uid )
8193 branch .add_param ("force" , "true" )
@@ -86,54 +98,99 @@ def _delete_created_branch(stack, uid):
8698 raise AssertionError (f"branch { uid } was not deleted after retries; status { resp .status_code } " )
8799
88100
101+ def _not_found (response ):
102+ return response .status_code , h .body (response ).get ("error_code" )
103+
104+
105+ @pytest .fixture (scope = "class" )
106+ def env_names (stack ):
107+ """Three environments of this class, so a list of two is a strict subset; deleted after."""
108+ names = [h .generate_valid_uid ("bev" ) for _ in range (3 )]
109+ for name in names :
110+ data = {"environment" : {"name" : name , "urls" : [{"url" : "https://example.com" , "locale" : "en-us" }]}}
111+ h .assert_status (stack .environments ().create (data ), 201 )
112+ yield names
113+ for name in names :
114+ stack .environments (name ).delete ()
115+
116+
117+ @pytest .fixture (scope = "class" )
118+ def nonexistent (stack ):
119+ """The response for a branch that does not exist (dev11: 422, error_code 905)."""
120+ resp = stack .branch (h .generate_valid_uid ("nob" )).fetch ()
121+ assert resp .status_code != 200
122+ return _not_found (resp )
123+
124+
89125class TestBranchEnvironmentList :
90126 """Branch create with publish_config.environments. Each test deletes its branch (stack branch cap)."""
91127
92- def test_create_two_names_clones_only_those (self , stack ):
93- names = _environment_names (stack )
94- if len (names ) < 2 :
95- pytest .skip ("stack has fewer than two environments" )
96- wanted = names [:2 ]
97- uid = h .generate_valid_uid ("branch_env" )
98- resp = _create_with_environments (stack , uid , wanted )
128+ def test_create_two_names_clones_only_those (self , stack , env_names ):
129+ wanted = env_names [:2 ]
130+ uid = h .generate_valid_uid ("bev" )
131+ resp = _create_branch (stack , uid , wanted )
99132 try :
100133 h .assert_status (resp , 201 )
101- assert _branch_environments (resp ) == wanted
102- h .wait (h .LONG_DELAY )
103- fetched = stack .branch (uid ).fetch ()
134+ assert sorted (_branch_environments (resp )) == sorted (wanted )
135+ fetched = _fetch_when_ready (stack , uid )
136+ h .assert_status (fetched , 200 )
137+ assert sorted (_branch_environments (fetched )) == sorted (wanted )
138+ assert env_names [2 ] not in _branch_environments (fetched )
139+ finally :
140+ if resp .status_code == 201 :
141+ _delete_created_branch (stack , uid )
142+
143+ def test_create_one_name_reads_back_that_one (self , stack , env_names ):
144+ uid = h .generate_valid_uid ("bev" )
145+ resp = _create_branch (stack , uid , env_names [:1 ])
146+ try :
147+ h .assert_status (resp , 201 )
148+ fetched = _fetch_when_ready (stack , uid )
104149 h .assert_status (fetched , 200 )
105- assert _branch_environments (fetched ) == wanted
150+ assert _branch_environments (fetched ) == env_names [: 1 ]
106151 finally :
107152 if resp .status_code == 201 :
108153 _delete_created_branch (stack , uid )
109154
110- def test_create_empty_list_clones_none (self , stack ):
111- uid = h .generate_valid_uid ("branch_env " )
112- resp = _create_with_environments (stack , uid , [])
155+ def test_create_empty_list_clones_none (self , stack , env_names ):
156+ uid = h .generate_valid_uid ("bev " )
157+ resp = _create_branch (stack , uid , [])
113158 try :
114159 h .assert_status (resp , 201 )
115160 assert _branch_environments (resp ) == []
116- h .wait (h .LONG_DELAY )
117- fetched = stack .branch (uid ).fetch ()
161+ fetched = _fetch_when_ready (stack , uid )
118162 h .assert_status (fetched , 200 )
163+ assert "publish_config" in _branch (fetched )
119164 assert _branch_environments (fetched ) == []
120165 finally :
121166 if resp .status_code == 201 :
122167 _delete_created_branch (stack , uid )
123168
124- def test_unknown_name_returns_422_and_creates_no_branch (self , stack ):
125- uid = h .generate_valid_uid ("branch_env" )
126- resp = _create_with_environments (stack , uid , ["no_such_env_for_integration" ])
127- h .assert_status (resp , 422 )
128- assert "publish_config.environments" in h .body (resp ).get ("errors" , {})
129- h .assert_status (stack .branch (uid ).fetch (), 404 )
130-
131- def test_mix_of_valid_and_unknown_names_returns_422_and_creates_no_branch (self , stack ):
132- names = _environment_names (stack )
133- if not names :
134- pytest .skip ("stack has no environments" )
135- uid = h .generate_valid_uid ("branch_env" )
136- resp = _create_with_environments (stack , uid , [names [0 ], "no_such_env_for_integration" ])
169+ def test_create_without_list_reads_back_no_publish_config (self , stack , env_names ):
170+ uid = h .generate_valid_uid ("bev" )
171+ resp = _create_branch (stack , uid )
172+ try :
173+ h .assert_status (resp , 201 )
174+ fetched = _fetch_when_ready (stack , uid )
175+ h .assert_status (fetched , 200 )
176+ assert "publish_config" not in _branch (fetched )
177+ finally :
178+ if resp .status_code == 201 :
179+ _delete_created_branch (stack , uid )
180+
181+ @pytest .mark .parametrize ("case" , ["unknown" , "other_case" , "mix" ])
182+ def test_rejected_names_return_422_and_create_no_branch (self , stack , env_names , nonexistent , case ):
183+ environments = {
184+ "unknown" : [h .generate_valid_uid ("nos" )],
185+ "other_case" : [env_names [0 ].upper ()],
186+ "mix" : [env_names [0 ], h .generate_valid_uid ("nos" )],
187+ }[case ]
188+ uid = h .generate_valid_uid ("bev" )
189+ resp = _create_branch (stack , uid , environments )
190+ fetched = stack .branch (uid ).fetch ()
191+ if fetched .status_code == 200 :
192+ _delete_created_branch (stack , uid )
137193 h .assert_status (resp , 422 )
194+ assert h .body (resp ).get ("error_message" )
138195 assert "publish_config.environments" in h .body (resp ).get ("errors" , {})
139- h . assert_status ( stack . branch ( uid ). fetch (), 404 )
196+ assert _not_found ( fetched ) == nonexistent , "a rejected create must leave no branch behind"
0 commit comments