@mbc-cqrs-serverless/master 0.1.70-beta.0 → 0.1.71-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/controllers/master-data.controller.spec.d.ts +1 -0
- package/dist/controllers/master-data.controller.spec.js +341 -0
- package/dist/controllers/master-data.controller.spec.js.map +1 -0
- package/dist/controllers/master-setting.controller.spec.d.ts +1 -0
- package/dist/controllers/master-setting.controller.spec.js +164 -0
- package/dist/controllers/master-setting.controller.spec.js.map +1 -0
- package/dist/custom-task/my-task.controller.spec.d.ts +1 -0
- package/dist/custom-task/my-task.controller.spec.js +147 -0
- package/dist/custom-task/my-task.controller.spec.js.map +1 -0
- package/dist/custom-task/my-task.service.spec.d.ts +1 -0
- package/dist/custom-task/my-task.service.spec.js +111 -0
- package/dist/custom-task/my-task.service.spec.js.map +1 -0
- package/dist/services/master-data.service.spec.d.ts +1 -0
- package/dist/services/master-data.service.spec.js +1385 -0
- package/dist/services/master-data.service.spec.js.map +1 -0
- package/dist/services/master-setting.service.spec.js +749 -27
- package/dist/services/master-setting.service.spec.js.map +1 -1
- package/package.json +5 -6
|
@@ -8,32 +8,34 @@ const master_setting_service_1 = require("./master-setting.service");
|
|
|
8
8
|
const constants_1 = require("../constants");
|
|
9
9
|
const master_module_definition_1 = require("../master.module-definition");
|
|
10
10
|
const task_1 = require("@mbc-cqrs-serverless/task");
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
},
|
|
11
|
+
const common_1 = require("@nestjs/common");
|
|
12
|
+
const mockInvokeContext = {
|
|
13
|
+
event: {
|
|
14
|
+
requestContext: {
|
|
15
|
+
accountId: '1',
|
|
16
|
+
http: {
|
|
17
|
+
protocol: 'HTTP/1.1',
|
|
18
|
+
sourceIp: '127.0.0.1',
|
|
19
|
+
userAgent: 'PostmanRuntime/7.28.4',
|
|
20
|
+
},
|
|
21
|
+
requestId: '81bf1821-34b0-4dc5-a2ce-685d37d22f8c',
|
|
22
|
+
authorizer: {
|
|
23
|
+
jwt: {
|
|
24
|
+
claims: {
|
|
25
|
+
sub: 'abc',
|
|
26
|
+
'custom:roles': '[{"tenant":"MBC","role":"admin"}]',
|
|
28
27
|
},
|
|
29
28
|
},
|
|
30
29
|
},
|
|
31
30
|
},
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
},
|
|
32
|
+
context: {
|
|
33
|
+
awsRequestId: '81bf1821-34b0-4dc5-a2ce-685d37d22f8c',
|
|
35
34
|
},
|
|
36
35
|
};
|
|
36
|
+
const optionsMock = {
|
|
37
|
+
invokeContext: mockInvokeContext,
|
|
38
|
+
};
|
|
37
39
|
describe('SettingService', () => {
|
|
38
40
|
let service;
|
|
39
41
|
let dataService;
|
|
@@ -55,12 +57,7 @@ describe('SettingService', () => {
|
|
|
55
57
|
provide: core_1.CommandService,
|
|
56
58
|
useValue: {
|
|
57
59
|
publishAsync: jest.fn(),
|
|
58
|
-
|
|
59
|
-
},
|
|
60
|
-
{
|
|
61
|
-
provide: core_1.CommandService,
|
|
62
|
-
useValue: {
|
|
63
|
-
publishAsync: jest.fn(),
|
|
60
|
+
publishPartialUpdateAsync: jest.fn(),
|
|
64
61
|
},
|
|
65
62
|
},
|
|
66
63
|
{
|
|
@@ -82,6 +79,7 @@ describe('SettingService', () => {
|
|
|
82
79
|
service = module.get(master_setting_service_1.MasterSettingService);
|
|
83
80
|
dataService = module.get(core_1.DataService);
|
|
84
81
|
commandService = module.get(core_1.CommandService);
|
|
82
|
+
dynamoDbService = module.get(core_1.DynamoDbService);
|
|
85
83
|
});
|
|
86
84
|
//
|
|
87
85
|
it('should be defined', () => {
|
|
@@ -673,6 +671,730 @@ describe('SettingService', () => {
|
|
|
673
671
|
expect(result).toEqual(mockResponse);
|
|
674
672
|
});
|
|
675
673
|
});
|
|
676
|
-
describe('deleteSetting', () => {
|
|
674
|
+
describe('deleteSetting', () => {
|
|
675
|
+
/**
|
|
676
|
+
* Test Overview: Tests deleteSetting method functionality for MasterSettingService
|
|
677
|
+
* Purpose: Ensures settings can be properly soft deleted with correct version handling
|
|
678
|
+
* Details: Verifies that settings are marked as deleted rather than physically removed
|
|
679
|
+
*/
|
|
680
|
+
it('should soft delete existing setting', async () => {
|
|
681
|
+
const key = { pk: 'MASTER#TEST_TENANT', sk: 'SETTING#TEST_CODE' };
|
|
682
|
+
const existingData = {
|
|
683
|
+
id: 'test-id',
|
|
684
|
+
pk: 'MASTER#TEST_TENANT',
|
|
685
|
+
sk: 'SETTING#TEST_CODE',
|
|
686
|
+
code: 'TEST_CODE',
|
|
687
|
+
name: 'Test Setting',
|
|
688
|
+
version: 1,
|
|
689
|
+
type: 'MASTER',
|
|
690
|
+
tenantCode: 'TEST_TENANT',
|
|
691
|
+
isDeleted: false,
|
|
692
|
+
createdAt: new Date(),
|
|
693
|
+
updatedAt: new Date(),
|
|
694
|
+
};
|
|
695
|
+
dataService.getItem.mockResolvedValue(existingData);
|
|
696
|
+
const mockDeleteResult = {
|
|
697
|
+
...existingData,
|
|
698
|
+
isDeleted: true,
|
|
699
|
+
version: 1,
|
|
700
|
+
updatedAt: new Date(),
|
|
701
|
+
};
|
|
702
|
+
commandService.publishPartialUpdateAsync.mockResolvedValue(mockDeleteResult);
|
|
703
|
+
const result = await service.deleteSetting(key, { invokeContext: mockInvokeContext });
|
|
704
|
+
expect(result).toBeInstanceOf(Object);
|
|
705
|
+
expect(commandService.publishPartialUpdateAsync).toHaveBeenCalledWith(expect.objectContaining({
|
|
706
|
+
pk: key.pk,
|
|
707
|
+
sk: key.sk,
|
|
708
|
+
version: existingData.version,
|
|
709
|
+
isDeleted: true,
|
|
710
|
+
}), { invokeContext: mockInvokeContext });
|
|
711
|
+
});
|
|
712
|
+
it('should throw BadRequestException when setting does not exist', async () => {
|
|
713
|
+
const key = { pk: 'MASTER#TEST_TENANT', sk: 'SETTING#NONEXISTENT' };
|
|
714
|
+
dataService.getItem.mockResolvedValue(null);
|
|
715
|
+
await expect(service.deleteSetting(key, { invokeContext: mockInvokeContext }))
|
|
716
|
+
.rejects.toThrow(common_1.BadRequestException);
|
|
717
|
+
expect(commandService.publishPartialUpdateAsync).not.toHaveBeenCalled();
|
|
718
|
+
});
|
|
719
|
+
});
|
|
720
|
+
/**
|
|
721
|
+
* Test Overview: Tests comprehensive error handling scenarios for MasterSettingService operations
|
|
722
|
+
* Purpose: Ensures the service properly handles database failures, validation errors, and edge cases
|
|
723
|
+
* Details: Verifies error handling for DynamoDB failures, CommandService errors, and hierarchical processing
|
|
724
|
+
*/
|
|
725
|
+
describe('Error Handling Scenarios', () => {
|
|
726
|
+
describe('getSetting - Hierarchical Error Handling', () => {
|
|
727
|
+
it('should handle DynamoDB tenant data access failures gracefully', async () => {
|
|
728
|
+
const tenantCode = 'TEST_TENANT';
|
|
729
|
+
const code = 'TEST_SETTING';
|
|
730
|
+
const dbError = new Error('DynamoDB access failed');
|
|
731
|
+
dbError.name = 'ResourceNotFoundException';
|
|
732
|
+
dynamoDbService.getItem.mockRejectedValue(dbError);
|
|
733
|
+
await expect(service.getSetting({ code }, { invokeContext: mockInvokeContext }))
|
|
734
|
+
.rejects.toThrow(common_1.BadRequestException);
|
|
735
|
+
});
|
|
736
|
+
it('should handle malformed tenant data in DynamoDB', async () => {
|
|
737
|
+
const tenantCode = 'TEST_TENANT';
|
|
738
|
+
const code = 'TEST_SETTING';
|
|
739
|
+
dynamoDbService.getItem.mockResolvedValue({
|
|
740
|
+
attributes: {
|
|
741
|
+
malformedData: 'invalid-json-structure'
|
|
742
|
+
}
|
|
743
|
+
});
|
|
744
|
+
await expect(service.getSetting({ code }, { invokeContext: mockInvokeContext }))
|
|
745
|
+
.rejects.toThrow(common_1.BadRequestException);
|
|
746
|
+
});
|
|
747
|
+
it('should handle timeout errors during hierarchical setting retrieval', async () => {
|
|
748
|
+
const tenantCode = 'TEST_TENANT';
|
|
749
|
+
const code = 'TEST_SETTING';
|
|
750
|
+
const timeoutError = new Error('Request timeout');
|
|
751
|
+
timeoutError.name = 'TimeoutError';
|
|
752
|
+
dataService.getItem.mockRejectedValue(timeoutError);
|
|
753
|
+
await expect(service.getSetting({ code }, { invokeContext: mockInvokeContext }))
|
|
754
|
+
.rejects.toThrow('Request timeout');
|
|
755
|
+
});
|
|
756
|
+
});
|
|
757
|
+
describe('createCommonTenantSetting - Error Handling', () => {
|
|
758
|
+
it('should handle CommandService publish failures', async () => {
|
|
759
|
+
const dto = {
|
|
760
|
+
code: 'TEST_SETTING',
|
|
761
|
+
name: 'Test Setting',
|
|
762
|
+
settingValue: { key: 'value' },
|
|
763
|
+
};
|
|
764
|
+
dataService.getItem.mockResolvedValue(null);
|
|
765
|
+
const publishError = new Error('Command publish failed');
|
|
766
|
+
commandService.publishAsync.mockRejectedValue(publishError);
|
|
767
|
+
await expect(service.createCommonTenantSetting(dto, { invokeContext: mockInvokeContext }))
|
|
768
|
+
.rejects.toThrow('Command publish failed');
|
|
769
|
+
});
|
|
770
|
+
it('should handle database connection errors during existence check', async () => {
|
|
771
|
+
const dto = {
|
|
772
|
+
code: 'TEST_SETTING',
|
|
773
|
+
name: 'Test Setting',
|
|
774
|
+
settingValue: { key: 'value' },
|
|
775
|
+
};
|
|
776
|
+
const dbError = new Error('Database connection failed');
|
|
777
|
+
dbError.name = 'NetworkingError';
|
|
778
|
+
dataService.getItem.mockRejectedValue(dbError);
|
|
779
|
+
await expect(service.createCommonTenantSetting(dto, { invokeContext: mockInvokeContext }))
|
|
780
|
+
.rejects.toThrow('Database connection failed');
|
|
781
|
+
});
|
|
782
|
+
});
|
|
783
|
+
describe('updateSetting - Error Handling', () => {
|
|
784
|
+
it('should handle version conflict errors during update', async () => {
|
|
785
|
+
const key = { pk: 'MASTER#TEST_TENANT', sk: 'SETTING#TEST_CODE' };
|
|
786
|
+
const existingData = {
|
|
787
|
+
id: 'test-id',
|
|
788
|
+
pk: 'MASTER#TEST_TENANT',
|
|
789
|
+
sk: 'SETTING#TEST_CODE',
|
|
790
|
+
code: 'TEST_CODE',
|
|
791
|
+
name: 'Test Setting',
|
|
792
|
+
version: 1,
|
|
793
|
+
type: 'MASTER',
|
|
794
|
+
tenantCode: 'TEST_TENANT',
|
|
795
|
+
isDeleted: false,
|
|
796
|
+
createdAt: new Date(),
|
|
797
|
+
updatedAt: new Date(),
|
|
798
|
+
};
|
|
799
|
+
dataService.getItem.mockResolvedValue(existingData);
|
|
800
|
+
const versionError = new Error('Version conflict');
|
|
801
|
+
versionError.name = 'ConditionalCheckFailedException';
|
|
802
|
+
commandService.publishPartialUpdateAsync.mockRejectedValue(versionError);
|
|
803
|
+
await expect(service.updateSetting(key, { settingValue: { updated: true } }, { invokeContext: mockInvokeContext }))
|
|
804
|
+
.rejects.toThrow('Version conflict');
|
|
805
|
+
});
|
|
806
|
+
it('should handle concurrent update attempts', async () => {
|
|
807
|
+
const key = { pk: 'MASTER#TEST_TENANT', sk: 'SETTING#TEST_CODE' };
|
|
808
|
+
const existingData = {
|
|
809
|
+
id: 'test-id',
|
|
810
|
+
pk: 'MASTER#TEST_TENANT',
|
|
811
|
+
sk: 'SETTING#TEST_CODE',
|
|
812
|
+
code: 'TEST_CODE',
|
|
813
|
+
name: 'Test Setting',
|
|
814
|
+
version: 1,
|
|
815
|
+
type: 'MASTER',
|
|
816
|
+
tenantCode: 'TEST_TENANT',
|
|
817
|
+
isDeleted: false,
|
|
818
|
+
createdAt: new Date(),
|
|
819
|
+
updatedAt: new Date(),
|
|
820
|
+
};
|
|
821
|
+
dataService.getItem.mockResolvedValue(existingData);
|
|
822
|
+
const concurrencyError = new Error('Concurrent modification');
|
|
823
|
+
commandService.publishPartialUpdateAsync.mockRejectedValue(concurrencyError);
|
|
824
|
+
await expect(service.updateSetting(key, { settingValue: { updated: true } }, { invokeContext: mockInvokeContext }))
|
|
825
|
+
.rejects.toThrow('Concurrent modification');
|
|
826
|
+
});
|
|
827
|
+
});
|
|
828
|
+
});
|
|
829
|
+
/**
|
|
830
|
+
* Test Overview: Tests edge cases and boundary conditions for MasterSettingService operations
|
|
831
|
+
* Purpose: Ensures the service handles unusual inputs and boundary conditions properly
|
|
832
|
+
* Details: Verifies behavior with empty values, special characters, and malformed data
|
|
833
|
+
*/
|
|
834
|
+
describe('Edge Cases and Boundary Conditions', () => {
|
|
835
|
+
it('should handle empty setting code', async () => {
|
|
836
|
+
await expect(service.getSetting({ code: 'TEST_SETTING' }, { invokeContext: mockInvokeContext }))
|
|
837
|
+
.rejects.toThrow(common_1.BadRequestException);
|
|
838
|
+
});
|
|
839
|
+
it('should handle null setting code', async () => {
|
|
840
|
+
await expect(service.getSetting({ code: null }, { invokeContext: mockInvokeContext }))
|
|
841
|
+
.rejects.toThrow(common_1.BadRequestException);
|
|
842
|
+
});
|
|
843
|
+
it('should handle special characters in setting codes', async () => {
|
|
844
|
+
const specialCode = 'SETTING_特殊文字@#$%';
|
|
845
|
+
const mockCommonSetting = {
|
|
846
|
+
id: 'test-id',
|
|
847
|
+
pk: 'SETTING#COMMON',
|
|
848
|
+
sk: `SETTING#${specialCode}`,
|
|
849
|
+
code: specialCode,
|
|
850
|
+
name: 'Special Setting',
|
|
851
|
+
version: 1,
|
|
852
|
+
type: 'MASTER',
|
|
853
|
+
tenantCode: 'COMMON',
|
|
854
|
+
isDeleted: false,
|
|
855
|
+
attributes: { special: true },
|
|
856
|
+
createdAt: new Date(),
|
|
857
|
+
updatedAt: new Date(),
|
|
858
|
+
};
|
|
859
|
+
dataService.getItem.mockResolvedValue(mockCommonSetting);
|
|
860
|
+
const result = await service.getSetting({ code: specialCode }, { invokeContext: mockInvokeContext });
|
|
861
|
+
expect(result).toBeDefined();
|
|
862
|
+
expect(result).toBeInstanceOf(entities_1.MasterSettingEntity);
|
|
863
|
+
});
|
|
864
|
+
it('should handle missing user context in invoke context', async () => {
|
|
865
|
+
const tenantCode = 'TEST_TENANT';
|
|
866
|
+
const code = 'TEST_SETTING';
|
|
867
|
+
const emptyInvokeContext = {};
|
|
868
|
+
dataService.getItem.mockResolvedValue(null);
|
|
869
|
+
await expect(service.getSetting({ code }, { invokeContext: mockInvokeContext }))
|
|
870
|
+
.rejects.toThrow(common_1.BadRequestException);
|
|
871
|
+
});
|
|
872
|
+
});
|
|
873
|
+
describe('createTenantSetting - Edge Cases', () => {
|
|
874
|
+
it('should handle empty setting values', async () => {
|
|
875
|
+
const dto = {
|
|
876
|
+
tenantCode: 'TEST_TENANT',
|
|
877
|
+
code: 'TEST_SETTING',
|
|
878
|
+
name: 'Test Setting',
|
|
879
|
+
settingValue: {},
|
|
880
|
+
};
|
|
881
|
+
dataService.getItem.mockResolvedValue(null);
|
|
882
|
+
const mockResponse = {
|
|
883
|
+
id: 'test-id',
|
|
884
|
+
pk: 'SETTING#TEST_TENANT',
|
|
885
|
+
sk: 'SETTING#TEST_SETTING',
|
|
886
|
+
version: 1,
|
|
887
|
+
type: 'MASTER',
|
|
888
|
+
tenantCode: 'TEST_TENANT',
|
|
889
|
+
name: 'TEST_SETTING',
|
|
890
|
+
code: 'TEST_SETTING',
|
|
891
|
+
isDeleted: false,
|
|
892
|
+
attributes: {},
|
|
893
|
+
createdAt: new Date(),
|
|
894
|
+
updatedAt: new Date(),
|
|
895
|
+
};
|
|
896
|
+
commandService.publishAsync.mockResolvedValue(mockResponse);
|
|
897
|
+
const result = await service.createTenantSetting(dto, { invokeContext: mockInvokeContext });
|
|
898
|
+
expect(result).toBeInstanceOf(Object);
|
|
899
|
+
expect(result.attributes).toEqual({});
|
|
900
|
+
});
|
|
901
|
+
it('should handle very large setting values', async () => {
|
|
902
|
+
const largeSettingValue = {};
|
|
903
|
+
for (let i = 0; i < 1000; i++) {
|
|
904
|
+
largeSettingValue[`key${i}`] = `value${i}`.repeat(50);
|
|
905
|
+
}
|
|
906
|
+
const dto = {
|
|
907
|
+
tenantCode: 'TEST_TENANT',
|
|
908
|
+
code: 'LARGE_SETTING',
|
|
909
|
+
name: 'Large Setting',
|
|
910
|
+
settingValue: largeSettingValue,
|
|
911
|
+
};
|
|
912
|
+
dataService.getItem.mockResolvedValue(null);
|
|
913
|
+
const mockResponse = {
|
|
914
|
+
id: 'test-id',
|
|
915
|
+
pk: 'SETTING#TEST_TENANT',
|
|
916
|
+
sk: 'SETTING#LARGE_SETTING',
|
|
917
|
+
version: 1,
|
|
918
|
+
type: 'MASTER',
|
|
919
|
+
tenantCode: 'TEST_TENANT',
|
|
920
|
+
name: 'LARGE_SETTING',
|
|
921
|
+
code: 'LARGE_SETTING',
|
|
922
|
+
isDeleted: false,
|
|
923
|
+
attributes: largeSettingValue,
|
|
924
|
+
createdAt: new Date(),
|
|
925
|
+
updatedAt: new Date(),
|
|
926
|
+
};
|
|
927
|
+
commandService.publishAsync.mockResolvedValue(mockResponse);
|
|
928
|
+
const result = await service.createTenantSetting(dto, { invokeContext: mockInvokeContext });
|
|
929
|
+
expect(result).toBeInstanceOf(Object);
|
|
930
|
+
expect(Object.keys(result.attributes)).toHaveLength(1000);
|
|
931
|
+
});
|
|
932
|
+
});
|
|
933
|
+
/**
|
|
934
|
+
* Test Overview: Tests comprehensive deleted setting re-addition scenarios for MasterSettingService
|
|
935
|
+
* Purpose: Ensures deleted settings can be properly recreated for all setting types with correct version handling
|
|
936
|
+
* Details: Verifies version increment, attribute preservation, and state transitions for common, tenant, group, and user settings
|
|
937
|
+
*/
|
|
938
|
+
describe('Deleted Setting Re-addition Scenarios', () => {
|
|
939
|
+
describe('createCommonTenantSetting - Deleted Setting Recreation', () => {
|
|
940
|
+
it('should recreate deleted common setting with incremented version', async () => {
|
|
941
|
+
const dto = {
|
|
942
|
+
code: 'RECREATED_SETTING',
|
|
943
|
+
name: 'Recreated Setting',
|
|
944
|
+
settingValue: { recreated: true, version: 2 },
|
|
945
|
+
};
|
|
946
|
+
const existingDeletedSetting = {
|
|
947
|
+
id: 'existing-id',
|
|
948
|
+
pk: 'SETTING#COMMON',
|
|
949
|
+
sk: 'SETTING#RECREATED_SETTING',
|
|
950
|
+
code: 'RECREATED_SETTING',
|
|
951
|
+
name: 'RECREATED_SETTING',
|
|
952
|
+
version: 3,
|
|
953
|
+
type: 'MASTER',
|
|
954
|
+
tenantCode: 'COMMON',
|
|
955
|
+
isDeleted: true,
|
|
956
|
+
attributes: { original: true, version: 1 },
|
|
957
|
+
createdAt: new Date('2023-01-01'),
|
|
958
|
+
updatedAt: new Date('2023-01-02'),
|
|
959
|
+
};
|
|
960
|
+
dataService.getItem.mockResolvedValue(existingDeletedSetting);
|
|
961
|
+
const mockResponse = {
|
|
962
|
+
id: 'existing-id',
|
|
963
|
+
pk: 'SETTING#COMMON',
|
|
964
|
+
sk: 'SETTING#RECREATED_SETTING',
|
|
965
|
+
version: 3,
|
|
966
|
+
type: 'MASTER',
|
|
967
|
+
tenantCode: 'COMMON',
|
|
968
|
+
name: 'RECREATED_SETTING',
|
|
969
|
+
code: 'RECREATED_SETTING',
|
|
970
|
+
isDeleted: false,
|
|
971
|
+
attributes: dto.settingValue,
|
|
972
|
+
createdAt: new Date('2023-01-01'),
|
|
973
|
+
updatedAt: new Date(),
|
|
974
|
+
};
|
|
975
|
+
commandService.publishAsync.mockResolvedValue(mockResponse);
|
|
976
|
+
const result = await service.createCommonTenantSetting(dto, { invokeContext: mockInvokeContext });
|
|
977
|
+
expect(result).toBeInstanceOf(Object);
|
|
978
|
+
expect(result.version).toBe(3);
|
|
979
|
+
expect(result.isDeleted).toBe(false);
|
|
980
|
+
expect(result.attributes).toEqual({ recreated: true, version: 2 });
|
|
981
|
+
expect(commandService.publishAsync).toHaveBeenCalledWith(expect.objectContaining({
|
|
982
|
+
version: 3,
|
|
983
|
+
isDeleted: false,
|
|
984
|
+
attributes: { recreated: true, version: 2 },
|
|
985
|
+
}), { invokeContext: mockInvokeContext });
|
|
986
|
+
});
|
|
987
|
+
it('should handle multiple deletion and recreation cycles for common settings', async () => {
|
|
988
|
+
const dto = {
|
|
989
|
+
code: 'CYCLED_SETTING',
|
|
990
|
+
name: 'Cycled Setting',
|
|
991
|
+
settingValue: { cycle: 4, final: true },
|
|
992
|
+
};
|
|
993
|
+
const existingDeletedSetting = {
|
|
994
|
+
id: 'existing-id',
|
|
995
|
+
pk: 'SETTING#COMMON',
|
|
996
|
+
sk: 'SETTING#CYCLED_SETTING',
|
|
997
|
+
code: 'CYCLED_SETTING',
|
|
998
|
+
name: 'CYCLED_SETTING',
|
|
999
|
+
version: 7,
|
|
1000
|
+
type: 'MASTER',
|
|
1001
|
+
tenantCode: 'COMMON',
|
|
1002
|
+
isDeleted: true,
|
|
1003
|
+
attributes: { cycle: 3, previous: true },
|
|
1004
|
+
createdAt: new Date('2023-01-01'),
|
|
1005
|
+
updatedAt: new Date('2023-01-04'),
|
|
1006
|
+
};
|
|
1007
|
+
dataService.getItem.mockResolvedValue(existingDeletedSetting);
|
|
1008
|
+
const mockResponse = {
|
|
1009
|
+
id: 'existing-id',
|
|
1010
|
+
pk: 'SETTING#COMMON',
|
|
1011
|
+
sk: 'SETTING#CYCLED_SETTING',
|
|
1012
|
+
version: 7,
|
|
1013
|
+
type: 'MASTER',
|
|
1014
|
+
tenantCode: 'COMMON',
|
|
1015
|
+
name: 'CYCLED_SETTING',
|
|
1016
|
+
code: 'CYCLED_SETTING',
|
|
1017
|
+
isDeleted: false,
|
|
1018
|
+
attributes: dto.settingValue,
|
|
1019
|
+
createdAt: new Date('2023-01-01'),
|
|
1020
|
+
updatedAt: new Date(),
|
|
1021
|
+
};
|
|
1022
|
+
commandService.publishAsync.mockResolvedValue(mockResponse);
|
|
1023
|
+
const result = await service.createCommonTenantSetting(dto, { invokeContext: mockInvokeContext });
|
|
1024
|
+
expect(result).toBeInstanceOf(Object);
|
|
1025
|
+
expect(result.version).toBe(7);
|
|
1026
|
+
expect(result.isDeleted).toBe(false);
|
|
1027
|
+
expect(result.attributes).toEqual({ cycle: 4, final: true });
|
|
1028
|
+
});
|
|
1029
|
+
});
|
|
1030
|
+
describe('createTenantSetting - Deleted Setting Recreation', () => {
|
|
1031
|
+
it('should recreate deleted tenant setting with proper tenant isolation', async () => {
|
|
1032
|
+
const dto = {
|
|
1033
|
+
tenantCode: 'TENANT_A',
|
|
1034
|
+
code: 'TENANT_SETTING',
|
|
1035
|
+
name: 'Tenant Setting',
|
|
1036
|
+
settingValue: { tenant: 'A', recreated: true },
|
|
1037
|
+
};
|
|
1038
|
+
const existingDeletedSetting = {
|
|
1039
|
+
id: 'existing-id',
|
|
1040
|
+
pk: 'SETTING#TENANT_A',
|
|
1041
|
+
sk: 'SETTING#TENANT_SETTING',
|
|
1042
|
+
code: 'TENANT_SETTING',
|
|
1043
|
+
name: 'TENANT_SETTING',
|
|
1044
|
+
version: 2,
|
|
1045
|
+
type: 'MASTER',
|
|
1046
|
+
tenantCode: 'TENANT_A',
|
|
1047
|
+
isDeleted: true,
|
|
1048
|
+
attributes: { tenant: 'A', original: true },
|
|
1049
|
+
createdAt: new Date('2023-01-01'),
|
|
1050
|
+
updatedAt: new Date('2023-01-02'),
|
|
1051
|
+
};
|
|
1052
|
+
dataService.getItem.mockResolvedValue(existingDeletedSetting);
|
|
1053
|
+
const mockResponse = {
|
|
1054
|
+
id: 'existing-id',
|
|
1055
|
+
pk: 'SETTING#TENANT_A',
|
|
1056
|
+
sk: 'SETTING#TENANT_SETTING',
|
|
1057
|
+
version: 2,
|
|
1058
|
+
type: 'MASTER',
|
|
1059
|
+
tenantCode: 'TENANT_A',
|
|
1060
|
+
name: 'TENANT_SETTING',
|
|
1061
|
+
code: 'TENANT_SETTING',
|
|
1062
|
+
isDeleted: false,
|
|
1063
|
+
attributes: dto.settingValue,
|
|
1064
|
+
createdAt: new Date('2023-01-01'),
|
|
1065
|
+
updatedAt: new Date(),
|
|
1066
|
+
};
|
|
1067
|
+
commandService.publishAsync.mockResolvedValue(mockResponse);
|
|
1068
|
+
const result = await service.createTenantSetting(dto, { invokeContext: mockInvokeContext });
|
|
1069
|
+
expect(result).toBeInstanceOf(Object);
|
|
1070
|
+
expect(result.version).toBe(2);
|
|
1071
|
+
expect(result.tenantCode).toBe('TENANT_A');
|
|
1072
|
+
expect(result.isDeleted).toBe(false);
|
|
1073
|
+
expect(result.attributes).toEqual({ tenant: 'A', recreated: true });
|
|
1074
|
+
});
|
|
1075
|
+
it('should handle tenant setting recreation with different tenant codes', async () => {
|
|
1076
|
+
const dto = {
|
|
1077
|
+
tenantCode: 'TENANT_B',
|
|
1078
|
+
code: 'SHARED_SETTING',
|
|
1079
|
+
name: 'Shared Setting',
|
|
1080
|
+
settingValue: { tenant: 'B', value: 'new' },
|
|
1081
|
+
};
|
|
1082
|
+
dataService.getItem.mockResolvedValue(null);
|
|
1083
|
+
const mockResponse = {
|
|
1084
|
+
id: 'new-id',
|
|
1085
|
+
pk: 'SETTING#TENANT_B',
|
|
1086
|
+
sk: 'SETTING#SHARED_SETTING',
|
|
1087
|
+
version: 1,
|
|
1088
|
+
type: 'MASTER',
|
|
1089
|
+
tenantCode: 'TENANT_B',
|
|
1090
|
+
name: 'SHARED_SETTING',
|
|
1091
|
+
code: 'SHARED_SETTING',
|
|
1092
|
+
isDeleted: false,
|
|
1093
|
+
attributes: dto.settingValue,
|
|
1094
|
+
createdAt: new Date(),
|
|
1095
|
+
updatedAt: new Date(),
|
|
1096
|
+
};
|
|
1097
|
+
commandService.publishAsync.mockResolvedValue(mockResponse);
|
|
1098
|
+
const result = await service.createTenantSetting(dto, { invokeContext: mockInvokeContext });
|
|
1099
|
+
expect(result).toBeInstanceOf(Object);
|
|
1100
|
+
expect(result.version).toBe(1);
|
|
1101
|
+
expect(result.tenantCode).toBe('TENANT_B');
|
|
1102
|
+
expect(result.isDeleted).toBe(false);
|
|
1103
|
+
});
|
|
1104
|
+
});
|
|
1105
|
+
describe('createGroupSetting - Deleted Setting Recreation', () => {
|
|
1106
|
+
it('should recreate deleted group setting with group hierarchy validation', async () => {
|
|
1107
|
+
const dto = {
|
|
1108
|
+
tenantCode: 'TEST_TENANT',
|
|
1109
|
+
groupId: 'GROUP_123',
|
|
1110
|
+
code: 'GROUP_SETTING',
|
|
1111
|
+
name: 'Group Setting',
|
|
1112
|
+
settingValue: { group: 'GROUP_123', recreated: true },
|
|
1113
|
+
};
|
|
1114
|
+
const existingDeletedSetting = {
|
|
1115
|
+
id: 'existing-id',
|
|
1116
|
+
pk: 'SETTING#TEST_TENANT',
|
|
1117
|
+
sk: 'SETTING#GROUP#GROUP_123#GROUP_SETTING',
|
|
1118
|
+
code: 'GROUP_SETTING',
|
|
1119
|
+
name: 'GROUP_SETTING',
|
|
1120
|
+
version: 4,
|
|
1121
|
+
type: 'MASTER',
|
|
1122
|
+
tenantCode: 'TEST_TENANT',
|
|
1123
|
+
isDeleted: true,
|
|
1124
|
+
attributes: { group: 'GROUP_123', original: true },
|
|
1125
|
+
createdAt: new Date('2023-01-01'),
|
|
1126
|
+
updatedAt: new Date('2023-01-03'),
|
|
1127
|
+
};
|
|
1128
|
+
dataService.getItem.mockResolvedValue(existingDeletedSetting);
|
|
1129
|
+
const mockResponse = {
|
|
1130
|
+
id: 'existing-id',
|
|
1131
|
+
pk: 'SETTING#TEST_TENANT',
|
|
1132
|
+
sk: 'SETTING#GROUP#GROUP_123#GROUP_SETTING',
|
|
1133
|
+
version: 4,
|
|
1134
|
+
type: 'MASTER',
|
|
1135
|
+
tenantCode: 'TEST_TENANT',
|
|
1136
|
+
name: 'GROUP_SETTING',
|
|
1137
|
+
code: 'GROUP_SETTING',
|
|
1138
|
+
isDeleted: false,
|
|
1139
|
+
attributes: dto.settingValue,
|
|
1140
|
+
createdAt: new Date('2023-01-01'),
|
|
1141
|
+
updatedAt: new Date(),
|
|
1142
|
+
};
|
|
1143
|
+
commandService.publishAsync.mockResolvedValue(mockResponse);
|
|
1144
|
+
const result = await service.createGroupSetting(dto, { invokeContext: mockInvokeContext });
|
|
1145
|
+
expect(result).toBeInstanceOf(Object);
|
|
1146
|
+
expect(result.version).toBe(4);
|
|
1147
|
+
expect(result.tenantCode).toBe('TEST_TENANT');
|
|
1148
|
+
expect(result.isDeleted).toBe(false);
|
|
1149
|
+
expect(result.attributes).toEqual({ group: 'GROUP_123', recreated: true });
|
|
1150
|
+
});
|
|
1151
|
+
it('should handle group setting recreation across different groups', async () => {
|
|
1152
|
+
const dto = {
|
|
1153
|
+
tenantCode: 'TEST_TENANT',
|
|
1154
|
+
groupId: 'GROUP_456',
|
|
1155
|
+
code: 'SHARED_GROUP_SETTING',
|
|
1156
|
+
name: 'Shared Group Setting',
|
|
1157
|
+
settingValue: { group: 'GROUP_456', value: 'different' },
|
|
1158
|
+
};
|
|
1159
|
+
dataService.getItem.mockResolvedValue(null);
|
|
1160
|
+
const mockResponse = {
|
|
1161
|
+
id: 'new-id',
|
|
1162
|
+
pk: 'SETTING#TEST_TENANT',
|
|
1163
|
+
sk: 'SETTING#GROUP#GROUP_456#SHARED_GROUP_SETTING',
|
|
1164
|
+
version: 1,
|
|
1165
|
+
type: 'MASTER',
|
|
1166
|
+
tenantCode: 'TEST_TENANT',
|
|
1167
|
+
name: 'SHARED_GROUP_SETTING',
|
|
1168
|
+
code: 'SHARED_GROUP_SETTING',
|
|
1169
|
+
isDeleted: false,
|
|
1170
|
+
attributes: dto.settingValue,
|
|
1171
|
+
createdAt: new Date(),
|
|
1172
|
+
updatedAt: new Date(),
|
|
1173
|
+
};
|
|
1174
|
+
commandService.publishAsync.mockResolvedValue(mockResponse);
|
|
1175
|
+
const result = await service.createGroupSetting(dto, { invokeContext: mockInvokeContext });
|
|
1176
|
+
expect(result).toBeInstanceOf(Object);
|
|
1177
|
+
expect(result.version).toBe(1);
|
|
1178
|
+
expect(result.isDeleted).toBe(false);
|
|
1179
|
+
expect(result.attributes).toEqual({ group: 'GROUP_456', value: 'different' });
|
|
1180
|
+
});
|
|
1181
|
+
});
|
|
1182
|
+
describe('createUserSetting - Deleted Setting Recreation', () => {
|
|
1183
|
+
it('should recreate deleted user setting with user context validation', async () => {
|
|
1184
|
+
const dto = {
|
|
1185
|
+
tenantCode: 'TEST_TENANT',
|
|
1186
|
+
userId: 'USER_789',
|
|
1187
|
+
code: 'USER_SETTING',
|
|
1188
|
+
name: 'User Setting',
|
|
1189
|
+
settingValue: { user: 'USER_789', recreated: true },
|
|
1190
|
+
};
|
|
1191
|
+
const existingDeletedSetting = {
|
|
1192
|
+
id: 'existing-id',
|
|
1193
|
+
pk: 'SETTING#TEST_TENANT',
|
|
1194
|
+
sk: 'SETTING#USER#USER_789#USER_SETTING',
|
|
1195
|
+
code: 'USER_SETTING',
|
|
1196
|
+
name: 'USER_SETTING',
|
|
1197
|
+
version: 6,
|
|
1198
|
+
type: 'MASTER',
|
|
1199
|
+
tenantCode: 'TEST_TENANT',
|
|
1200
|
+
isDeleted: true,
|
|
1201
|
+
attributes: { user: 'USER_789', original: true },
|
|
1202
|
+
createdAt: new Date('2023-01-01'),
|
|
1203
|
+
updatedAt: new Date('2023-01-05'),
|
|
1204
|
+
};
|
|
1205
|
+
dataService.getItem.mockResolvedValue(existingDeletedSetting);
|
|
1206
|
+
const mockResponse = {
|
|
1207
|
+
id: 'existing-id',
|
|
1208
|
+
pk: 'SETTING#TEST_TENANT',
|
|
1209
|
+
sk: 'SETTING#USER#USER_789#USER_SETTING',
|
|
1210
|
+
version: 6,
|
|
1211
|
+
type: 'MASTER',
|
|
1212
|
+
tenantCode: 'TEST_TENANT',
|
|
1213
|
+
name: 'USER_SETTING',
|
|
1214
|
+
code: 'USER_SETTING',
|
|
1215
|
+
isDeleted: false,
|
|
1216
|
+
attributes: dto.settingValue,
|
|
1217
|
+
createdAt: new Date('2023-01-01'),
|
|
1218
|
+
updatedAt: new Date(),
|
|
1219
|
+
};
|
|
1220
|
+
commandService.publishAsync.mockResolvedValue(mockResponse);
|
|
1221
|
+
const result = await service.createUserSetting(dto, { invokeContext: mockInvokeContext });
|
|
1222
|
+
expect(result).toBeInstanceOf(Object);
|
|
1223
|
+
expect(result.version).toBe(6);
|
|
1224
|
+
expect(result.tenantCode).toBe('TEST_TENANT');
|
|
1225
|
+
expect(result.isDeleted).toBe(false);
|
|
1226
|
+
expect(result.attributes).toEqual({ user: 'USER_789', recreated: true });
|
|
1227
|
+
});
|
|
1228
|
+
it('should preserve original creation timestamp when recreating user setting', async () => {
|
|
1229
|
+
const originalCreatedAt = new Date('2023-01-01T08:00:00Z');
|
|
1230
|
+
const dto = {
|
|
1231
|
+
tenantCode: 'TEST_TENANT',
|
|
1232
|
+
userId: 'USER_ABC',
|
|
1233
|
+
code: 'TIMESTAMP_SETTING',
|
|
1234
|
+
name: 'Timestamp Setting',
|
|
1235
|
+
settingValue: { preserveTimestamp: true },
|
|
1236
|
+
};
|
|
1237
|
+
const existingDeletedSetting = {
|
|
1238
|
+
id: 'existing-id',
|
|
1239
|
+
pk: 'SETTING#TEST_TENANT',
|
|
1240
|
+
sk: 'SETTING#USER#USER_ABC#TIMESTAMP_SETTING',
|
|
1241
|
+
code: 'TIMESTAMP_SETTING',
|
|
1242
|
+
name: 'TIMESTAMP_SETTING',
|
|
1243
|
+
version: 3,
|
|
1244
|
+
type: 'MASTER',
|
|
1245
|
+
tenantCode: 'TEST_TENANT',
|
|
1246
|
+
isDeleted: true,
|
|
1247
|
+
attributes: { original: true },
|
|
1248
|
+
createdAt: originalCreatedAt,
|
|
1249
|
+
updatedAt: new Date('2023-01-02'),
|
|
1250
|
+
};
|
|
1251
|
+
dataService.getItem.mockResolvedValue(existingDeletedSetting);
|
|
1252
|
+
const mockResponse = {
|
|
1253
|
+
id: 'existing-id',
|
|
1254
|
+
pk: 'SETTING#TEST_TENANT',
|
|
1255
|
+
sk: 'SETTING#USER#USER_ABC#TIMESTAMP_SETTING',
|
|
1256
|
+
version: 3,
|
|
1257
|
+
type: 'MASTER',
|
|
1258
|
+
tenantCode: 'TEST_TENANT',
|
|
1259
|
+
name: 'TIMESTAMP_SETTING',
|
|
1260
|
+
code: 'TIMESTAMP_SETTING',
|
|
1261
|
+
isDeleted: false,
|
|
1262
|
+
attributes: dto.settingValue,
|
|
1263
|
+
createdAt: originalCreatedAt,
|
|
1264
|
+
updatedAt: new Date(),
|
|
1265
|
+
};
|
|
1266
|
+
commandService.publishAsync.mockResolvedValue(mockResponse);
|
|
1267
|
+
const result = await service.createUserSetting(dto, { invokeContext: mockInvokeContext });
|
|
1268
|
+
expect(result).toBeInstanceOf(Object);
|
|
1269
|
+
expect(result.createdAt).toEqual(originalCreatedAt);
|
|
1270
|
+
expect(result.isDeleted).toBe(false);
|
|
1271
|
+
expect(result.attributes).toEqual({ preserveTimestamp: true });
|
|
1272
|
+
});
|
|
1273
|
+
});
|
|
1274
|
+
});
|
|
1275
|
+
/**
|
|
1276
|
+
* Test Overview: Tests concurrent operation scenarios for MasterSettingService
|
|
1277
|
+
* Purpose: Ensures the service handles simultaneous operations correctly with proper version control
|
|
1278
|
+
* Details: Verifies race condition handling, version conflicts, and concurrent hierarchical setting operations
|
|
1279
|
+
*/
|
|
1280
|
+
describe('Concurrent Operation Scenarios', () => {
|
|
1281
|
+
describe('getSetting - Concurrent Hierarchical Access', () => {
|
|
1282
|
+
it('should handle concurrent hierarchical setting access correctly', async () => {
|
|
1283
|
+
const tenantCode = 'TEST_TENANT';
|
|
1284
|
+
const code = 'CONCURRENT_SETTING';
|
|
1285
|
+
const mockCommonSetting = {
|
|
1286
|
+
id: 'test-id',
|
|
1287
|
+
pk: 'SETTING#COMMON',
|
|
1288
|
+
sk: 'SETTING#CONCURRENT_SETTING',
|
|
1289
|
+
code: 'CONCURRENT_SETTING',
|
|
1290
|
+
name: 'Concurrent Setting',
|
|
1291
|
+
version: 1,
|
|
1292
|
+
type: 'MASTER',
|
|
1293
|
+
tenantCode: 'COMMON',
|
|
1294
|
+
isDeleted: false,
|
|
1295
|
+
attributes: { concurrent: true },
|
|
1296
|
+
createdAt: new Date(),
|
|
1297
|
+
updatedAt: new Date(),
|
|
1298
|
+
};
|
|
1299
|
+
dataService.getItem.mockResolvedValue(mockCommonSetting);
|
|
1300
|
+
const promises = Array.from({ length: 5 }, () => service.getSetting({ code }, { invokeContext: mockInvokeContext }));
|
|
1301
|
+
const results = await Promise.all(promises);
|
|
1302
|
+
results.forEach(result => {
|
|
1303
|
+
expect(result).toBeInstanceOf(entities_1.MasterSettingEntity);
|
|
1304
|
+
expect(result).toBeDefined();
|
|
1305
|
+
});
|
|
1306
|
+
});
|
|
1307
|
+
it('should handle mixed success and failure in concurrent hierarchical access', async () => {
|
|
1308
|
+
const tenantCode = 'TEST_TENANT';
|
|
1309
|
+
const code = 'MIXED_SETTING';
|
|
1310
|
+
dataService.getItem
|
|
1311
|
+
.mockResolvedValueOnce(null)
|
|
1312
|
+
.mockRejectedValueOnce(new Error('User fetch failed'))
|
|
1313
|
+
.mockResolvedValueOnce(null);
|
|
1314
|
+
const results = await Promise.allSettled([
|
|
1315
|
+
service.getSetting({ code }, { invokeContext: mockInvokeContext }),
|
|
1316
|
+
service.getSetting({ code }, { invokeContext: mockInvokeContext }),
|
|
1317
|
+
service.getSetting({ code }, { invokeContext: mockInvokeContext })
|
|
1318
|
+
]);
|
|
1319
|
+
expect(results[0].status).toBe('rejected');
|
|
1320
|
+
expect(results[1].status).toBe('rejected');
|
|
1321
|
+
expect(results[2].status).toBe('rejected');
|
|
1322
|
+
});
|
|
1323
|
+
});
|
|
1324
|
+
describe('createTenantSetting - Concurrent Operations', () => {
|
|
1325
|
+
it('should handle concurrent tenant setting creation with version conflicts', async () => {
|
|
1326
|
+
const dto1 = {
|
|
1327
|
+
tenantCode: 'TEST_TENANT',
|
|
1328
|
+
code: 'CONCURRENT_SETTING',
|
|
1329
|
+
name: 'Concurrent Setting 1',
|
|
1330
|
+
settingValue: { first: true },
|
|
1331
|
+
};
|
|
1332
|
+
const dto2 = {
|
|
1333
|
+
tenantCode: 'TEST_TENANT',
|
|
1334
|
+
code: 'CONCURRENT_SETTING',
|
|
1335
|
+
name: 'Concurrent Setting 2',
|
|
1336
|
+
settingValue: { second: true },
|
|
1337
|
+
};
|
|
1338
|
+
dataService.getItem.mockResolvedValue(null);
|
|
1339
|
+
const mockResponse1 = {
|
|
1340
|
+
id: 'test-id-1',
|
|
1341
|
+
pk: 'SETTING#TEST_TENANT',
|
|
1342
|
+
sk: 'SETTING#CONCURRENT_SETTING',
|
|
1343
|
+
version: 1,
|
|
1344
|
+
type: 'MASTER',
|
|
1345
|
+
tenantCode: 'TEST_TENANT',
|
|
1346
|
+
name: 'CONCURRENT_SETTING',
|
|
1347
|
+
code: 'CONCURRENT_SETTING',
|
|
1348
|
+
isDeleted: false,
|
|
1349
|
+
attributes: dto1.settingValue,
|
|
1350
|
+
createdAt: new Date(),
|
|
1351
|
+
updatedAt: new Date(),
|
|
1352
|
+
};
|
|
1353
|
+
const versionConflictError = new Error('Version conflict');
|
|
1354
|
+
versionConflictError.name = 'ConditionalCheckFailedException';
|
|
1355
|
+
commandService.publishAsync
|
|
1356
|
+
.mockResolvedValueOnce(mockResponse1)
|
|
1357
|
+
.mockRejectedValueOnce(versionConflictError);
|
|
1358
|
+
const result1 = await service.createTenantSetting(dto1, { invokeContext: mockInvokeContext });
|
|
1359
|
+
await expect(service.createTenantSetting(dto2, { invokeContext: mockInvokeContext }))
|
|
1360
|
+
.rejects.toThrow('Version conflict');
|
|
1361
|
+
expect(result1).toBeInstanceOf(Object);
|
|
1362
|
+
expect(result1.attributes).toEqual({ first: true });
|
|
1363
|
+
});
|
|
1364
|
+
});
|
|
1365
|
+
describe('updateSetting - Concurrent Operations', () => {
|
|
1366
|
+
it('should handle concurrent setting updates with proper version control', async () => {
|
|
1367
|
+
const key = { pk: 'SETTING#TEST_TENANT', sk: 'SETTING#UPDATE_TEST' };
|
|
1368
|
+
const existingData = {
|
|
1369
|
+
id: 'test-id',
|
|
1370
|
+
pk: 'SETTING#TEST_TENANT',
|
|
1371
|
+
sk: 'SETTING#UPDATE_TEST',
|
|
1372
|
+
code: 'UPDATE_TEST',
|
|
1373
|
+
name: 'Update Test',
|
|
1374
|
+
version: 1,
|
|
1375
|
+
type: 'MASTER',
|
|
1376
|
+
tenantCode: 'TEST_TENANT',
|
|
1377
|
+
isDeleted: false,
|
|
1378
|
+
createdAt: new Date(),
|
|
1379
|
+
updatedAt: new Date(),
|
|
1380
|
+
};
|
|
1381
|
+
dataService.getItem.mockResolvedValue(existingData);
|
|
1382
|
+
const mockUpdateResult1 = {
|
|
1383
|
+
...existingData,
|
|
1384
|
+
version: 2,
|
|
1385
|
+
updatedAt: new Date(),
|
|
1386
|
+
};
|
|
1387
|
+
const versionConflictError = new Error('Version conflict');
|
|
1388
|
+
versionConflictError.name = 'ConditionalCheckFailedException';
|
|
1389
|
+
commandService.publishPartialUpdateAsync
|
|
1390
|
+
.mockResolvedValueOnce(mockUpdateResult1)
|
|
1391
|
+
.mockRejectedValueOnce(versionConflictError);
|
|
1392
|
+
const result1 = await service.updateSetting(key, { settingValue: { updated: true } }, { invokeContext: mockInvokeContext });
|
|
1393
|
+
await expect(service.updateSetting(key, { settingValue: { updated: true } }, { invokeContext: mockInvokeContext }))
|
|
1394
|
+
.rejects.toThrow('Version conflict');
|
|
1395
|
+
expect(result1.version).toBe(2);
|
|
1396
|
+
});
|
|
1397
|
+
});
|
|
1398
|
+
});
|
|
677
1399
|
});
|
|
678
1400
|
//# sourceMappingURL=master-setting.service.spec.js.map
|