123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404 |
- import 'reflect-metadata'
- import { Logger } from 'winston'
- import { EncryptionVersion } from '../Encryption/EncryptionVersion'
- import { SubscriptionSettingService } from './SubscriptionSettingService'
- import { SettingDecrypterInterface } from './SettingDecrypterInterface'
- import { SubscriptionSettingRepositoryInterface } from './SubscriptionSettingRepositoryInterface'
- import { SubscriptionSetting } from './SubscriptionSetting'
- import { UserSubscription } from '../Subscription/UserSubscription'
- import { SubscriptionName } from '@standardnotes/common'
- import { User } from '../User/User'
- import { SettingFactoryInterface } from './SettingFactoryInterface'
- import { SubscriptionSettingsAssociationServiceInterface } from './SubscriptionSettingsAssociationServiceInterface'
- import { UserSubscriptionRepositoryInterface } from '../Subscription/UserSubscriptionRepositoryInterface'
- import { SettingName } from '@standardnotes/settings'
- import { SettingInterpreterInterface } from './SettingInterpreterInterface'
- describe('SubscriptionSettingService', () => {
- let setting: SubscriptionSetting
- let user: User
- let userSubscription: UserSubscription
- let factory: SettingFactoryInterface
- let subscriptionSettingRepository: SubscriptionSettingRepositoryInterface
- let subscriptionSettingsAssociationService: SubscriptionSettingsAssociationServiceInterface
- let settingInterpreter: SettingInterpreterInterface
- let settingDecrypter: SettingDecrypterInterface
- let userSubscriptionRepository: UserSubscriptionRepositoryInterface
- let logger: Logger
- const createService = () =>
- new SubscriptionSettingService(
- factory,
- subscriptionSettingRepository,
- subscriptionSettingsAssociationService,
- settingInterpreter,
- settingDecrypter,
- userSubscriptionRepository,
- logger,
- )
- beforeEach(() => {
- user = {} as jest.Mocked<User>
- userSubscription = {
- uuid: '1-2-3',
- user: Promise.resolve(user),
- planName: SubscriptionName.PlusPlan,
- } as jest.Mocked<UserSubscription>
- setting = {
- name: SettingName.NAMES.FileUploadBytesUsed,
- } as jest.Mocked<SubscriptionSetting>
- factory = {} as jest.Mocked<SettingFactoryInterface>
- factory.createSubscriptionSetting = jest.fn().mockReturnValue(setting)
- factory.createSubscriptionSettingReplacement = jest.fn().mockReturnValue(setting)
- subscriptionSettingRepository = {} as jest.Mocked<SubscriptionSettingRepositoryInterface>
- subscriptionSettingRepository.findLastByNameAndUserSubscriptionUuid = jest.fn().mockReturnValue(null)
- subscriptionSettingRepository.save = jest.fn().mockImplementation((setting) => setting)
- userSubscriptionRepository = {} as jest.Mocked<UserSubscriptionRepositoryInterface>
- userSubscriptionRepository.findByUserUuid = jest.fn().mockReturnValue([
- {
- uuid: 's-1-2-3',
- } as jest.Mocked<UserSubscription>,
- {
- uuid: 's-2-3-4',
- } as jest.Mocked<UserSubscription>,
- ])
- subscriptionSettingsAssociationService = {} as jest.Mocked<SubscriptionSettingsAssociationServiceInterface>
- subscriptionSettingsAssociationService.getDefaultSettingsAndValuesForSubscriptionName = jest.fn().mockReturnValue(
- new Map([
- [
- SettingName.NAMES.FileUploadBytesUsed,
- {
- value: '0',
- sensitive: 0,
- serverEncryptionVersion: EncryptionVersion.Unencrypted,
- replaceable: true,
- },
- ],
- ]),
- )
- settingInterpreter = {} as jest.Mocked<SettingInterpreterInterface>
- settingInterpreter.interpretSettingUpdated = jest.fn()
- settingDecrypter = {} as jest.Mocked<SettingDecrypterInterface>
- settingDecrypter.decryptSettingValue = jest.fn().mockReturnValue('decrypted')
- logger = {} as jest.Mocked<Logger>
- logger.debug = jest.fn()
- logger.warn = jest.fn()
- logger.error = jest.fn()
- })
- it('should create default settings for a subscription', async () => {
- await createService().applyDefaultSubscriptionSettingsForSubscription(userSubscription)
- expect(subscriptionSettingRepository.save).toHaveBeenCalledWith(setting)
- })
- it('should create default settings for a subscription with overrides', async () => {
- subscriptionSettingsAssociationService.getDefaultSettingsAndValuesForSubscriptionName = jest.fn().mockReturnValue(
- new Map([
- [
- SettingName.NAMES.FileUploadBytesUsed,
- {
- value: '0',
- sensitive: 0,
- serverEncryptionVersion: EncryptionVersion.Unencrypted,
- replaceable: false,
- },
- ],
- [
- SettingName.NAMES.FileUploadBytesLimit,
- {
- value: '345',
- sensitive: 0,
- serverEncryptionVersion: EncryptionVersion.Unencrypted,
- replaceable: true,
- },
- ],
- ]),
- )
- await createService().applyDefaultSubscriptionSettingsForSubscription(
- userSubscription,
- new Map([[SettingName.NAMES.FileUploadBytesLimit, '123']]),
- )
- expect(factory.createSubscriptionSetting).toHaveBeenNthCalledWith(
- 1,
- {
- name: SettingName.NAMES.FileUploadBytesUsed,
- sensitive: 0,
- serverEncryptionVersion: EncryptionVersion.Unencrypted,
- unencryptedValue: '0',
- },
- {
- planName: SubscriptionName.PlusPlan,
- user: Promise.resolve(user),
- uuid: '1-2-3',
- },
- )
- expect(factory.createSubscriptionSetting).toHaveBeenNthCalledWith(
- 2,
- {
- name: SettingName.NAMES.FileUploadBytesLimit,
- sensitive: 0,
- serverEncryptionVersion: EncryptionVersion.Unencrypted,
- unencryptedValue: '123',
- },
- {
- planName: SubscriptionName.PlusPlan,
- user: Promise.resolve(user),
- uuid: '1-2-3',
- },
- )
- })
- it('should throw error if subscription setting is invalid', async () => {
- subscriptionSettingsAssociationService.getDefaultSettingsAndValuesForSubscriptionName = jest.fn().mockReturnValue(
- new Map([
- [
- 'invalid',
- {
- value: '0',
- sensitive: 0,
- serverEncryptionVersion: EncryptionVersion.Unencrypted,
- replaceable: true,
- },
- ],
- ]),
- )
- await expect(createService().applyDefaultSubscriptionSettingsForSubscription(userSubscription)).rejects.toThrow()
- })
- it('should throw error if setting name is not a subscription setting when applying defaults', async () => {
- subscriptionSettingsAssociationService.getDefaultSettingsAndValuesForSubscriptionName = jest.fn().mockReturnValue(
- new Map([
- [
- SettingName.NAMES.DropboxBackupFrequency,
- {
- value: '0',
- sensitive: 0,
- serverEncryptionVersion: EncryptionVersion.Unencrypted,
- replaceable: false,
- },
- ],
- ]),
- )
- await expect(createService().applyDefaultSubscriptionSettingsForSubscription(userSubscription)).rejects.toThrow()
- })
- it('should reassign existing default settings for a subscription if it is not replaceable', async () => {
- subscriptionSettingsAssociationService.getDefaultSettingsAndValuesForSubscriptionName = jest.fn().mockReturnValue(
- new Map([
- [
- SettingName.NAMES.FileUploadBytesUsed,
- {
- value: '0',
- sensitive: 0,
- serverEncryptionVersion: EncryptionVersion.Unencrypted,
- replaceable: false,
- },
- ],
- ]),
- )
- subscriptionSettingRepository.findLastByNameAndUserSubscriptionUuid = jest.fn().mockReturnValue(setting)
- await createService().applyDefaultSubscriptionSettingsForSubscription(userSubscription)
- expect(subscriptionSettingRepository.save).toHaveBeenCalled()
- })
- it('should create default settings for a subscription if it is not replaceable and not existing', async () => {
- subscriptionSettingsAssociationService.getDefaultSettingsAndValuesForSubscriptionName = jest.fn().mockReturnValue(
- new Map([
- [
- SettingName.NAMES.FileUploadBytesUsed,
- {
- value: '0',
- sensitive: 0,
- serverEncryptionVersion: EncryptionVersion.Unencrypted,
- replaceable: false,
- },
- ],
- ]),
- )
- subscriptionSettingRepository.findLastByNameAndUserSubscriptionUuid = jest.fn().mockReturnValue(null)
- await createService().applyDefaultSubscriptionSettingsForSubscription(userSubscription)
- expect(subscriptionSettingRepository.save).toHaveBeenCalledWith(setting)
- })
- it('should create default settings for a subscription if it is not replaceable and no previous subscription existed', async () => {
- subscriptionSettingsAssociationService.getDefaultSettingsAndValuesForSubscriptionName = jest.fn().mockReturnValue(
- new Map([
- [
- SettingName.NAMES.FileUploadBytesUsed,
- {
- value: '0',
- sensitive: 0,
- serverEncryptionVersion: EncryptionVersion.Unencrypted,
- replaceable: false,
- },
- ],
- ]),
- )
- subscriptionSettingRepository.findLastByNameAndUserSubscriptionUuid = jest.fn().mockReturnValue(null)
- userSubscriptionRepository.findByUserUuid = jest.fn().mockReturnValue([
- {
- uuid: '1-2-3',
- } as jest.Mocked<UserSubscription>,
- ])
- await createService().applyDefaultSubscriptionSettingsForSubscription(userSubscription)
- expect(subscriptionSettingRepository.save).toHaveBeenCalledWith(setting)
- })
- it('should not create default settings for a subscription if subscription has no defaults', async () => {
- subscriptionSettingsAssociationService.getDefaultSettingsAndValuesForSubscriptionName = jest
- .fn()
- .mockReturnValue(undefined)
- await createService().applyDefaultSubscriptionSettingsForSubscription(userSubscription)
- expect(subscriptionSettingRepository.save).not.toHaveBeenCalled()
- })
- it("should create setting if it doesn't exist", async () => {
- const result = await createService().createOrReplace({
- userSubscription,
- user,
- props: {
- name: SettingName.NAMES.FileUploadBytesLimit,
- unencryptedValue: 'value',
- serverEncryptionVersion: 1,
- sensitive: false,
- },
- })
- expect(result.status).toEqual('created')
- })
- it('should throw error if the setting name is not valid', async () => {
- await expect(
- createService().createOrReplace({
- userSubscription,
- user,
- props: {
- name: 'invalid',
- unencryptedValue: 'value',
- serverEncryptionVersion: 1,
- sensitive: false,
- },
- }),
- ).rejects.toThrow()
- })
- it('should throw error if the setting name is not a subscription setting', async () => {
- await expect(
- createService().createOrReplace({
- userSubscription,
- user,
- props: {
- name: SettingName.NAMES.DropboxBackupFrequency,
- unencryptedValue: 'value',
- serverEncryptionVersion: 1,
- sensitive: false,
- },
- }),
- ).rejects.toThrow()
- })
- it('should create setting with a given uuid if it does not exist', async () => {
- subscriptionSettingRepository.findOneByUuid = jest.fn().mockReturnValue(null)
- const result = await createService().createOrReplace({
- userSubscription,
- user,
- props: {
- uuid: '1-2-3',
- name: SettingName.NAMES.FileUploadBytesLimit,
- unencryptedValue: 'value',
- serverEncryptionVersion: 1,
- sensitive: false,
- },
- })
- expect(result.status).toEqual('created')
- })
- it('should replace setting if it does exist', async () => {
- subscriptionSettingRepository.findLastByNameAndUserSubscriptionUuid = jest.fn().mockReturnValue(setting)
- const result = await createService().createOrReplace({
- userSubscription,
- user,
- props: {
- ...setting,
- unencryptedValue: 'value',
- serverEncryptionVersion: 1,
- },
- })
- expect(result.status).toEqual('replaced')
- })
- it('should replace setting with a given uuid if it does exist', async () => {
- subscriptionSettingRepository.findOneByUuid = jest.fn().mockReturnValue(setting)
- const result = await createService().createOrReplace({
- userSubscription,
- user,
- props: {
- ...setting,
- uuid: '1-2-3',
- unencryptedValue: 'value',
- serverEncryptionVersion: 1,
- },
- })
- expect(result.status).toEqual('replaced')
- })
- it('should find and decrypt the value of a setting for user', async () => {
- setting = {
- value: 'encrypted',
- serverEncryptionVersion: EncryptionVersion.Default,
- } as jest.Mocked<SubscriptionSetting>
- subscriptionSettingRepository.findLastByNameAndUserSubscriptionUuid = jest.fn().mockReturnValue(setting)
- expect(
- await createService().findSubscriptionSettingWithDecryptedValue({
- userSubscriptionUuid: '2-3-4',
- userUuid: '1-2-3',
- subscriptionSettingName: SettingName.create(SettingName.NAMES.FileUploadBytesLimit).getValue(),
- }),
- ).toEqual({
- serverEncryptionVersion: 1,
- value: 'decrypted',
- })
- })
- it('should throw error when trying to find and decrypt a setting with invalid subscription setting name', async () => {
- await expect(
- createService().findSubscriptionSettingWithDecryptedValue({
- userSubscriptionUuid: '2-3-4',
- userUuid: '1-2-3',
- subscriptionSettingName: SettingName.create(SettingName.NAMES.DropboxBackupFrequency).getValue(),
- }),
- ).rejects.toThrow()
- })
- })
|