Skip to content

Commit 8bf5b1c

Browse files
authored
Merge pull request #108 from ThriveCommunityChurch/dev
Adds tests to the GetAllSermons endpoint
2 parents 8147f10 + d367e14 commit 8bf5b1c

2 files changed

Lines changed: 313 additions & 7 deletions

File tree

.github/workflows/deploy.yml

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,17 +50,38 @@ jobs:
5050
echo "image=$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" >> $GITHUB_OUTPUT
5151
5252
- name: Deploy to App Runner
53+
env:
54+
IMAGE_URI: ${{ steps.build-image.outputs.image }}
5355
run: |
5456
# Check if service exists
5557
SERVICE_ARN=$(aws apprunner list-services --query "ServiceSummaryList[?ServiceName=='${{ env.APP_RUNNER_SERVICE }}'].ServiceArn" --output text)
56-
58+
5759
if [ -z "$SERVICE_ARN" ] || [ "$SERVICE_ARN" == "None" ]; then
5860
echo "App Runner service does not exist yet. Please create it manually in the AWS Console first."
59-
echo "Once created, subsequent pushes will auto-deploy via ECR trigger."
60-
exit 0
61+
exit 1
6162
fi
62-
63-
# Trigger a new deployment
64-
aws apprunner start-deployment --service-arn $SERVICE_ARN
65-
echo "Deployment triggered for App Runner service: ${{ env.APP_RUNNER_SERVICE }}"
63+
64+
echo "Updating App Runner service to use image: $IMAGE_URI"
65+
66+
# Get the current service configuration to preserve all settings
67+
CURRENT_CONFIG=$(aws apprunner describe-service --service-arn $SERVICE_ARN)
68+
69+
# Extract and update the source configuration, preserving all existing settings
70+
# This keeps environment variables, secrets, and other ImageConfiguration intact
71+
UPDATED_SOURCE_CONFIG=$(echo $CURRENT_CONFIG | jq --arg NEW_IMAGE "$IMAGE_URI" '
72+
.Service.SourceConfiguration |
73+
.ImageRepository.ImageIdentifier = $NEW_IMAGE |
74+
del(.CodeRepository) |
75+
del(.AutoDeploymentsEnabled)
76+
')
77+
78+
# Update the service with the new image while preserving all other settings
79+
# Only output the operation ID (safe) - suppress all other output that contains env vars
80+
aws apprunner update-service \
81+
--service-arn $SERVICE_ARN \
82+
--source-configuration "$UPDATED_SOURCE_CONFIG" \
83+
--query 'OperationId' \
84+
--output text
85+
86+
echo "App Runner service updated for: ${{ env.APP_RUNNER_SERVICE }}"
6687

API/ThriveChurchOfficialAPI/ThriveChurchOfficialAPI.Tests/Services/SermonsServiceTests.cs

Lines changed: 285 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -972,6 +972,291 @@ public async Task GetMessageWaveformData_ResponseFormatIsCorrect_VerifiesSystemR
972972

973973
#endregion
974974

975+
#region GetAllSermons Caching Tests
976+
977+
[TestMethod]
978+
public async Task GetAllSermons_CacheMiss_FetchesFromRepositoryAndCachesResult()
979+
{
980+
// Arrange
981+
var series1 = CreateTestSermonSeries("1", "Series 1", "series-1");
982+
var series2 = CreateTestSermonSeries("2", "Series 2", "series-2");
983+
var seriesList = new List<SermonSeries> { series1, series2 };
984+
985+
var message1 = CreateTestSermonMessage("msg1", "1", "Message 1");
986+
var message2 = CreateTestSermonMessage("msg2", "2", "Message 2");
987+
var messagesList = new List<SermonMessage> { message1, message2 };
988+
989+
_mockSermonsRepository.Setup(r => r.GetAllSermons(It.IsAny<bool>()))
990+
.ReturnsAsync(seriesList);
991+
992+
_mockMessagesRepository.Setup(r => r.GetAllMessages())
993+
.ReturnsAsync(messagesList);
994+
995+
// Setup cache miss
996+
object cacheValue = null;
997+
_mockCache.Setup(c => c.TryGetValue(It.IsAny<object>(), out cacheValue))
998+
.Returns(false);
999+
1000+
// Setup cache entry for Set
1001+
var cacheEntry = new Mock<ICacheEntry>();
1002+
_mockCache.Setup(c => c.CreateEntry(It.IsAny<object>()))
1003+
.Returns(cacheEntry.Object);
1004+
1005+
// Act
1006+
var result = await _sermonsService.GetAllSermons(highResImg: false);
1007+
1008+
// Assert
1009+
Assert.IsNotNull(result);
1010+
Assert.IsFalse(result.HasErrors);
1011+
Assert.IsNotNull(result.Result);
1012+
Assert.AreEqual(2, result.Result.Summaries.Count());
1013+
1014+
// Verify repository was called (cache miss)
1015+
_mockSermonsRepository.Verify(r => r.GetAllSermons(It.IsAny<bool>()), Times.Once);
1016+
_mockMessagesRepository.Verify(r => r.GetAllMessages(), Times.Once);
1017+
1018+
// Verify cache Set was called
1019+
_mockCache.Verify(c => c.CreateEntry(It.Is<object>(key =>
1020+
key.ToString().Contains("AllSermonsSummaryCache"))), Times.Once);
1021+
}
1022+
1023+
[TestMethod]
1024+
public async Task GetAllSermons_CacheHit_ReturnsCachedResultWithoutCallingRepository()
1025+
{
1026+
// Arrange
1027+
var cachedSummaries = new List<AllSermonSeriesSummary>
1028+
{
1029+
new AllSermonSeriesSummary { Id = "1", Title = "Cached Series 1", MessageCount = 5 },
1030+
new AllSermonSeriesSummary { Id = "2", Title = "Cached Series 2", MessageCount = 3 }
1031+
};
1032+
var cachedResponse = new SystemResponse<AllSermonsSummaryResponse>(
1033+
new AllSermonsSummaryResponse { Summaries = cachedSummaries },
1034+
"Success!");
1035+
1036+
// Setup cache hit
1037+
object cacheValue = cachedResponse;
1038+
_mockCache.Setup(c => c.TryGetValue(It.IsAny<object>(), out cacheValue))
1039+
.Returns(true);
1040+
1041+
// Act
1042+
var result = await _sermonsService.GetAllSermons(highResImg: false);
1043+
1044+
// Assert
1045+
Assert.IsNotNull(result);
1046+
Assert.IsFalse(result.HasErrors);
1047+
Assert.AreEqual(2, result.Result.Summaries.Count());
1048+
Assert.AreEqual("Cached Series 1", result.Result.Summaries.First().Title);
1049+
1050+
// Verify repository was NOT called (cache hit)
1051+
_mockSermonsRepository.Verify(r => r.GetAllSermons(It.IsAny<bool>()), Times.Never);
1052+
_mockMessagesRepository.Verify(r => r.GetAllMessages(), Times.Never);
1053+
}
1054+
1055+
[TestMethod]
1056+
public async Task GetAllSermons_HighResImgTrue_UsesDifferentCacheKey()
1057+
{
1058+
// Arrange
1059+
var series = CreateTestSermonSeries("1", "Series 1", "series-1");
1060+
var seriesList = new List<SermonSeries> { series };
1061+
var messagesList = new List<SermonMessage>();
1062+
1063+
_mockSermonsRepository.Setup(r => r.GetAllSermons(It.IsAny<bool>()))
1064+
.ReturnsAsync(seriesList);
1065+
1066+
_mockMessagesRepository.Setup(r => r.GetAllMessages())
1067+
.ReturnsAsync(messagesList);
1068+
1069+
// Setup cache miss
1070+
object cacheValue = null;
1071+
_mockCache.Setup(c => c.TryGetValue(It.IsAny<object>(), out cacheValue))
1072+
.Returns(false);
1073+
1074+
// Setup cache entry for Set
1075+
var cacheEntry = new Mock<ICacheEntry>();
1076+
_mockCache.Setup(c => c.CreateEntry(It.IsAny<object>()))
1077+
.Returns(cacheEntry.Object);
1078+
1079+
// Act
1080+
var result = await _sermonsService.GetAllSermons(highResImg: true);
1081+
1082+
// Assert
1083+
Assert.IsNotNull(result);
1084+
Assert.IsFalse(result.HasErrors);
1085+
1086+
// Verify cache key contains "True" for highResImg
1087+
_mockCache.Verify(c => c.CreateEntry(It.Is<object>(key =>
1088+
key.ToString().Contains("True"))), Times.Once);
1089+
}
1090+
1091+
[TestMethod]
1092+
public async Task GetAllSermons_HighResImgFalse_UsesThumbnailUrl()
1093+
{
1094+
// Arrange
1095+
var series = new SermonSeries
1096+
{
1097+
Id = "1",
1098+
Name = "Test Series",
1099+
Slug = "test-series",
1100+
StartDate = DateTime.UtcNow,
1101+
ArtUrl = "https://example.com/high-res-art.jpg",
1102+
Thumbnail = "https://example.com/thumbnail.jpg"
1103+
};
1104+
var seriesList = new List<SermonSeries> { series };
1105+
var messagesList = new List<SermonMessage>();
1106+
1107+
_mockSermonsRepository.Setup(r => r.GetAllSermons(It.IsAny<bool>()))
1108+
.ReturnsAsync(seriesList);
1109+
1110+
_mockMessagesRepository.Setup(r => r.GetAllMessages())
1111+
.ReturnsAsync(messagesList);
1112+
1113+
// Setup cache miss
1114+
object cacheValue = null;
1115+
_mockCache.Setup(c => c.TryGetValue(It.IsAny<object>(), out cacheValue))
1116+
.Returns(false);
1117+
1118+
// Setup cache entry
1119+
var cacheEntry = new Mock<ICacheEntry>();
1120+
_mockCache.Setup(c => c.CreateEntry(It.IsAny<object>()))
1121+
.Returns(cacheEntry.Object);
1122+
1123+
// Act
1124+
var result = await _sermonsService.GetAllSermons(highResImg: false);
1125+
1126+
// Assert
1127+
Assert.IsNotNull(result);
1128+
Assert.IsFalse(result.HasErrors);
1129+
var summary = result.Result.Summaries.First();
1130+
Assert.AreEqual("https://example.com/thumbnail.jpg", summary.ArtUrl);
1131+
}
1132+
1133+
[TestMethod]
1134+
public async Task GetAllSermons_HighResImgTrue_UsesArtUrl()
1135+
{
1136+
// Arrange
1137+
var series = new SermonSeries
1138+
{
1139+
Id = "1",
1140+
Name = "Test Series",
1141+
Slug = "test-series",
1142+
StartDate = DateTime.UtcNow,
1143+
ArtUrl = "https://example.com/high-res-art.jpg",
1144+
Thumbnail = "https://example.com/thumbnail.jpg"
1145+
};
1146+
var seriesList = new List<SermonSeries> { series };
1147+
var messagesList = new List<SermonMessage>();
1148+
1149+
_mockSermonsRepository.Setup(r => r.GetAllSermons(It.IsAny<bool>()))
1150+
.ReturnsAsync(seriesList);
1151+
1152+
_mockMessagesRepository.Setup(r => r.GetAllMessages())
1153+
.ReturnsAsync(messagesList);
1154+
1155+
// Setup cache miss
1156+
object cacheValue = null;
1157+
_mockCache.Setup(c => c.TryGetValue(It.IsAny<object>(), out cacheValue))
1158+
.Returns(false);
1159+
1160+
// Setup cache entry
1161+
var cacheEntry = new Mock<ICacheEntry>();
1162+
_mockCache.Setup(c => c.CreateEntry(It.IsAny<object>()))
1163+
.Returns(cacheEntry.Object);
1164+
1165+
// Act
1166+
var result = await _sermonsService.GetAllSermons(highResImg: true);
1167+
1168+
// Assert
1169+
Assert.IsNotNull(result);
1170+
Assert.IsFalse(result.HasErrors);
1171+
var summary = result.Result.Summaries.First();
1172+
Assert.AreEqual("https://example.com/high-res-art.jpg", summary.ArtUrl);
1173+
}
1174+
1175+
[TestMethod]
1176+
public async Task GetAllSermons_CalculatesMessageCountCorrectly()
1177+
{
1178+
// Arrange
1179+
var series1 = CreateTestSermonSeries("1", "Series 1", "series-1");
1180+
var series2 = CreateTestSermonSeries("2", "Series 2", "series-2");
1181+
var seriesList = new List<SermonSeries> { series1, series2 };
1182+
1183+
// 3 messages for series 1, 2 messages for series 2
1184+
var messages = new List<SermonMessage>
1185+
{
1186+
CreateTestSermonMessage("msg1", "1", "Message 1"),
1187+
CreateTestSermonMessage("msg2", "1", "Message 2"),
1188+
CreateTestSermonMessage("msg3", "1", "Message 3"),
1189+
CreateTestSermonMessage("msg4", "2", "Message 4"),
1190+
CreateTestSermonMessage("msg5", "2", "Message 5")
1191+
};
1192+
1193+
_mockSermonsRepository.Setup(r => r.GetAllSermons(It.IsAny<bool>()))
1194+
.ReturnsAsync(seriesList);
1195+
1196+
_mockMessagesRepository.Setup(r => r.GetAllMessages())
1197+
.ReturnsAsync(messages);
1198+
1199+
// Setup cache miss
1200+
object cacheValue = null;
1201+
_mockCache.Setup(c => c.TryGetValue(It.IsAny<object>(), out cacheValue))
1202+
.Returns(false);
1203+
1204+
// Setup cache entry
1205+
var cacheEntry = new Mock<ICacheEntry>();
1206+
_mockCache.Setup(c => c.CreateEntry(It.IsAny<object>()))
1207+
.Returns(cacheEntry.Object);
1208+
1209+
// Act
1210+
var result = await _sermonsService.GetAllSermons(highResImg: false);
1211+
1212+
// Assert
1213+
Assert.IsNotNull(result);
1214+
Assert.IsFalse(result.HasErrors);
1215+
var summaries = result.Result.Summaries.ToList();
1216+
Assert.AreEqual(2, summaries.Count);
1217+
1218+
var series1Summary = summaries.First(s => s.Id == "1");
1219+
var series2Summary = summaries.First(s => s.Id == "2");
1220+
Assert.AreEqual(3, series1Summary.MessageCount);
1221+
Assert.AreEqual(2, series2Summary.MessageCount);
1222+
}
1223+
1224+
[TestMethod]
1225+
public async Task GetAllSermons_SeriesWithNoMessages_ReturnsZeroMessageCount()
1226+
{
1227+
// Arrange
1228+
var series = CreateTestSermonSeries("1", "Empty Series", "empty-series");
1229+
var seriesList = new List<SermonSeries> { series };
1230+
var emptyMessages = new List<SermonMessage>();
1231+
1232+
_mockSermonsRepository.Setup(r => r.GetAllSermons(It.IsAny<bool>()))
1233+
.ReturnsAsync(seriesList);
1234+
1235+
_mockMessagesRepository.Setup(r => r.GetAllMessages())
1236+
.ReturnsAsync(emptyMessages);
1237+
1238+
// Setup cache miss
1239+
object cacheValue = null;
1240+
_mockCache.Setup(c => c.TryGetValue(It.IsAny<object>(), out cacheValue))
1241+
.Returns(false);
1242+
1243+
// Setup cache entry
1244+
var cacheEntry = new Mock<ICacheEntry>();
1245+
_mockCache.Setup(c => c.CreateEntry(It.IsAny<object>()))
1246+
.Returns(cacheEntry.Object);
1247+
1248+
// Act
1249+
var result = await _sermonsService.GetAllSermons(highResImg: false);
1250+
1251+
// Assert
1252+
Assert.IsNotNull(result);
1253+
Assert.IsFalse(result.HasErrors);
1254+
var summary = result.Result.Summaries.First();
1255+
Assert.AreEqual(0, summary.MessageCount);
1256+
}
1257+
1258+
#endregion
1259+
9751260
#region Helper Methods
9761261

9771262
private SermonSeries CreateTestSermonSeries(string id, string name, string slug)

0 commit comments

Comments
 (0)