-
Notifications
You must be signed in to change notification settings - Fork 59
/
Copy pathing Hng.Infrastructure.Repository.Interface
550 lines (550 loc) · 28 KB
/
ing Hng.Infrastructure.Repository.Interface
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
[1mdiff --git a/.github/workflows/dev-deployment.yml b/.github/workflows/dev-deployment.yml[m
[1mindex baae780..f90dc1b 100644[m
[1m--- a/.github/workflows/dev-deployment.yml[m
[1m+++ b/.github/workflows/dev-deployment.yml[m
[36m@@ -10,23 +10,22 @@[m [mjobs:[m
build:[m
runs-on: ubuntu-latest[m
steps:[m
[31m- - uses: actions/checkout@v2[m
[32m+[m[32m - uses: actions/checkout@v4[m
[m
[31m- - name: Build Docker image[m
[31m- run: docker build -t csharp_dev .[m
[32m+[m[32m # - name: Build Docker image[m
[32m+[m[32m # run: docker build -t csharp_dev .[m
[m
[31m- - name: Save and compress Docker image[m
[31m- run: docker save csharp_dev | gzip > csharp_dev.tar.gz[m
[32m+[m[32m # - name: Save and compress Docker image[m
[32m+[m[32m # run: docker save csharp_dev | gzip > csharp_dev.tar.gz[m
[m
[31m- - name: Upload Docker image[m
[31m- uses: actions/upload-artifact@v2[m
[31m- with:[m
[31m- name: csharp_dev[m
[31m- path: csharp_dev.tar.gz[m
[32m+[m[32m # - name: Upload Docker image[m
[32m+[m[32m # uses: actions/upload-artifact@v4[m
[32m+[m[32m # with:[m
[32m+[m[32m # name: csharp_dev[m
[32m+[m[32m # path: csharp_dev.tar.gz[m
[m
deploy:[m
needs: build[m
[31m- if: github.event.repository.fork == false[m
runs-on: ubuntu-latest[m
[m
environment:[m
[36m@@ -34,29 +33,41 @@[m [mjobs:[m
url: ${{ vars.URL }}[m
[m
steps:[m
[31m- - name: Download Docker image[m
[31m- uses: actions/download-artifact@v2[m
[31m- with:[m
[31m- name: csharp_dev[m
[31m- path: .[m
[32m+[m[32m # - name: Download Docker image[m
[32m+[m[32m # uses: actions/download-artifact@v4[m
[32m+[m[32m # with:[m
[32m+[m[32m # name: csharp_dev[m
[32m+[m[32m # path: .[m
[m
[31m- - name: Copy image to server[m
[31m- uses: appleboy/scp-action@master[m
[31m- with:[m
[31m- host: ${{ secrets.HOST }}[m
[31m- username: ${{ secrets.USERNAME }}[m
[31m- password: ${{ secrets.PASSWORD }}[m
[31m- source: csharp_dev.tar.gz[m
[31m- target: "/tmp"[m
[32m+[m[32m # - name: Copy image to server[m
[32m+[m[32m # uses: appleboy/scp-action@master[m
[32m+[m[32m # with:[m
[32m+[m[32m # host: ${{ secrets.HOST }}[m
[32m+[m[32m # username: ${{ secrets.USERNAME }}[m
[32m+[m[32m # password: ${{ secrets.PASSWORD }}[m
[32m+[m[32m # source: csharp_dev.tar.gz[m
[32m+[m[32m # target: "/tmp"[m
[32m+[m
[32m+[m[32m # - name: Deploy on server[m
[32m+[m[32m # uses: appleboy/ssh-action@master[m
[32m+[m[32m # with:[m
[32m+[m[32m # host: ${{ secrets.HOST }}[m
[32m+[m[32m # username: ${{ secrets.USERNAME }}[m
[32m+[m[32m # password: ${{ secrets.PASSWORD }}[m
[32m+[m[32m # script: |[m
[32m+[m[32m # gunzip -c /tmp/csharp_dev.tar.gz | docker load[m
[32m+[m[32m # rm -f /tmp/csharp_dev.tar.gz[m
[32m+[m[32m # cd ~/hng_boilerplate_csharp_web[m
[32m+[m[32m # docker compose -p csharp_dev up -d[m
[m
[31m- - name: Deploy on server[m
[31m- uses: appleboy/ssh-action@master[m
[32m+[m[32m - name: SSH into server and deploy[m
[32m+[m[32m uses: appleboy/[email protected][m
with:[m
host: ${{ secrets.HOST }}[m
username: ${{ secrets.USERNAME }}[m
password: ${{ secrets.PASSWORD }}[m
script: |[m
[31m- gunzip -c /tmp/csharp_dev.tar.gz | docker load[m
[31m- rm -f /tmp/csharp_dev.tar.gz[m
[31m- cd ~/hng_boilerplate_csharp_web[m
[31m- docker compose -p csharp_dev up -d[m
\ No newline at end of file[m
[32m+[m[32m mkdir -p ~/csharp/backend[m
[32m+[m[32m cd ~/csharp/backend[m
[32m+[m[32m git pull origin dev[m
[32m+[m[32m docker compose -p csharp_dev up -d[m
[1mdiff --git a/src/Hng.Application.Test/Features/Job/UpdateJobCommandShould.cs b/src/Hng.Application.Test/Features/Job/UpdateJobCommandShould.cs[m
[1mdeleted file mode 100644[m
[1mindex 6eea192..0000000[m
[1m--- a/src/Hng.Application.Test/Features/Job/UpdateJobCommandShould.cs[m
[1m+++ /dev/null[m
[36m@@ -1,108 +0,0 @@[m
[31m-using Hng.Infrastructure.Repository.Interface;[m
[31m-using Moq;[m
[31m-using System;[m
[31m-using System.Collections.Generic;[m
[31m-using System.Linq;[m
[31m-using System.Text;[m
[31m-using System.Threading.Tasks;[m
[31m-using AutoMapper;[m
[31m-using Hng.Application.Features.Jobs.Handlers;[m
[31m-using Xunit;[m
[31m-using Hng.Domain.Entities;[m
[31m-using Hng.Application.Features.Jobs.Dtos;[m
[31m-using Hng.Application.Features.Jobs.Commands;[m
[31m-using Microsoft.AspNetCore.Http;[m
[31m-[m
[31m-namespace Hng.Application.Test.Features.Job[m
[31m-{[m
[31m- public class UpdateJobCommandShould[m
[31m- {[m
[31m- private readonly Mock<IRepository<Domain.Entities.Job>> _mockJobRepository;[m
[31m- private readonly Mock<IMapper> _mockMapper;[m
[31m- private readonly UpdateJobCommandHandler _handler;[m
[31m-[m
[31m- public UpdateJobCommandShould()[m
[31m- {[m
[31m- _mockJobRepository = new Mock<IRepository<Domain.Entities.Job>>();[m
[31m- _mockMapper = new Mock<IMapper>();[m
[31m- _handler = new UpdateJobCommandHandler(_mockJobRepository.Object, _mockMapper.Object);[m
[31m- }[m
[31m-[m
[31m- [Fact][m
[31m- public async Task Handle_JobExists_UpdatesJobSuccessfully()[m
[31m- {[m
[31m- // Arrange - Create existing job[m
[31m- var existingJob = new Domain.Entities.Job[m
[31m- {[m
[31m- Id = Guid.NewGuid(),[m
[31m- Title = "Software Developer",[m
[31m- Description = "Develop software",[m
[31m- Location = "Lagos",[m
[31m- Salary = 30_000,[m
[31m- Company = "HNG",[m
[31m- DatePosted = DateTime.Now,[m
[31m- Level = Domain.Enums.ExperienceLevel.Junior[m
[31m-[m
[31m- };[m
[31m-[m
[31m- var updateJob = new UpdateJobDto[m
[31m- {[m
[31m- Title = "Backend Developer",[m
[31m- Description = "Develop software",[m
[31m- Level = Domain.Enums.ExperienceLevel.Senior[m
[31m- };[m
[31m-[m
[31m- var command = new UpdateJobCommand(updateJob, existingJob.Id);[m
[31m-[m
[31m- _mockJobRepository.Setup(repo => repo.GetAsync(existingJob.Id)).ReturnsAsync(existingJob);[m
[31m- _mockMapper[m
[31m- .Setup(mapper => mapper.Map(updateJob, existingJob))[m
[31m- .Callback<UpdateJobDto, Domain.Entities.Job>((src, dest) =>[m
[31m- {[m
[31m- dest.Title = src.Title;[m
[31m- dest.Description = src.Description;[m
[31m- dest.Level = src.Level.Value;[m
[31m- });[m
[31m-[m
[31m- // Act[m
[31m- var response = await _handler.Handle(command, CancellationToken.None);[m
[31m-[m
[31m- // Assert - Ensure the job was updated and the response is correct[m
[31m- Assert.NotNull(response.Data);[m
[31m- Assert.True(response.Success);[m
[31m- Assert.Equal(StatusCodes.Status200OK, response.StatusCode);[m
[31m- Assert.Equal(updateJob.Title, existingJob.Title);[m
[31m- _mockJobRepository.Verify(repo => repo.UpdateAsync(existingJob), Times.Once);[m
[31m- _mockJobRepository.Verify(repo => repo.SaveChanges(), Times.Once);[m
[31m- }[m
[31m-[m
[31m- [Fact][m
[31m- public async Task Handle_JobDoesNotExist_ReturnsNotFound()[m
[31m- {[m
[31m- // Arrange = Simulate job not existing[m
[31m- var existingJobId = Guid.NewGuid();[m
[31m-[m
[31m- var updateJob = new UpdateJobDto[m
[31m- {[m
[31m- Title = "Backend Developer",[m
[31m- Description = "Develop software",[m
[31m- Level = Domain.Enums.ExperienceLevel.Senior[m
[31m- };[m
[31m-[m
[31m- var command = new UpdateJobCommand(updateJob, existingJobId);[m
[31m- [m
[31m- _mockJobRepository.Setup(repo => repo.GetAsync(existingJobId)).ReturnsAsync((Domain.Entities.Job)null);[m
[31m-[m
[31m- // Act[m
[31m- var response = await _handler.Handle(command, CancellationToken.None);[m
[31m-[m
[31m- // Assert - Check response for not found[m
[31m- Assert.Null(response.Data);[m
[31m- Assert.False(response.Success);[m
[31m- Assert.Equal(StatusCodes.Status404NotFound, response.StatusCode);[m
[31m- Assert.Equal("Job not found", response.Message);[m
[31m- Assert.Null(response.Data);[m
[31m-[m
[31m- }[m
[31m- }[m
[31m-}[m
[1mdiff --git a/src/Hng.Application.Test/Features/NewsLetterSubscription/AddSubscriberCommandHandlerShould.cs b/src/Hng.Application.Test/Features/NewsLetterSubscription/AddSubscriberCommandHandlerShould.cs[m
[1mnew file mode 100644[m
[1mindex 0000000..087e63e[m
[1m--- /dev/null[m
[1m+++ b/src/Hng.Application.Test/Features/NewsLetterSubscription/AddSubscriberCommandHandlerShould.cs[m
[36m@@ -0,0 +1,82 @@[m
[32m+[m[32musing AutoMapper;[m
[32m+[m[32musing Hng.Application.Features.NewsLetterSubscription.Commands;[m
[32m+[m[32musing Hng.Application.Features.NewsLetterSubscription.Dtos;[m
[32m+[m[32musing Hng.Application.Features.NewsLetterSubscription.Handlers;[m
[32m+[m[32musing Hng.Domain.Entities;[m
[32m+[m[32musing Hng.Infrastructure.Repository.Interface;[m
[32m+[m[32musing Moq;[m
[32m+[m[32musing Xunit;[m
[32m+[m
[32m+[m[32mnamespace Hng.Application.Test.Features.NewsLetterSubscription[m
[32m+[m[32m{[m
[32m+[m[32m public class AddSubscriberHandlerShould[m
[32m+[m[32m {[m
[32m+[m[32m private readonly Mock<IRepository<NewsLetterSubscriber>> _mockRepository;[m
[32m+[m[32m private readonly AddSubscriberHandler _handler;[m
[32m+[m[32m private readonly IMapper _mapper;[m
[32m+[m
[32m+[m[32m public AddSubscriberHandlerShould()[m
[32m+[m[32m {[m
[32m+[m[32m _mockRepository = new Mock<IRepository<NewsLetterSubscriber>>();[m
[32m+[m
[32m+[m[32m var mapperConfig = new MapperConfiguration(cfg =>[m
[32m+[m[32m {[m
[32m+[m[32m cfg.CreateMap<NewsLetterSubscriptionDto, NewsLetterSubscriber>();[m
[32m+[m[32m });[m
[32m+[m[32m _mapper = mapperConfig.CreateMapper();[m
[32m+[m
[32m+[m[32m _handler = new AddSubscriberHandler(_mockRepository.Object, _mapper);[m
[32m+[m[32m }[m
[32m+[m
[32m+[m[32m [Fact][m
[32m+[m[32m public async Task Handle_ShouldAddSubscriber_WhenSubscriberDoesNotExist()[m
[32m+[m[32m {[m
[32m+[m[32m // Arrange[m
[32m+[m[32m var email = "[email protected]";[m
[32m+[m[32m var subscriber = new NewsLetterSubscriptionDto { Email = email };[m
[32m+[m[32m var command = new AddSubscriberCommand(subscriber);[m
[32m+[m
[32m+[m[32m _mockRepository.Setup(r => r.GetBySpec(It.IsAny<System.Linq.Expressions.Expression<Func<NewsLetterSubscriber, bool>>>(), It.IsAny<System.Linq.Expressions.Expression<Func<NewsLetterSubscriber, object>>[]>()))[m
[32m+[m[32m .ReturnsAsync((NewsLetterSubscriber)null);[m
[32m+[m
[32m+[m[32m _mockRepository.Setup(r => r.AddAsync(It.IsAny<NewsLetterSubscriber>()))[m
[32m+[m[32m .ReturnsAsync((NewsLetterSubscriber)null);[m
[32m+[m
[32m+[m[32m _mockRepository.Setup(r => r.SaveChanges())[m
[32m+[m[32m .Returns(Task.CompletedTask);[m
[32m+[m
[32m+[m[32m // Act[m
[32m+[m[32m var result = await _handler.Handle(command, CancellationToken.None);[m
[32m+[m
[32m+[m[32m // Assert[m
[32m+[m[32m Assert.NotNull(result);[m
[32m+[m[32m Assert.Equal(email, result.Email);[m
[32m+[m[32m _mockRepository.Verify(r => r.AddAsync(It.IsAny<NewsLetterSubscriber>()), Times.Once);[m
[32m+[m[32m _mockRepository.Verify(r => r.SaveChanges(), Times.Once);[m
[32m+[m[32m }[m
[32m+[m
[32m+[m[32m [Fact][m
[32m+[m[32m public async Task Handle_ShouldReturnNull_WhenSubscriberAlreadyExists()[m
[32m+[m[32m {[m
[32m+[m[32m // Arrange[m
[32m+[m[32m var email = "[email protected]";[m
[32m+[m[32m var subscriberDto = new NewsLetterSubscriptionDto { Email = email };[m
[32m+[m[32m var command = new AddSubscriberCommand(subscriberDto);[m
[32m+[m
[32m+[m[32m var existingSubscriber = new NewsLetterSubscriber { Email = email };[m
[32m+[m
[32m+[m[32m _mockRepository.Setup(r => r.GetBySpec(It.IsAny<System.Linq.Expressions.Expression<Func<NewsLetterSubscriber, bool>>>(), It.IsAny<System.Linq.Expressions.Expression<Func<NewsLetterSubscriber, object>>[]>()))[m
[32m+[m[32m .ReturnsAsync(existingSubscriber);[m
[32m+[m
[32m+[m[32m // Act[m
[32m+[m[32m var result = await _handler.Handle(command, CancellationToken.None);[m
[32m+[m
[32m+[m[32m // Assert[m
[32m+[m[32m Assert.Null(result);[m
[32m+[m[32m _mockRepository.Verify(r => r.AddAsync(It.IsAny<NewsLetterSubscriber>()), Times.Never);[m
[32m+[m[32m _mockRepository.Verify(r => r.SaveChanges(), Times.Never);[m
[32m+[m[32m }[m
[32m+[m
[32m+[m
[32m+[m[32m }[m
[32m+[m[32m}[m
[1mdiff --git a/src/Hng.Application.Test/Features/NewsLetterSubscription/DeleteSubscriberCommandHandlerShould.cs b/src/Hng.Application.Test/Features/NewsLetterSubscription/DeleteSubscriberCommandHandlerShould.cs[m
[1mnew file mode 100644[m
[1mindex 0000000..3f189e3[m
[1m--- /dev/null[m
[1m+++ b/src/Hng.Application.Test/Features/NewsLetterSubscription/DeleteSubscriberCommandHandlerShould.cs[m
[36m@@ -0,0 +1,70 @@[m
[32m+[m[32musing Hng.Application.Features.NewsLetterSubscription.Commands;[m
[32m+[m[32musing Hng.Application.Features.NewsLetterSubscription.Handlers;[m
[32m+[m[32musing Hng.Domain.Entities;[m
[32m+[m[32musing Hng.Infrastructure.Repository.Interface;[m
[32m+[m[32musing Moq;[m
[32m+[m[32musing Xunit;[m
[32m+[m
[32m+[m[32mnamespace Hng.Application.Test.Features.NewsLetterSubscription[m
[32m+[m[32m{[m
[32m+[m[32m public class DeleteSubscriberHandlerShould[m
[32m+[m[32m {[m
[32m+[m[32m private readonly Mock<IRepository<NewsLetterSubscriber>> _mockRepository;[m
[32m+[m[32m private readonly DeleteSubscriberHandler _handler;[m
[32m+[m
[32m+[m[32m public DeleteSubscriberHandlerShould()[m
[32m+[m[32m {[m
[32m+[m[32m _mockRepository = new Mock<IRepository<NewsLetterSubscriber>>();[m
[32m+[m[32m _handler = new DeleteSubscriberHandler(_mockRepository.Object);[m
[32m+[m[32m }[m
[32m+[m
[32m+[m[32m [Fact][m
[32m+[m[32m public async Task Handle_ShouldDeleteSubscriber_WhenSubscriberExists()[m
[32m+[m[32m {[m
[32m+[m[32m var subscriberId = Guid.NewGuid();[m
[32m+[m[32m var subscriber = new NewsLetterSubscriber { Id = subscriberId };[m
[32m+[m[32m var command = new DeleteSubscriberCommand(subscriberId);[m
[32m+[m
[32m+[m[32m _mockRepository.Setup(r => r.GetAsync(subscriberId))[m
[32m+[m[32m .ReturnsAsync(subscriber);[m
[32m+[m
[32m+[m[32m _mockRepository.Setup(r => r.UpdateAsync(It.IsAny<NewsLetterSubscriber>()))[m
[32m+[m[32m .Returns(Task.CompletedTask);[m
[32m+[m
[32m+[m[32m _mockRepository.Setup(r => r.SaveChanges())[m
[32m+[m[32m .Returns(Task.CompletedTask);[m
[32m+[m
[32m+[m[32m // Act[m
[32m+[m[32m var result = await _handler.Handle(command, CancellationToken.None);[m
[32m+[m
[32m+[m[32m // Assert[m
[32m+[m[32m Assert.Equal(200, result.StatusCode);[m
[32m+[m[32m Assert.Equal("Subscriber deleted successfully.", result.Message);[m
[32m+[m
[32m+[m[32m _mockRepository.Verify(r => r.GetAsync(subscriberId), Times.Once);[m
[32m+[m[32m _mockRepository.Verify(r => r.UpdateAsync(subscriber), Times.Once);[m
[32m+[m[32m _mockRepository.Verify(r => r.SaveChanges(), Times.Once);[m
[32m+[m[32m }[m
[32m+[m
[32m+[m[32m [Fact][m
[32m+[m[32m public async Task Handle_ShouldReturnNotFound_WhenSubscriberDoesNotExist()[m
[32m+[m[32m {[m
[32m+[m[32m var subscriberId = Guid.NewGuid();[m
[32m+[m[32m var command = new DeleteSubscriberCommand(subscriberId);[m
[32m+[m
[32m+[m[32m _mockRepository.Setup(r => r.GetAsync(subscriberId))[m
[32m+[m[32m .ReturnsAsync((NewsLetterSubscriber)null);[m
[32m+[m
[32m+[m[32m // Act[m
[32m+[m[32m var result = await _handler.Handle(command, CancellationToken.None);[m
[32m+[m
[32m+[m[32m // Assert[m
[32m+[m[32m Assert.Equal(404, result.StatusCode);[m
[32m+[m[32m Assert.Equal("Subscriber not found.", result.Message);[m
[32m+[m
[32m+[m[32m _mockRepository.Verify(r => r.GetAsync(subscriberId), Times.Once);[m
[32m+[m[32m _mockRepository.Verify(r => r.UpdateAsync(It.IsAny<NewsLetterSubscriber>()), Times.Never);[m
[32m+[m[32m _mockRepository.Verify(r => r.SaveChanges(), Times.Never);[m
[32m+[m[32m }[m
[32m+[m[32m }[m
[32m+[m[32m}[m
[1mdiff --git a/src/Hng.Application.Test/Features/Organization/UpdateOrganizationShould.cs b/src/Hng.Application.Test/Features/Organization/UpdateOrganizationShould.cs[m
[1mnew file mode 100644[m
[1mindex 0000000..470bdc7[m
[1m--- /dev/null[m
[1m+++ b/src/Hng.Application.Test/Features/Organization/UpdateOrganizationShould.cs[m
[36m@@ -0,0 +1,184 @@[m
[32m+[m[32musing AutoMapper;[m
[32m+[m[32musing Hng.Application.Features.Organisations.Commands;[m
[32m+[m[32musing Hng.Application.Features.Organisations.Dtos;[m
[32m+[m[32musing Hng.Application.Features.Organisations.Handlers;[m
[32m+[m[32musing Hng.Application.Features.Organisations.Mappers;[m
[32m+[m[32musing Hng.Infrastructure.Repository.Interface;[m
[32m+[m[32musing Hng.Infrastructure.Services.Interfaces;[m
[32m+[m[32musing Microsoft.AspNetCore.Http;[m
[32m+[m[32musing Moq;[m
[32m+[m[32musing System.Linq.Expressions;[m
[32m+[m[32musing Xunit;[m
[32m+[m
[32m+[m[32mnamespace Hng.Application.Test.Features.Organization[m
[32m+[m[32m{[m
[32m+[m[32m public class UpdateOrganizationShould[m
[32m+[m[32m {[m
[32m+[m[32m private readonly Mock<IRepository<Domain.Entities.Organization>> _repositoryMock;[m
[32m+[m[32m private readonly Mock<IAuthenticationService> _authenticationServiceMock;[m
[32m+[m[32m private readonly UpdateOrganizationCommandHandler _handler;[m
[32m+[m[32m private readonly IMapper _mapper;[m
[32m+[m
[32m+[m[32m public UpdateOrganizationShould()[m
[32m+[m[32m {[m
[32m+[m[32m // Setup mapper with proper profile[m
[32m+[m[32m var mappingProfile = new OrganizationMapperProfile();[m
[32m+[m[32m var configuration = new MapperConfiguration(cfg => cfg.AddProfile(mappingProfile));[m
[32m+[m[32m _mapper = new Mapper(configuration);[m
[32m+[m
[32m+[m[32m // Setup repository and authentication mocks[m
[32m+[m[32m _repositoryMock = new Mock<IRepository<Domain.Entities.Organization>>();[m
[32m+[m[32m _authenticationServiceMock = new Mock<IAuthenticationService>();[m
[32m+[m
[32m+[m[32m // Initialize the handler with mocks[m
[32m+[m[32m _handler = new UpdateOrganizationCommandHandler([m
[32m+[m[32m _repositoryMock.Object,[m
[32m+[m[32m _mapper,[m
[32m+[m[32m _authenticationServiceMock.Object[m
[32m+[m[32m );[m
[32m+[m[32m }[m
[32m+[m
[32m+[m[32m [Fact][m
[32m+[m[32m public async Task Handle_ShouldReturn200_WhenOrganizationUpdatedSuccessfully()[m
[32m+[m[32m {[m
[32m+[m[32m // Arrange[m
[32m+[m[32m var userId = Guid.NewGuid();[m
[32m+[m[32m var organizationId = Guid.NewGuid();[m
[32m+[m
[32m+[m[32m var updateDto = new UpdateOrganizationDto[m
[32m+[m[32m {[m
[32m+[m[32m Name = "Updated Org",[m
[32m+[m[32m Description = "Updated Description",[m
[32m+[m[32m Email = "[email protected]",[m
[32m+[m[32m Industry = "Tech",[m
[32m+[m[32m Type = "Enterprise",[m
[32m+[m[32m Country = "Updated Country",[m
[32m+[m[32m Address = "Updated Address",[m
[32m+[m[32m State = "Updated State"[m
[32m+[m[32m };[m
[32m+[m
[32m+[m[32m var existingOrganization = new Domain.Entities.Organization[m
[32m+[m[32m {[m
[32m+[m[32m Id = organizationId,[m
[32m+[m[32m OwnerId = userId,[m
[32m+[m[32m Name = "Old Org",[m
[32m+[m[32m Description = "Old Description",[m
[32m+[m[32m Email = "[email protected]",[m
[32m+[m[32m Industry = "Old Industry",[m
[32m+[m[32m Type = "Old Type",[m
[32m+[m[32m Country = "Old Country",[m
[32m+[m[32m Address = "Old Address",[m
[32m+[m[32m State = "Old State"[m
[32m+[m[32m };[m
[32m+[m
[32m+[m[32m // Setup authentication to return the current user[m
[32m+[m[32m _authenticationServiceMock[m
[32m+[m[32m .Setup(a => a.GetCurrentUserAsync())[m
[32m+[m[32m .ReturnsAsync(userId);[m
[32m+[m
[32m+[m[32m // Setup repository to return existing organization when GetBySpec is called[m
[32m+[m[32m _repositoryMock[m
[32m+[m[32m .Setup(r => r.GetBySpec(It.IsAny<Expression<Func<Domain.Entities.Organization, bool>>>()))[m
[32m+[m[32m .ReturnsAsync(existingOrganization);[m
[32m+[m
[32m+[m[32m // Setup UpdateAsync to do nothing (void return)[m
[32m+[m[32m _repositoryMock[m
[32m+[m[32m .Setup(r => r.UpdateAsync(It.IsAny<Domain.Entities.Organization>()))[m
[32m+[m[32m .Returns(Task.CompletedTask);[m
[32m+[m
[32m+[m[32m // Setup SaveChanges to return success[m
[32m+[m[32m _repositoryMock[m
[32m+[m[32m .Setup(r => r.SaveChanges())[m
[32m+[m[32m .Returns(Task.FromResult(true));[m
[32m+[m
[32m+[m[32m var command = new UpdateOrganizationCommand(organizationId, updateDto);[m
[32m+[m
[32m+[m[32m // Act[m
[32m+[m[32m var result = await _handler.Handle(command, CancellationToken.None);[m
[32m+[m
[32m+[m[32m // Assert[m
[32m+[m[32m Assert.NotNull(result);[m
[32m+[m[32m Assert.Equal(StatusCodes.Status200OK, result.StatusCode);[m
[32m+[m[32m Assert.Equal("Organization updated successfully", result.Message);[m
[32m+[m[32m Assert.NotNull(result.Data);[m
[32m+[m
[32m+[m[32m // Verify all properties were mapped correctly[m
[32m+[m[32m Assert.Equal(updateDto.Name, result.Data.Name);[m
[32m+[m[32m Assert.Equal(updateDto.Description, result.Data.Description);[m
[32m+[m[32m Assert.Equal(updateDto.Email, result.Data.Email);[m
[32m+[m[32m Assert.Equal(updateDto.Industry, result.Data.Industry);[m
[32m+[m[32m Assert.Equal(updateDto.Type, result.Data.Type);[m
[32m+[m[32m Assert.Equal(updateDto.Country, result.Data.Country);[m
[32m+[m[32m Assert.Equal(updateDto.Address, result.Data.Address);[m
[32m+[m[32m Assert.Equal(updateDto.State, result.Data.State);[m
[32m+[m
[32m+[m[32m // Verify repository methods were called[m
[32m+[m[32m _repositoryMock.Verify(r => r.UpdateAsync(It.IsAny<Domain.Entities.Organization>()), Times.Once);[m
[32m+[m[32m _repositoryMock.Verify(r => r.SaveChanges(), Times.Once);[m
[32m+[m[32m }[m
[32m+[m
[32m+[m[32m [Fact][m
[32m+[m[32m public async Task Handle_ShouldReturn404_WhenOrganizationNotFound()[m
[32m+[m[32m {[m
[32m+[m[32m // Arrange[m
[32m+[m[32m var organizationId = Guid.NewGuid();[m
[32m+[m[32m var updateDto = new UpdateOrganizationDto { Name = "Updated Org" };[m
[32m+[m[32m var command = new UpdateOrganizationCommand(organizationId, updateDto);[m
[32m+[m
[32m+[m[32m // Setup repository to return null (organization not found)[m
[32m+[m[32m _repositoryMock[m
[32m+[m[32m .Setup(r => r.GetBySpec(It.IsAny<Expression<Func<Domain.Entities.Organization, bool>>>()))[m
[32m+[m[32m .ReturnsAsync((Domain.Entities.Organization)null);[m
[32m+[m
[32m+[m[32m // Act[m
[32m+[m[32m var result = await _handler.Handle(command, CancellationToken.None);[m
[32m+[m
[32m+[m[32m // Assert[m
[32m+[m[32m Assert.Equal(StatusCodes.Status404NotFound, result.StatusCode);[m
[32m+[m[32m Assert.Equal("Organization not found", result.Message);[m
[32m+[m
[32m+[m[32m // Verify Update/Save were never called[m
[32m+[m[32m _repositoryMock.Verify(r => r.UpdateAsync(It.IsAny<Domain.Entities.Organization>()), Times.Never);[m
[32m+[m[32m _repositoryMock.Verify(r => r.SaveChanges(), Times.Never);[m
[32m+[m[32m }[m
[32m+[m
[32m+[m[32m [Fact][m
[32m+[m[32m public async Task Handle_ShouldReturn403_WhenUnauthorizedUpdateAttempt()[m
[32m+[m[32m {[m
[32m+[m[32m // Arrange[m
[32m+[m[32m var organizationId = Guid.NewGuid();[m
[32m+[m[32m var ownerId = Guid.NewGuid();[m
[32m+[m[32m var unauthorizedUserId = Guid.NewGuid(); // Different from owner[m
[32m+[m[32m var updateDto = new UpdateOrganizationDto { Name = "Updated Org" };[m
[32m+[m[32m var command = new UpdateOrganizationCommand(organizationId, updateDto);[m
[32m+[m
[32m+[m[32m var organization = new Domain.Entities.Organization[m
[32m+[m[32m {[m
[32m+[m[32m Id = organizationId,[m
[32m+[m[32m OwnerId = ownerId // This is the owner[m
[32m+[m[32m };[m
[32m+[m
[32m+[m[32m // Setup authentication to return unauthorized user[m
[32m+[m[32m _authenticationServiceMock[m
[32m+[m[32m .Setup(a => a.GetCurrentUserAsync())[m
[32m+[m[32m .ReturnsAsync(unauthorizedUserId); // Different from owner[m
[32m+[m
[32m+[m[32m // Setup repositor