Skip to content

Commit a2bef0b

Browse files
wbrezaCopilot
andcommitted
fix: Defensive factory cleanup on registration failure + VirtualEnv test
- Delete factory from map if SendAndWait fails, enabling retry with same name - Add VirtualEnv test case to convertToProtoOptions coverage Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 932af94 commit a2bef0b

File tree

2 files changed

+35
-5
lines changed

2 files changed

+35
-5
lines changed

cli/azd/internal/grpcserver/external_provisioning_provider_test.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,26 @@ func Test_convertToProtoOptions(t *testing.T) {
8989
assert.Nil(t, result.Config)
9090
},
9191
},
92+
{
93+
name: "OptionsWithVirtualEnv",
94+
options: provisioning.Options{
95+
Provider: provisioning.Bicep,
96+
Path: "infra",
97+
VirtualEnv: map[string]string{
98+
"LAYER1_OUTPUT": "value1",
99+
"LAYER1_ENDPOINT": "https://example.com",
100+
},
101+
},
102+
verify: func(t *testing.T, result *azdext.ProvisioningOptions, err error) {
103+
require.NoError(t, err)
104+
require.NotNil(t, result)
105+
assert.Equal(t, "bicep", result.Provider)
106+
assert.Equal(t, "infra", result.Path)
107+
require.Len(t, result.VirtualEnv, 2)
108+
assert.Equal(t, "value1", result.VirtualEnv["LAYER1_OUTPUT"])
109+
assert.Equal(t, "https://example.com", result.VirtualEnv["LAYER1_ENDPOINT"])
110+
},
111+
},
92112
}
93113

94114
for _, tt := range tests {

cli/azd/pkg/azdext/provisioning_manager.go

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -188,29 +188,39 @@ func (m *ProvisioningManager) Register(
188188
},
189189
}
190190

191+
// Store factory before RPC so the duplicate check works for concurrent calls.
192+
m.mu.Lock()
193+
m.factories[providerName] = factory
194+
m.mu.Unlock()
195+
191196
resp, err := m.broker.SendAndWait(ctx, registerReq)
192197
if err != nil {
198+
// Clean up factory so the same name can be retried
199+
m.mu.Lock()
200+
delete(m.factories, providerName)
201+
m.mu.Unlock()
193202
return fmt.Errorf(
194203
"provisioning provider registration failed: %w", err,
195204
)
196205
}
197206

198207
if resp == nil {
208+
m.mu.Lock()
209+
delete(m.factories, providerName)
210+
m.mu.Unlock()
199211
return fmt.Errorf("provisioning provider registration: received nil response")
200212
}
201213

202214
if resp.GetRegisterProvisioningProviderResponse() == nil {
215+
m.mu.Lock()
216+
delete(m.factories, providerName)
217+
m.mu.Unlock()
203218
return fmt.Errorf(
204219
"expected RegisterProvisioningProviderResponse, got %T",
205220
resp.GetMessageType(),
206221
)
207222
}
208223

209-
// Store factory ONLY after successful registration
210-
m.mu.Lock()
211-
m.factories[providerName] = factory
212-
m.mu.Unlock()
213-
214224
return nil
215225
}
216226

0 commit comments

Comments
 (0)