Skip to content
This repository was archived by the owner on Jul 28, 2025. It is now read-only.

Commit cdfea60

Browse files
test: Updated unit tests for FileExtractFunction
1 parent a11ea60 commit cdfea60

File tree

2 files changed

+140
-18
lines changed

2 files changed

+140
-18
lines changed

src/ServiceLayer.Mesh/Functions/FileExtractFunction.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using Google.Protobuf.WellKnownTypes;
12
using Microsoft.Azure.Functions.Worker;
23
using Microsoft.EntityFrameworkCore;
34
using Microsoft.Extensions.Logging;
@@ -77,7 +78,7 @@ private bool IsFileSuitableForExtraction(MeshFile file)
7778
"File with id: {fileId} found in MeshFiles table but is not suitable for extraction. Status: {status}, LastUpdatedUtc: {lastUpdatedUtc}.",
7879
file.FileId,
7980
file.Status,
80-
file.LastUpdatedUtc);
81+
file.LastUpdatedUtc.ToTimestamp());
8182
return false;
8283
}
8384
return true;

tests/ServiceLayer.Mesh.Tests/Functions/FileExtractFunctionTests.cs

Lines changed: 138 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using System.Globalization;
2+
using Google.Protobuf.WellKnownTypes;
13
using Microsoft.EntityFrameworkCore;
24
using Microsoft.Extensions.Logging;
35
using Moq;
@@ -89,7 +91,7 @@ public async Task Run_FileNotFound_ExitsSilently()
8991
}
9092

9193
[Fact]
92-
public async Task Run_FileInInvalidStatus_ExitsSilently()
94+
public async Task Run_FileStatusInvalid_ExitsSilently()
9395
{
9496
// Arrange
9597
var file = new MeshFile
@@ -113,7 +115,7 @@ public async Task Run_FileInInvalidStatus_ExitsSilently()
113115
x => x.Log(
114116
LogLevel.Warning,
115117
It.IsAny<EventId>(),
116-
It.Is<It.IsAnyType>((v, t) => v.ToString().StartsWith($"File with id: {message.FileId} found in MeshFiles table but is not suitable for extraction. Status: {file.Status}, LastUpdatedUtc:")),
118+
It.Is<It.IsAnyType>((v, t) => v.ToString() == $"File with id: {message.FileId} found in MeshFiles table but is not suitable for extraction. Status: {file.Status}, LastUpdatedUtc: {file.LastUpdatedUtc.ToTimestamp()}."),
117119
null,
118120
It.IsAny<Func<It.IsAnyType, Exception?, string>>()
119121
), Times.Once);
@@ -133,8 +135,9 @@ public async Task Run_FileInInvalidStatus_ExitsSilently()
133135
}
134136

135137
[Fact]
136-
public async Task Run_FileExtractingButNotTimedOut_ExitsSilently()
138+
public async Task Run_FileStatusExtractingButNotTimedOut_ExitsSilently()
137139
{
140+
// Arrange
138141
var file = new MeshFile
139142
{
140143
FileType = MeshFileType.NbssAppointmentEvents,
@@ -148,28 +151,53 @@ public async Task Run_FileExtractingButNotTimedOut_ExitsSilently()
148151

149152
var message = new FileExtractQueueMessage { FileId = "file-2" };
150153

151-
var exception = await Assert.ThrowsAsync<InvalidOperationException>(() => _function.Run(message));
152-
Assert.Equal("File is not in expected status", exception.Message);
154+
// Act
155+
await _function.Run(message);
156+
157+
// Assert
158+
_loggerMock.Verify(
159+
x => x.Log(
160+
LogLevel.Warning,
161+
It.IsAny<EventId>(),
162+
It.Is<It.IsAnyType>((v, t) => v.ToString() == $"File with id: {message.FileId} found in MeshFiles table but is not suitable for extraction. Status: {file.Status}, LastUpdatedUtc: {file.LastUpdatedUtc.ToTimestamp()}."),
163+
null,
164+
It.IsAny<Func<It.IsAnyType, Exception?, string>>()
165+
), Times.Once);
166+
_loggerMock.Verify(
167+
x => x.Log(
168+
LogLevel.Warning,
169+
It.IsAny<EventId>(),
170+
It.Is<It.IsAnyType>((v, t) => v.ToString() == "Exiting function."),
171+
null,
172+
It.IsAny<Func<It.IsAnyType, Exception?, string>>()
173+
), Times.Once);
174+
175+
_meshInboxServiceMock.Verify(x => x.GetHeadMessageByIdAsync(It.IsAny<string>(), It.IsAny<string>()), Times.Never);
176+
_blobStoreMock.Verify(x => x.UploadAsync(It.IsAny<MeshFile>(), It.IsAny<byte[]>()), Times.Never);
177+
_fileTransformQueueClientMock.Verify(x => x.EnqueueFileTransformAsync(It.IsAny<MeshFile>()), Times.Never);
178+
_fileTransformQueueClientMock.Verify(x => x.SendToPoisonQueueAsync(It.IsAny<FileTransformQueueMessage>()), Times.Never);
153179
}
154180

155181
[Fact]
156-
public async Task Run_FileExtractSuccess_UploadsBlob()
182+
public async Task Run_FileValid_FileUploadedToBlobAndAcknowledgedAndEnqueued()
157183
{
158-
var fileId = "file-3";
184+
// Arrange
185+
var originalLastUpdatedUtc = DateTime.UtcNow.AddHours(-1);
159186
var file = new MeshFile
160187
{
161188
FileType = MeshFileType.NbssAppointmentEvents,
162189
MailboxId = "test-mailbox",
163-
FileId = fileId,
190+
FileId = "file-3",
164191
Status = MeshFileStatus.Discovered,
165-
LastUpdatedUtc = DateTime.UtcNow.AddHours(-1)
192+
LastUpdatedUtc = originalLastUpdatedUtc
166193
};
167194
_dbContext.MeshFiles.Add(file);
168195
await _dbContext.SaveChangesAsync();
169196

170197
var content = new byte[] { 1, 2, 3 };
198+
const string blobPath = "directory/fileName";
171199

172-
_meshInboxServiceMock.Setup(s => s.GetMessageByIdAsync("test-mailbox", fileId))
200+
_meshInboxServiceMock.Setup(s => s.GetMessageByIdAsync(file.MailboxId, file.FileId))
173201
.ReturnsAsync(new MeshResponse<GetMessageResponse>
174202
{
175203
IsSuccessful = true,
@@ -178,38 +206,131 @@ public async Task Run_FileExtractSuccess_UploadsBlob()
178206
FileAttachment = new FileAttachment { Content = content }
179207
}
180208
});
209+
_blobStoreMock.Setup(s => s.UploadAsync(file, content)).ReturnsAsync(blobPath);
210+
_meshInboxServiceMock.Setup(s => s.AcknowledgeMessageByIdAsync(file.MailboxId, file.FileId))
211+
.ReturnsAsync(new MeshResponse<AcknowledgeMessageResponse>
212+
{
213+
IsSuccessful = true
214+
});
215+
216+
var message = new FileExtractQueueMessage { FileId = file.FileId };
217+
218+
// Act
219+
await _function.Run(message);
220+
221+
// Assert
222+
_blobStoreMock.Verify(b => b.UploadAsync(It.Is<MeshFile>(f => f.FileId == file.FileId), content), Times.Once);
223+
_meshInboxServiceMock.Verify(m => m.AcknowledgeMessageByIdAsync(file.MailboxId, file.FileId), Times.Once);
224+
_fileTransformQueueClientMock.Verify(q => q.EnqueueFileTransformAsync(file), Times.Once);
225+
var updatedFile = _dbContext.MeshFiles.First();
226+
Assert.Equal(blobPath, updatedFile.BlobPath);
227+
Assert.Equal(MeshFileStatus.Extracted, updatedFile.Status);
228+
Assert.True(updatedFile.LastUpdatedUtc > originalLastUpdatedUtc);
229+
}
230+
231+
[Fact]
232+
public async Task Run_GetMessageFails_ErrorLoggedAndFileSentToPoisonQueue()
233+
{
234+
// Arrange
235+
var fileId = "file-4";
236+
var originalLastUpdatedUtc = DateTime.UtcNow.AddHours(-1);
237+
var file = new MeshFile
238+
{
239+
FileType = MeshFileType.NbssAppointmentEvents,
240+
MailboxId = "test-mailbox",
241+
FileId = fileId,
242+
Status = MeshFileStatus.Discovered,
243+
LastUpdatedUtc = originalLastUpdatedUtc
244+
};
245+
_dbContext.MeshFiles.Add(file);
246+
await _dbContext.SaveChangesAsync();
247+
248+
_meshInboxServiceMock.Setup(s => s.GetMessageByIdAsync(file.MailboxId, fileId))
249+
.ReturnsAsync(new MeshResponse<GetMessageResponse>
250+
{
251+
IsSuccessful = false
252+
});
181253

182254
var message = new FileExtractQueueMessage { FileId = fileId };
183255

256+
// Act
184257
await _function.Run(message);
185258

186-
_blobStoreMock.Verify(b => b.UploadAsync(It.Is<MeshFile>(f => f.FileId == fileId), content), Times.Once);
259+
// Assert
260+
_loggerMock.Verify(
261+
x => x.Log(
262+
LogLevel.Error,
263+
It.IsAny<EventId>(),
264+
It.Is<It.IsAnyType>((v, t) => v.ToString() == $"An exception occurred during file extraction for fileId: {fileId}"),
265+
It.Is<InvalidOperationException>(e => e.Message.StartsWith("Mesh extraction failed: ")),
266+
It.IsAny<Func<It.IsAnyType, Exception?, string>>()
267+
), Times.Once);
268+
_blobStoreMock.Verify(b => b.UploadAsync(It.IsAny<MeshFile>(), It.IsAny<byte[]>()), Times.Never);
269+
_meshInboxServiceMock.Verify(m => m.AcknowledgeMessageByIdAsync(file.MailboxId, file.FileId), Times.Never);
270+
_fileTransformQueueClientMock.Verify(q => q.EnqueueFileTransformAsync(It.IsAny<MeshFile>()), Times.Never);
271+
_fileExtractQueueClientMock.Verify(q => q.SendToPoisonQueueAsync(message), Times.Once);
272+
var updatedFile = _dbContext.MeshFiles.First();
273+
Assert.Null(updatedFile.BlobPath);
274+
Assert.Equal(MeshFileStatus.FailedExtract, updatedFile.Status);
275+
Assert.True(updatedFile.LastUpdatedUtc > originalLastUpdatedUtc);
187276
}
188277

189278
[Fact]
190-
public async Task Run_MeshResponseFails_Throws()
279+
public async Task Run_AcknowledgeMessageFails_ErrorLoggedAndFileSentToPoisonQueue()
191280
{
281+
// Arrange
192282
var fileId = "file-4";
283+
var originalLastUpdatedUtc = DateTime.UtcNow.AddHours(-1);
193284
var file = new MeshFile
194285
{
195286
FileType = MeshFileType.NbssAppointmentEvents,
196287
MailboxId = "test-mailbox",
197288
FileId = fileId,
198289
Status = MeshFileStatus.Discovered,
199-
LastUpdatedUtc = DateTime.UtcNow.AddHours(-2)
290+
LastUpdatedUtc = originalLastUpdatedUtc
200291
};
201292
_dbContext.MeshFiles.Add(file);
202293
await _dbContext.SaveChangesAsync();
203294

204-
_meshInboxServiceMock.Setup(s => s.GetMessageByIdAsync("test-mailbox", fileId))
295+
var content = new byte[] { 1, 2, 3 };
296+
297+
_meshInboxServiceMock.Setup(s => s.GetMessageByIdAsync(file.MailboxId, fileId))
205298
.ReturnsAsync(new MeshResponse<GetMessageResponse>
206299
{
207-
IsSuccessful = false,
300+
IsSuccessful = true,
301+
Response = new GetMessageResponse
302+
{
303+
FileAttachment = new FileAttachment { Content = content }
304+
}
305+
});
306+
_blobStoreMock.Setup(s => s.UploadAsync(file, content)).ReturnsAsync("directory/fileName");
307+
_meshInboxServiceMock.Setup(s => s.AcknowledgeMessageByIdAsync(file.MailboxId, file.FileId))
308+
.ReturnsAsync(new MeshResponse<AcknowledgeMessageResponse>
309+
{
310+
IsSuccessful = false
208311
});
209312

210313
var message = new FileExtractQueueMessage { FileId = fileId };
211314

212-
var exception = await Assert.ThrowsAsync<InvalidOperationException>(() => _function.Run(message));
213-
Assert.Contains("Mesh extraction failed", exception.Message);
315+
// Act
316+
await _function.Run(message);
317+
318+
// Assert
319+
_loggerMock.Verify(
320+
x => x.Log(
321+
LogLevel.Error,
322+
It.IsAny<EventId>(),
323+
It.Is<It.IsAnyType>((v, t) => v.ToString() == $"An exception occurred during file extraction for fileId: {fileId}"),
324+
It.Is<InvalidOperationException>(e => e.Message.StartsWith("Mesh acknowledgement failed: ")),
325+
It.IsAny<Func<It.IsAnyType, Exception?, string>>()
326+
), Times.Once);
327+
_blobStoreMock.Verify(b => b.UploadAsync(file, content), Times.Once);
328+
_meshInboxServiceMock.Verify(m => m.AcknowledgeMessageByIdAsync(file.MailboxId, file.FileId), Times.Once);
329+
_fileTransformQueueClientMock.Verify(q => q.EnqueueFileTransformAsync(It.IsAny<MeshFile>()), Times.Never);
330+
_fileExtractQueueClientMock.Verify(q => q.SendToPoisonQueueAsync(message), Times.Once);
331+
var updatedFile = _dbContext.MeshFiles.First();
332+
Assert.Null(updatedFile.BlobPath);
333+
Assert.Equal(MeshFileStatus.FailedExtract, updatedFile.Status);
334+
Assert.True(updatedFile.LastUpdatedUtc > originalLastUpdatedUtc);
214335
}
215336
}

0 commit comments

Comments
 (0)