Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BC-7124 - Add delete sessions endpoint #5001

Merged
merged 36 commits into from
May 21, 2024
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
9ba0f25
Add delete sessions endpoint
bischofmax May 13, 2024
13126b3
Merge branch 'main' into BC-7124-remove-etherpad-cookie
bischofmax May 13, 2024
7809654
Remove duplicate implementation of deleteSession and filter only vali…
bischofmax May 14, 2024
0e08239
Add api test
bischofmax May 14, 2024
cdcde50
Add filter case for list sessions of author
bischofmax May 14, 2024
6af94cb
Adjust more tests
bischofmax May 14, 2024
630331a
Add and fix service test
bischofmax May 14, 2024
e320673
Merge branch 'main' into BC-7124-remove-etherpad-cookie
bischofmax May 14, 2024
bbca049
Remove response decoratos and fix userid typing
bischofmax May 14, 2024
3e03e59
Merge branch 'main' into BC-7124-remove-etherpad-cookie
bischofmax May 15, 2024
fa8f566
Convert expiresMillisconds to seconds
bischofmax May 15, 2024
723cd5a
Add check if session duration is sufficient
bischofmax May 16, 2024
56f5fdb
Move duration threshold to service
bischofmax May 16, 2024
5b26722
BC-7124 - move interface
SevenWaysDP May 16, 2024
45a4b0a
Adjust adapter tests
bischofmax May 16, 2024
e46b390
BC-7124 - refactor EtherpadClientAdapter to use EtherpadResponseMappe…
SevenWaysDP May 16, 2024
07800c7
Add test for mapEtherpadSessionToSession
bischofmax May 16, 2024
ad08ee9
Merge branch 'main' into BC-7124-remove-etherpad-cookie
bischofmax May 16, 2024
fef4cf7
Fix cookie path
bischofmax May 17, 2024
9abd101
Move mapEtherpadSessionsToSessions to mapper
bischofmax May 17, 2024
c30cf91
Fixx error handling
bischofmax May 17, 2024
047b9b1
Add console logs
bischofmax May 17, 2024
fa16002
Add more logs
bischofmax May 17, 2024
6d27ca0
Fix scenario when no session for user exists
bischofmax May 17, 2024
0f48742
Fix adapter test
bischofmax May 17, 2024
32894fb
Fix service test
bischofmax May 17, 2024
44c172e
Add more untit tests
bischofmax May 17, 2024
fa470ea
Merge branch 'main' into BC-7124-remove-etherpad-cookie
bischofmax May 17, 2024
62c677f
Fix null response in legacy etherpad client
bischofmax May 17, 2024
7bbe2da
Fix naming of unix timestamp
bischofmax May 17, 2024
93f060d
Remove typing from client in CollaborativeTextEditor
bischofmax May 17, 2024
295d7fc
Merge branch 'BC-7124-remove-etherpad-cookie' of github.com:hpi-schul…
bischofmax May 17, 2024
017ab2d
Merge branch 'main' into BC-7124-remove-etherpad-cookie
bischofmax May 17, 2024
c3f2c95
Fix null on correct response data object
bischofmax May 17, 2024
488975f
Merge branch 'main' into BC-7124-remove-etherpad-cookie
CeEv May 17, 2024
2ac8355
Merge branch 'main' into BC-7124-remove-etherpad-cookie
CeEv May 21, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
258 changes: 214 additions & 44 deletions apps/server/src/infra/etherpad-client/etherpad-client.adapter.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,9 @@ describe(EtherpadClientAdapter.name, () => {
await module.close();
});

afterEach(() => {
beforeEach(() => {
jest.resetAllMocks();
jest.useFakeTimers();
});

it('should be defined', () => {
Expand All @@ -85,20 +86,40 @@ describe(EtherpadClientAdapter.name, () => {
return { userId, username };
};

it('should return author id', async () => {
const { userId, username } = setup();
describe('When user name parameter is set', () => {
it('should return author id', async () => {
const { userId, username } = setup();

const result = await service.getOrCreateAuthorId(userId, username);

expect(result).toBe('authorId');
});

it('should call createAuthorIfNotExistsForUsingGET with correct params', async () => {
const { userId, username } = setup();

const result = await service.getOrCreateAuthorId(userId, username);
await service.getOrCreateAuthorId(userId, username);

expect(result).toBe('authorId');
expect(authorApi.createAuthorIfNotExistsForUsingGET).toBeCalledWith(userId, username);
});
});

it('should call createAuthorIfNotExistsForUsingGET with correct params', async () => {
const { userId, username } = setup();
describe('When user name parameter is not set', () => {
it('should return author id', async () => {
const { userId } = setup();

const result = await service.getOrCreateAuthorId(userId);

expect(result).toBe('authorId');
});

it('should call createAuthorIfNotExistsForUsingGET with correct params', async () => {
const { userId } = setup();

await service.getOrCreateAuthorId(userId, username);
await service.getOrCreateAuthorId(userId);

expect(authorApi.createAuthorIfNotExistsForUsingGET).toBeCalledWith(userId, username);
expect(authorApi.createAuthorIfNotExistsForUsingGET).toBeCalledWith(userId, undefined);
});
});
});

Expand Down Expand Up @@ -146,6 +167,127 @@ describe(EtherpadClientAdapter.name, () => {

describe('getOrCreateSessionId', () => {
describe('when session already exists', () => {
describe('when session duration is sufficient', () => {
const setup = () => {
const groupId = 'groupId';
const authorId = 'authorId';
const parentId = 'parentId';
const sessionCookieExpire = new Date();

const listSessionsResponse = createMock<AxiosResponse<InlineResponse2006>>({
data: {
code: EtherpadResponseCode.OK,
data: {
// @ts-expect-error wrong type mapping
'session-id-1': { groupID: groupId, authorID: authorId, validUntil: 20 },
'session-id-2': { groupID: 'other-group-id', authorID: 'other-author-id', validUntil: 20 },
},
},
});

const ETHERPAD_COOKIE_RELEASE_THRESHOLD = 5;
jest.setSystemTime(10 * 1000);

authorApi.listSessionsOfAuthorUsingGET.mockResolvedValue(listSessionsResponse);

return { groupId, authorId, parentId, sessionCookieExpire, ETHERPAD_COOKIE_RELEASE_THRESHOLD };
};

it('should return session id', async () => {
const { groupId, authorId, parentId, sessionCookieExpire, ETHERPAD_COOKIE_RELEASE_THRESHOLD } = setup();

const result = await service.getOrCreateSessionId(
groupId,
authorId,
parentId,
sessionCookieExpire,
ETHERPAD_COOKIE_RELEASE_THRESHOLD
);

expect(result).toBe('session-id-1');
});

it('should not call createSessionUsingGET', async () => {
const { groupId, authorId, parentId, sessionCookieExpire, ETHERPAD_COOKIE_RELEASE_THRESHOLD } = setup();

await service.getOrCreateSessionId(
groupId,
authorId,
parentId,
sessionCookieExpire,
ETHERPAD_COOKIE_RELEASE_THRESHOLD
);

expect(sessionApi.createSessionUsingGET).not.toBeCalled();
});
});

describe('when session duration is not sufficient', () => {
const setup = () => {
const groupId = 'groupId';
const authorId = 'authorId';
const parentId = 'parentId';
const sessionCookieExpire = new Date();
const response = createMock<AxiosResponse<InlineResponse2004>>({
data: {
code: EtherpadResponseCode.OK,
data: { sessionID: 'sessionId' },
},
});

const listSessionsResponse = createMock<AxiosResponse<InlineResponse2006>>({
data: {
code: EtherpadResponseCode.OK,
data: {
// @ts-expect-error wrong type mapping
'session-id-1': { groupID: groupId, authorID: authorId, validUntil: 20 },
'session-id-2': { groupID: 'other-group-id', authorID: 'other-author-id', validUntil: 20 },
},
},
});

const ETHERPAD_COOKIE_RELEASE_THRESHOLD = 15;
jest.setSystemTime(10 * 1000);

authorApi.listSessionsOfAuthorUsingGET.mockResolvedValue(listSessionsResponse);

sessionApi.createSessionUsingGET.mockResolvedValue(response);

return { groupId, authorId, parentId, sessionCookieExpire, ETHERPAD_COOKIE_RELEASE_THRESHOLD };
};

it('should return session id', async () => {
const { groupId, authorId, parentId, sessionCookieExpire, ETHERPAD_COOKIE_RELEASE_THRESHOLD } = setup();

const result = await service.getOrCreateSessionId(
groupId,
authorId,
parentId,
sessionCookieExpire,
ETHERPAD_COOKIE_RELEASE_THRESHOLD
);

expect(result).toBe('sessionId');
});

it('should call createSessionUsingGET with correct params', async () => {
const { groupId, authorId, parentId, sessionCookieExpire, ETHERPAD_COOKIE_RELEASE_THRESHOLD } = setup();

await service.getOrCreateSessionId(
groupId,
authorId,
parentId,
sessionCookieExpire,
ETHERPAD_COOKIE_RELEASE_THRESHOLD
);

const unixTimeInSeconds = Math.floor(sessionCookieExpire.getTime() / 1000).toString();
expect(sessionApi.createSessionUsingGET).toBeCalledWith(groupId, authorId, unixTimeInSeconds);
});
});
});

describe('when two sessions already exist', () => {
const setup = () => {
const groupId = 'groupId';
const authorId = 'authorId';
Expand All @@ -163,32 +305,33 @@ describe(EtherpadClientAdapter.name, () => {
code: EtherpadResponseCode.OK,
data: {
// @ts-expect-error wrong type mapping
'session-id-1': { groupID: groupId, authorID: authorId },
'session-id-2': { groupID: 'other-group-id', authorID: 'other-author-id' },
'session-id-1': { groupID: groupId, authorID: authorId, validUntil: 20 },
'session-id-2': { groupID: groupId, authorID: authorId, validUntil: 30 },
},
},
});

authorApi.listSessionsOfAuthorUsingGET.mockResolvedValue(listSessionsResponse);
const ETHERPAD_COOKIE_RELEASE_THRESHOLD = 15;
jest.setSystemTime(10 * 1000);

authorApi.listSessionsOfAuthorUsingGET.mockResolvedValue(listSessionsResponse);
sessionApi.createSessionUsingGET.mockResolvedValue(response);
return { groupId, authorId, parentId, sessionCookieExpire };
};

it('should return session id', async () => {
const { groupId, authorId, parentId, sessionCookieExpire } = setup();

const result = await service.getOrCreateSessionId(groupId, authorId, parentId, sessionCookieExpire);

expect(result).toBe('session-id-1');
});
return { groupId, authorId, parentId, sessionCookieExpire, ETHERPAD_COOKIE_RELEASE_THRESHOLD };
};

it('should not call createSessionUsingGET', async () => {
const { groupId, authorId, parentId, sessionCookieExpire } = setup();
it('should return the session with longer validUntil', async () => {
const { groupId, authorId, parentId, sessionCookieExpire, ETHERPAD_COOKIE_RELEASE_THRESHOLD } = setup();

await service.getOrCreateSessionId(groupId, authorId, parentId, sessionCookieExpire);
const result = await service.getOrCreateSessionId(
groupId,
authorId,
parentId,
sessionCookieExpire,
ETHERPAD_COOKIE_RELEASE_THRESHOLD
);

expect(sessionApi.createSessionUsingGET).not.toBeCalled();
expect(result).toBe('session-id-2');
});
});

Expand All @@ -212,29 +355,41 @@ describe(EtherpadClientAdapter.name, () => {
},
});

const ETHERPAD_COOKIE_RELEASE_THRESHOLD = 15;

authorApi.listSessionsOfAuthorUsingGET.mockResolvedValue(listSessionsResponse);
sessionApi.createSessionUsingGET.mockResolvedValue(response);
return { groupId, authorId, parentId, sessionCookieExpire };

return { groupId, authorId, parentId, sessionCookieExpire, ETHERPAD_COOKIE_RELEASE_THRESHOLD };
};

it('should return session id', async () => {
const { groupId, authorId, parentId, sessionCookieExpire } = setup();
const { groupId, authorId, parentId, sessionCookieExpire, ETHERPAD_COOKIE_RELEASE_THRESHOLD } = setup();

const result = await service.getOrCreateSessionId(groupId, authorId, parentId, sessionCookieExpire);
const result = await service.getOrCreateSessionId(
groupId,
authorId,
parentId,
sessionCookieExpire,
ETHERPAD_COOKIE_RELEASE_THRESHOLD
);

expect(result).toBe('sessionId');
});

it('should call createSessionUsingGET with correct params', async () => {
const { groupId, authorId, parentId, sessionCookieExpire } = setup();
const { groupId, authorId, parentId, sessionCookieExpire, ETHERPAD_COOKIE_RELEASE_THRESHOLD } = setup();

await service.getOrCreateSessionId(groupId, authorId, parentId, sessionCookieExpire);

expect(sessionApi.createSessionUsingGET).toBeCalledWith(
await service.getOrCreateSessionId(
groupId,
authorId,
sessionCookieExpire.getTime().toString()
parentId,
sessionCookieExpire,
ETHERPAD_COOKIE_RELEASE_THRESHOLD
);

const unixTimeInSeconds = Math.floor(sessionCookieExpire.getTime() / 1000).toString();
expect(sessionApi.createSessionUsingGET).toBeCalledWith(groupId, authorId, unixTimeInSeconds);
});
});

Expand All @@ -259,16 +414,24 @@ describe(EtherpadClientAdapter.name, () => {
data: {},
},
});
const ETHERPAD_COOKIE_RELEASE_THRESHOLD = 15;

sessionApi.createSessionUsingGET.mockResolvedValue(response);
return { groupId, authorId, parentId, sessionCookieExpire };

return { groupId, authorId, parentId, sessionCookieExpire, ETHERPAD_COOKIE_RELEASE_THRESHOLD };
};

it('should throw an error', async () => {
const { groupId, authorId, parentId, sessionCookieExpire } = setup();
const { groupId, authorId, parentId, sessionCookieExpire, ETHERPAD_COOKIE_RELEASE_THRESHOLD } = setup();

await expect(
service.getOrCreateSessionId(groupId, authorId, parentId, sessionCookieExpire)
service.getOrCreateSessionId(
groupId,
authorId,
parentId,
sessionCookieExpire,
ETHERPAD_COOKIE_RELEASE_THRESHOLD
)
).rejects.toThrowError('Session could not be created');
});
});
Expand All @@ -285,18 +448,25 @@ describe(EtherpadClientAdapter.name, () => {
data: {},
},
});
const ETHERPAD_COOKIE_RELEASE_THRESHOLD = 15;

authorApi.listSessionsOfAuthorUsingGET.mockResolvedValue(listSessionsResponse);

sessionApi.createSessionUsingGET.mockRejectedValueOnce(new Error('error'));
return { groupId, authorId, parentId, sessionCookieExpire };
return { groupId, authorId, parentId, sessionCookieExpire, ETHERPAD_COOKIE_RELEASE_THRESHOLD };
};

it('should throw EtherpadErrorLoggableException', async () => {
const { groupId, authorId, parentId, sessionCookieExpire } = setup();
const { groupId, authorId, parentId, sessionCookieExpire, ETHERPAD_COOKIE_RELEASE_THRESHOLD } = setup();

await expect(
service.getOrCreateSessionId(groupId, authorId, parentId, sessionCookieExpire)
service.getOrCreateSessionId(
groupId,
authorId,
parentId,
sessionCookieExpire,
ETHERPAD_COOKIE_RELEASE_THRESHOLD
)
).rejects.toThrowError(EtherpadErrorLoggableException);
});
});
Expand All @@ -310,7 +480,7 @@ describe(EtherpadClientAdapter.name, () => {
data: {
code: EtherpadResponseCode.OK,
// @ts-expect-error wrong type mapping
data: { 'session-id-1': { groupID: 'groupId', authorID: authorId } },
data: { 'session-id-1': { groupID: 'groupId', authorID: authorId, validUntil: 10 }, 'session-id-2': null },
},
});

Expand Down Expand Up @@ -381,12 +551,12 @@ describe(EtherpadClientAdapter.name, () => {
return authorId;
};

it('should throw an error', async () => {
it('should return empty array', async () => {
const authorId = setup();

await expect(service.listSessionIdsOfAuthor(authorId)).rejects.toThrowError(
'Etherpad session ids response is not an object'
);
const result = await service.listSessionIdsOfAuthor(authorId);

expect(result).toEqual([]);
});
});
});
Expand Down
Loading
Loading