Skip to content

Commit

Permalink
[service] test: improve coverage
Browse files Browse the repository at this point in the history
Co-authored-by: Maciej Samoraj <[email protected]>
  • Loading branch information
elf-pavlik and samurex committed Jan 3, 2024
1 parent 7f2ccec commit a0b554c
Show file tree
Hide file tree
Showing 10 changed files with 630 additions and 93 deletions.
8 changes: 5 additions & 3 deletions packages/service/src/handlers/api-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@ import {
getUnregisteredApplicationProfile,
getResource,
shareResource,
listDataInstances
listDataInstances,
requestAccessUsingApplicationNeeds,
acceptInvitation,
createInvitation,
getSocialAgentInvitations
} from '../services';
import type { SaiContext } from '../models/http-solid-context';
import { validateContentType } from '../utils/http-validators';
import { IReciprocalRegistrationsJobData } from '../models/jobs';
import { requestAccessUsingApplicationNeeds } from '../services/access-request';
import { acceptInvitation, createInvitation, getSocialAgentInvitations } from '../services/invitations';

export class ApiHandler extends HttpHandler {
private logger = getLogger();
Expand Down
17 changes: 8 additions & 9 deletions packages/service/src/handlers/invitations-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,21 +32,20 @@ export class InvitationsHandler extends HttpHandler {
socialAgentInvitation.label,
socialAgentInvitation.note
);
// create job to discover, add and subscribe to reciprocal registration
await this.queue.add(
{
webId: userId,
registeredAgent: socialAgentRegistration.registeredAgent
} as IReciprocalRegistrationsJobData,
{ delay: 10000 }
);
}

// update invitation with agent who accepted it
socialAgentInvitation.registeredAgent = socialAgentRegistration.registeredAgent;
await socialAgentInvitation.update();

// create job to discover, add and subscribe to reciprocal registration
await this.queue.add(
{
webId: userId,
registeredAgent: socialAgentRegistration.registeredAgent
} as IReciprocalRegistrationsJobData,
{ delay: 10000 }
);

return {
body: userId,
status: 200,
Expand Down
2 changes: 2 additions & 0 deletions packages/service/src/services/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ export * from './descriptions';
export * from './social-agents';
export * from './web-push';
export * from './data-instance';
export * from './access-request';
export * from './invitations';
1 change: 1 addition & 0 deletions packages/service/src/services/invitations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export async function acceptInvitation(saiSession: AuthorizationAgent, invitatio
});
if (!response.ok) throw new Error('fetching capability url failed');
const webId = (await response.text()).trim();
// TODO: validate with regex
if (!webId) throw new Error('can not accept invitation without webid');
// check if agent already has registration
let socialAgentRegistration = await saiSession.findSocialAgentRegistration(webId);
Expand Down
62 changes: 32 additions & 30 deletions packages/service/test/unit/handlers/agents-handler-test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
// eslint-disable-next-line import/no-extraneous-dependencies
import { jest } from '@jest/globals';

import { InMemoryStorage } from '@inrupt/solid-client-authn-node';
import { HttpHandlerRequest } from '@digita-ai/handlersjs-http';
import { AuthorizationAgent } from '@janeirodigital/interop-authorization-agent';
import { INTEROP } from '@janeirodigital/interop-utils';

import {
AgentsHandler,
SessionManager,
Expand All @@ -7,26 +15,18 @@ import {
webId2agentUrl,
encodeWebId
} from '../../../src';
import { jest } from '@jest/globals';

jest.mock('../../../src/session-manager', () => {
const originalModule = jest.requireActual('../../../src/session-manager') as object;

return {
...originalModule,
SessionManager: jest.fn(() => {
return {
getSaiSession: jest.fn()
};
})
SessionManager: jest.fn(() => ({
getSaiSession: jest.fn()
}))
};
});

import { AuthorizationAgent } from '@janeirodigital/interop-authorization-agent';
import { INTEROP } from '@janeirodigital/interop-utils';
import { InMemoryStorage } from '@inrupt/solid-client-authn-node';
import { HttpHandlerRequest } from '@digita-ai/handlersjs-http';

const aliceWebId = 'https://alice.example';
const aliceAgentUrl = webId2agentUrl(aliceWebId);

Expand Down Expand Up @@ -70,15 +70,16 @@ describe('authenticated request', () => {
test('application registration discovery', (done) => {
const applicationRegistrationIri = 'https://some.example/application-registration';

manager.getSaiSession.mockImplementation(async (webId) => {
return {
webId,
findApplicationRegistration: async (applicationId) => {
expect(applicationId).toBe(clientId);
return { iri: applicationRegistrationIri };
}
} as AuthorizationAgent;
});
manager.getSaiSession.mockImplementation(
async (webId) =>
({
webId,
findApplicationRegistration: async (applicationId) => {
expect(applicationId).toBe(clientId);
return { iri: applicationRegistrationIri };
}
}) as AuthorizationAgent
);

const request = {
url: aliceAgentUrl
Expand All @@ -99,15 +100,16 @@ describe('authenticated request', () => {
const bobWebId = 'https://bob.example/';
const socialAgentRegistrationIri = 'https://some.example/application-registration';

manager.getSaiSession.mockImplementation(async (webId) => {
return {
webId,
findSocialAgentRegistration: async (webid) => {
expect(webid).toBe(bobWebId);
return { iri: socialAgentRegistrationIri };
}
} as AuthorizationAgent;
});
manager.getSaiSession.mockImplementation(
async (webId) =>
({
webId,
findSocialAgentRegistration: async (webid) => {
expect(webid).toBe(bobWebId);
return { iri: socialAgentRegistrationIri };
}
}) as AuthorizationAgent
);

const request = {
url: aliceAgentUrl
Expand All @@ -119,7 +121,7 @@ describe('authenticated request', () => {
clientId
};

const ctx = { request, authn: authn } as AuthenticatedAuthnContext;
const ctx = { request, authn } as AuthenticatedAuthnContext;

agentsHandler.handle(ctx).subscribe((response) => {
expect(manager.getSaiSession).toBeCalledWith(aliceWebId);
Expand Down
110 changes: 108 additions & 2 deletions packages/service/test/unit/handlers/api-handler-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ import {
Resource,
ResponseMessageTypes,
ShareAuthorizationConfirmation,
SocialAgent
SocialAgent,
SocialAgentInvitation
} from '@janeirodigital/sai-api-messages';

import { ApiHandler, SaiContext } from '../../../src';
Expand All @@ -31,8 +32,12 @@ jest.mock('../../../src/services', () => ({
getDescriptions: jest.fn(),
listDataInstances: jest.fn(),
recordAuthorization: jest.fn(),
requestAccessUsingApplicationNeeds: jest.fn(),
getResource: jest.fn(),
shareResource: jest.fn()
shareResource: jest.fn(),
getSocialAgentInvitations: jest.fn(),
createInvitation: jest.fn(),
acceptInvitation: jest.fn()
}));

const mocked = jest.mocked(services);
Expand Down Expand Up @@ -319,6 +324,35 @@ describe('recordAuthorization', () => {
});
});

describe('requestAccessUsingApplicationNeeds', () => {
test('sucessful response', (done) => {
const request = {
headers,
body: {
type: RequestMessageTypes.REQUEST_AUTHORIZATION_USING_APPLICATION_NEEDS,
applicationId: 'https://projectron.example',
agentId: 'https://alice.example'
}
} as unknown as HttpHandlerRequest;
const ctx = { request, authn, saiSession, logger } as SaiContext;

apiHandler.handle(ctx).subscribe({
next: (response: HttpHandlerResponse) => {
expect(response.status).toBe(200);
expect(response.body.type).toBe(ResponseMessageTypes.REQUEST_ACCESS_USING_APPLICATION_NEEDS_CONFIRMTION);
expect(response.body.payload).toBe(null);

expect(mocked.requestAccessUsingApplicationNeeds).toBeCalledWith(
request.body.applicationId,
request.body.agentId,
saiSession
);
done();
}
});
});
});

describe('getResource', () => {
test('sucessful response', (done) => {
const request = {
Expand Down Expand Up @@ -373,3 +407,75 @@ describe('shareResource', () => {
});
});
});

describe('getSocialAgentInvitations', () => {
test('sucessful response', (done) => {
const request = {
headers,
body: {
type: RequestMessageTypes.SOCIAL_AGENT_INVITATIONS_REQUEST
}
} as unknown as HttpHandlerRequest;
const ctx = { request, authn, saiSession, logger } as SaiContext;
const socialAgentInvitations = [] as unknown as SocialAgentInvitation[];
mocked.getSocialAgentInvitations.mockResolvedValueOnce(socialAgentInvitations);

apiHandler.handle(ctx).subscribe({
next: (response: HttpHandlerResponse) => {
expect(response.status).toBe(200);
expect(response.body.type).toBe(ResponseMessageTypes.SOCIAL_AGENT_INVITATIONS_RESPONSE);
expect(response.body.payload).toBe(socialAgentInvitations);
expect(mocked.getSocialAgentInvitations).toBeCalledTimes(1);
done();
}
});
});
});

describe('createInvitation', () => {
test('sucessful response', (done) => {
const request = {
headers,
body: {
type: RequestMessageTypes.CREATE_INVITATION
}
} as unknown as HttpHandlerRequest;
const ctx = { request, authn, saiSession, logger } as SaiContext;
const socialAgentInvitation = {} as SocialAgentInvitation;
mocked.createInvitation.mockResolvedValueOnce(socialAgentInvitation);

apiHandler.handle(ctx).subscribe({
next: (response: HttpHandlerResponse) => {
expect(response.status).toBe(200);
expect(response.body.type).toBe(ResponseMessageTypes.INVITATION_REGISTRATION);
expect(response.body.payload).toBe(socialAgentInvitation);
expect(mocked.createInvitation).toBeCalledWith(saiSession, request.body);
done();
}
});
});
});

describe('acceptInvitation', () => {
test('sucessful response', (done) => {
const request = {
headers,
body: {
type: RequestMessageTypes.ACCEPT_INVITATION
}
} as unknown as HttpHandlerRequest;
const ctx = { request, authn, saiSession, logger } as SaiContext;
const socialAgent = {} as SocialAgent;
mocked.acceptInvitation.mockResolvedValueOnce(socialAgent);

apiHandler.handle(ctx).subscribe({
next: (response: HttpHandlerResponse) => {
expect(response.status).toBe(200);
expect(response.body.type).toBe(ResponseMessageTypes.SOCIAL_AGENT_RESPONSE);
expect(response.body.payload).toBe(socialAgent);
expect(mocked.acceptInvitation).toBeCalledWith(saiSession, request.body);
done();
}
});
});
});
Loading

0 comments on commit a0b554c

Please sign in to comment.