Skip to content

Commit d73f6ec

Browse files
[ADMINAPI-1421] feat: Create and Delete DbInstances jobs integrated into v3 (#349)
* [ADMINAPI-1421] Create and Delete DbInstances jobs integrated into v3 * [ADMINAPI-1421] fix: E2E tests fixed * [ADMINAPI-1421] fix: Copilot comments applied * [ADMINAPI-1421] fix: Removed location from Delete responses (v2 & v3) * [ADMINAPI-1421] 'SweepIntervalInMins' updated from 5 minutes to 2 hours * fix: Delete endpoint response code from 202 to 204 (v2 and v3)
1 parent 29dca81 commit d73f6ec

23 files changed

Lines changed: 3209 additions & 158 deletions

Application/EdFi.Ods.AdminApi.UnitTests/Features/DbInstances/DeleteDbInstanceTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ public async Task Handle_WhenStatusIsCreated_ExecutesCommandAndReturnsAccepted()
8888

8989
var result = await Handle(1);
9090

91-
result.ShouldBeOfType<Accepted>();
91+
result.ShouldBeOfType<NoContent>();
9292
A.CallTo(() => _deleteDbInstanceCommand.Execute(1)).MustHaveHappenedOnceExactly();
9393
}
9494

Application/EdFi.Ods.AdminApi.V3.UnitTests/Features/DbInstances/AddDbInstanceTests.cs

Lines changed: 302 additions & 22 deletions
Large diffs are not rendered by default.

Application/EdFi.Ods.AdminApi.V3.UnitTests/Features/DbInstances/DeleteDbInstanceTests.cs

Lines changed: 117 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,25 @@
33
// The Ed-Fi Alliance licenses this file to you under the Apache License, Version 2.0.
44
// See the LICENSE and NOTICES files in the project root for more information.
55

6+
using System;
7+
using System.Threading;
68
using System.Threading.Tasks;
79
using EdFi.Ods.AdminApi.Common.Constants;
10+
using EdFi.Ods.AdminApi.Common.Infrastructure.Context;
811
using EdFi.Ods.AdminApi.Common.Infrastructure.ErrorHandling;
912
using EdFi.Ods.AdminApi.Common.Infrastructure.Models;
13+
using EdFi.Ods.AdminApi.Common.Infrastructure.MultiTenancy;
14+
using EdFi.Ods.AdminApi.Common.Settings;
1015
using EdFi.Ods.AdminApi.V3.Features.DbInstances;
1116
using EdFi.Ods.AdminApi.V3.Infrastructure.Database.Commands;
1217
using EdFi.Ods.AdminApi.V3.Infrastructure.Database.Queries;
1318
using FakeItEasy;
1419
using FluentValidation;
20+
using Microsoft.AspNetCore.Http;
1521
using Microsoft.AspNetCore.Http.HttpResults;
22+
using Microsoft.Extensions.Options;
1623
using NUnit.Framework;
24+
using Quartz;
1725
using Shouldly;
1826

1927
#nullable enable
@@ -25,161 +33,226 @@ public class DeleteDbInstanceTests
2533
{
2634
private IGetDbInstanceByIdQuery _getDbInstanceByIdQuery = null!;
2735
private IDeleteDbInstanceCommand _deleteDbInstanceCommand = null!;
36+
private ISchedulerFactory _schedulerFactory = null!;
37+
private IContextProvider<TenantConfiguration> _tenantConfigurationProvider = null!;
38+
private IOptions<AppSettings> _options = null!;
2839

2940
[SetUp]
3041
public void SetUp()
3142
{
3243
_getDbInstanceByIdQuery = A.Fake<IGetDbInstanceByIdQuery>();
3344
_deleteDbInstanceCommand = A.Fake<IDeleteDbInstanceCommand>();
45+
46+
var scheduler = A.Fake<IScheduler>();
47+
A.CallTo(() => scheduler.ScheduleJob(A<IJobDetail>._, A<ITrigger>._, A<CancellationToken>._))
48+
.Returns(Task.FromResult(DateTimeOffset.UtcNow));
49+
50+
_schedulerFactory = A.Fake<ISchedulerFactory>();
51+
A.CallTo(() => _schedulerFactory.GetScheduler(A<CancellationToken>._))
52+
.Returns(Task.FromResult(scheduler));
53+
54+
_tenantConfigurationProvider = A.Fake<IContextProvider<TenantConfiguration>>();
55+
A.CallTo(() => _tenantConfigurationProvider.Get()).Returns(null);
56+
57+
_options = Options.Create(new AppSettings { DatabaseEngine = "SqlServer" });
3458
}
3559

60+
private Task<IResult> Handle(int id)
61+
=> DeleteDbInstance.Handle(
62+
_getDbInstanceByIdQuery,
63+
_deleteDbInstanceCommand,
64+
_schedulerFactory,
65+
_tenantConfigurationProvider,
66+
_options,
67+
id);
68+
3669
[Test]
3770
public async Task Handle_WhenDbInstanceNotFound_ThrowsNotFoundException()
3871
{
3972
A.CallTo(() => _getDbInstanceByIdQuery.Execute(99)).Returns(null);
4073

41-
await Should.ThrowAsync<NotFoundException<int>>(() =>
42-
DeleteDbInstance.Handle(_getDbInstanceByIdQuery, _deleteDbInstanceCommand, 99)
43-
);
74+
await Should.ThrowAsync<NotFoundException<int>>(() => Handle(99));
4475
}
4576

4677
[Test]
47-
public async Task Handle_WhenStatusIsPending_ThrowsValidationException()
78+
public async Task Handle_WhenStatusIsCreated_ExecutesCommandAndReturnsAccepted()
4879
{
4980
var dbInstance = new DbInstance
5081
{
5182
Id = 1,
5283
Name = "Test",
53-
Status = DbInstanceStatus.PendingCreate.ToString(),
84+
Status = DbInstanceStatus.Created.ToString(),
5485
DatabaseTemplate = "Minimal",
5586
};
5687
A.CallTo(() => _getDbInstanceByIdQuery.Execute(1)).Returns(dbInstance);
5788

58-
var ex = await Should.ThrowAsync<ValidationException>(() =>
59-
DeleteDbInstance.Handle(_getDbInstanceByIdQuery, _deleteDbInstanceCommand, 1)
60-
);
89+
var result = await Handle(1);
6190

62-
ex.Errors.ShouldContain(e => e.ErrorMessage.Contains("provisioned"));
63-
A.CallTo(() => _deleteDbInstanceCommand.Execute(A<int>._)).MustNotHaveHappened();
91+
result.ShouldBeOfType<NoContent>();
92+
A.CallTo(() => _deleteDbInstanceCommand.Execute(1)).MustHaveHappenedOnceExactly();
6493
}
6594

6695
[Test]
67-
public async Task Handle_WhenStatusIsInProgress_ThrowsValidationException()
96+
public async Task Handle_WhenStatusIsPendingCreate_ThrowsValidationException()
6897
{
6998
var dbInstance = new DbInstance
7099
{
71100
Id = 2,
72101
Name = "Test",
73-
Status = DbInstanceStatus.CreateInProgress.ToString(),
102+
Status = DbInstanceStatus.PendingCreate.ToString(),
74103
DatabaseTemplate = "Minimal",
75104
};
76105
A.CallTo(() => _getDbInstanceByIdQuery.Execute(2)).Returns(dbInstance);
77106

78-
var ex = await Should.ThrowAsync<ValidationException>(
79-
() => DeleteDbInstance.Handle(_getDbInstanceByIdQuery, _deleteDbInstanceCommand, 2)
80-
);
107+
var ex = await Should.ThrowAsync<ValidationException>(() => Handle(2));
81108

82109
ex.Errors.ShouldContain(e => e.ErrorMessage.Contains("provisioned"));
83110
A.CallTo(() => _deleteDbInstanceCommand.Execute(A<int>._)).MustNotHaveHappened();
84111
}
85112

86113
[Test]
87-
public async Task Handle_WhenStatusIsCompleted_ExecutesCommandAndReturnsNoContent()
114+
public async Task Handle_WhenStatusIsCreateInProgress_ThrowsValidationException()
88115
{
89116
var dbInstance = new DbInstance
90117
{
91118
Id = 3,
92119
Name = "Test",
93-
Status = DbInstanceStatus.Created.ToString(),
120+
Status = DbInstanceStatus.CreateInProgress.ToString(),
94121
DatabaseTemplate = "Minimal",
95122
};
96123
A.CallTo(() => _getDbInstanceByIdQuery.Execute(3)).Returns(dbInstance);
97124

98-
var result = await DeleteDbInstance.Handle(_getDbInstanceByIdQuery, _deleteDbInstanceCommand, 3);
125+
var ex = await Should.ThrowAsync<ValidationException>(() => Handle(3));
99126

100-
result.ShouldBeOfType<NoContent>();
101-
A.CallTo(() => _deleteDbInstanceCommand.Execute(3)).MustHaveHappenedOnceExactly();
127+
ex.Errors.ShouldContain(e => e.ErrorMessage.Contains("provisioned"));
128+
A.CallTo(() => _deleteDbInstanceCommand.Execute(A<int>._)).MustNotHaveHappened();
102129
}
103130

104131
[Test]
105-
public async Task Handle_WhenStatusIsDeleteFailed_ExecutesCommandAndReturnsNoContent()
132+
public async Task Handle_WhenStatusIsCreateFailed_ThrowsValidationException()
106133
{
107134
var dbInstance = new DbInstance
108135
{
109136
Id = 4,
110137
Name = "Test",
111-
Status = DbInstanceStatus.DeleteFailed.ToString(),
138+
Status = DbInstanceStatus.CreateFailed.ToString(),
112139
DatabaseTemplate = "Minimal",
113140
};
114141
A.CallTo(() => _getDbInstanceByIdQuery.Execute(4)).Returns(dbInstance);
115142

116-
var result = await DeleteDbInstance.Handle(_getDbInstanceByIdQuery, _deleteDbInstanceCommand, 4);
143+
var ex = await Should.ThrowAsync<ValidationException>(() => Handle(4));
117144

118-
result.ShouldBeOfType<NoContent>();
119-
A.CallTo(() => _deleteDbInstanceCommand.Execute(4)).MustHaveHappenedOnceExactly();
145+
ex.Errors.ShouldContain(e => e.ErrorMessage.Contains("creation failed"));
146+
A.CallTo(() => _deleteDbInstanceCommand.Execute(A<int>._)).MustNotHaveHappened();
120147
}
121148

122149
[Test]
123-
public async Task Handle_WhenStatusIsPendingDelete_ThrowsValidationException()
150+
public async Task Handle_WhenStatusIsCreateError_ThrowsValidationException()
124151
{
125152
var dbInstance = new DbInstance
126153
{
127154
Id = 5,
128155
Name = "Test",
129-
Status = DbInstanceStatus.PendingDelete.ToString(),
156+
Status = DbInstanceStatus.CreateError.ToString(),
130157
DatabaseTemplate = "Minimal",
131158
};
132159
A.CallTo(() => _getDbInstanceByIdQuery.Execute(5)).Returns(dbInstance);
133160

134-
var ex = await Should.ThrowAsync<ValidationException>(() =>
135-
DeleteDbInstance.Handle(_getDbInstanceByIdQuery, _deleteDbInstanceCommand, 5)
136-
);
161+
var ex = await Should.ThrowAsync<ValidationException>(() => Handle(5));
137162

138-
ex.Errors.ShouldContain(e => e.ErrorMessage.Contains("queued for deletion"));
163+
ex.Errors.ShouldContain(e => e.ErrorMessage.Contains("creation failed permanently"));
139164
A.CallTo(() => _deleteDbInstanceCommand.Execute(A<int>._)).MustNotHaveHappened();
140165
}
141166

142167
[Test]
143-
public async Task Handle_WhenStatusIsError_ThrowsValidationException()
168+
public async Task Handle_WhenStatusIsPendingDelete_ThrowsValidationException()
144169
{
145170
var dbInstance = new DbInstance
146171
{
147172
Id = 6,
148173
Name = "Test",
149-
Status = DbInstanceStatus.CreateError.ToString(),
174+
Status = DbInstanceStatus.PendingDelete.ToString(),
150175
DatabaseTemplate = "Minimal",
151176
};
152177
A.CallTo(() => _getDbInstanceByIdQuery.Execute(6)).Returns(dbInstance);
153178

154-
var ex = await Should.ThrowAsync<ValidationException>(() =>
155-
DeleteDbInstance.Handle(_getDbInstanceByIdQuery, _deleteDbInstanceCommand, 6)
156-
);
179+
var ex = await Should.ThrowAsync<ValidationException>(() => Handle(6));
157180

158-
ex.Errors.ShouldContain(e => e.ErrorMessage.Contains("error during provisioning"));
181+
ex.Errors.ShouldContain(e => e.ErrorMessage.Contains("queued for deletion"));
159182
A.CallTo(() => _deleteDbInstanceCommand.Execute(A<int>._)).MustNotHaveHappened();
160183
}
161184

162185
[Test]
163-
public async Task Handle_WhenStatusIsDeleted_ThrowsNotFoundException()
186+
public async Task Handle_WhenStatusIsDeleteInProgress_ThrowsValidationException()
164187
{
165188
var dbInstance = new DbInstance
166189
{
167190
Id = 7,
168191
Name = "Test",
169-
Status = DbInstanceStatus.Deleted.ToString(),
192+
Status = DbInstanceStatus.DeleteInProgress.ToString(),
170193
DatabaseTemplate = "Minimal",
171194
};
172195
A.CallTo(() => _getDbInstanceByIdQuery.Execute(7)).Returns(dbInstance);
173196

174-
await Should.ThrowAsync<NotFoundException<int>>(() =>
175-
DeleteDbInstance.Handle(_getDbInstanceByIdQuery, _deleteDbInstanceCommand, 7)
176-
);
197+
var ex = await Should.ThrowAsync<ValidationException>(() => Handle(7));
177198

199+
ex.Errors.ShouldContain(e => e.ErrorMessage.Contains("currently being deleted"));
178200
A.CallTo(() => _deleteDbInstanceCommand.Execute(A<int>._)).MustNotHaveHappened();
179201
}
180-
}
181202

182-
#nullable restore
203+
[Test]
204+
public async Task Handle_WhenStatusIsDeleteFailed_ThrowsValidationException()
205+
{
206+
var dbInstance = new DbInstance
207+
{
208+
Id = 8,
209+
Name = "Test",
210+
Status = DbInstanceStatus.DeleteFailed.ToString(),
211+
DatabaseTemplate = "Minimal",
212+
};
213+
A.CallTo(() => _getDbInstanceByIdQuery.Execute(8)).Returns(dbInstance);
214+
215+
var ex = await Should.ThrowAsync<ValidationException>(() => Handle(8));
216+
217+
ex.Errors.ShouldContain(e => e.ErrorMessage.Contains("retried automatically"));
218+
A.CallTo(() => _deleteDbInstanceCommand.Execute(A<int>._)).MustNotHaveHappened();
219+
}
220+
221+
[Test]
222+
public async Task Handle_WhenStatusIsDeleteError_ThrowsValidationException()
223+
{
224+
var dbInstance = new DbInstance
225+
{
226+
Id = 9,
227+
Name = "Test",
228+
Status = DbInstanceStatus.DeleteError.ToString(),
229+
DatabaseTemplate = "Minimal",
230+
};
231+
A.CallTo(() => _getDbInstanceByIdQuery.Execute(9)).Returns(dbInstance);
183232

233+
var ex = await Should.ThrowAsync<ValidationException>(() => Handle(9));
184234

235+
ex.Errors.ShouldContain(e => e.ErrorMessage.Contains("deletion failed permanently"));
236+
A.CallTo(() => _deleteDbInstanceCommand.Execute(A<int>._)).MustNotHaveHappened();
237+
}
238+
239+
[Test]
240+
public async Task Handle_WhenStatusIsDeleted_ThrowsNotFoundException()
241+
{
242+
var dbInstance = new DbInstance
243+
{
244+
Id = 10,
245+
Name = "Test",
246+
Status = DbInstanceStatus.Deleted.ToString(),
247+
DatabaseTemplate = "Minimal",
248+
};
249+
A.CallTo(() => _getDbInstanceByIdQuery.Execute(10)).Returns(dbInstance);
250+
251+
await Should.ThrowAsync<NotFoundException<int>>(() => Handle(10));
252+
253+
A.CallTo(() => _deleteDbInstanceCommand.Execute(A<int>._)).MustNotHaveHappened();
254+
}
255+
}
256+
257+
#nullable restore
185258

0 commit comments

Comments
 (0)