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

Bug 466. Rules without a subscription cannot be listed. Listing rules for an invalid DID causes infinite loading #469

Merged
merged 9 commits into from
Nov 26, 2024
10 changes: 0 additions & 10 deletions src/lib/core/use-case/list-did-rules/list-did-rules-usecase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,6 @@ class ListDIDRulesUseCase
}

validateFinalResponseModel(responseModel: ListDIDRulesResponse): { isValid: boolean; errorModel?: ListDIDRulesError | undefined } {
if (!responseModel.subscription_name || !responseModel.subscription_account) {
return {
isValid: false,
errorModel: {
status: 'error',
message: 'Subscription details not found',
} as ListDIDRulesError,
};
}

return {
isValid: true,
};
Expand Down
10 changes: 9 additions & 1 deletion src/lib/core/use-case/list-dids/pipeline-element-get-did.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,15 @@ export default class GetDIDsPipelineElement extends BaseStreamingPostProcessingP
};
}

transformResponseModel(responseModel: ListDIDsResponse, dto: DIDExtendedDTO): ListDIDsResponse {
transformResponseModel(responseModel: ListDIDsResponse, dto: DIDExtendedDTO): ListDIDsResponse | ListDIDsError {
if (dto.status === 'error')
return {
status: 'error',
name: '',
message: '',
error: '',
code: 500,
};
responseModel.bytes = dto.bytes;
responseModel.length = dto.length;
responseModel.did_type = dto.did_type;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,15 @@ export default class GetRSEPipelineElement extends BaseStreamingPostProcessingPi
return errorModel;
}

transformResponseModel(responseModel: ListRSEsResponse, dto: RSEDetailsDTO): ListRSEsResponse {
transformResponseModel(responseModel: ListRSEsResponse, dto: RSEDetailsDTO): ListRSEsResponse | ListRSEsError {
if (dto.status === 'error') {
return {
status: 'error',
message: '',
name: '',
code: 500,
};
}
responseModel.id = dto.id;
responseModel.deterministic = dto.deterministic;
responseModel.rse_type = dto.rse_type;
Expand Down
28 changes: 18 additions & 10 deletions src/lib/infrastructure/gateway/did-gateway/did-gateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,11 +204,15 @@ export default class RucioDIDGateway implements DIDGatewayOutputPort {
async listDIDRules(rucioAuthToken: string, scope: string, name: string): Promise<ListDIDRulesDTO> {
try {
const endpoint = new ListDIDRulesEndpoint(rucioAuthToken, scope, name);
await endpoint.fetch();
return {
status: 'success',
stream: endpoint,
};
const errorDTO: ListDIDDTO | undefined = await endpoint.fetch();
if (!errorDTO) {
const dto: ListDIDDTO = {
status: 'success',
stream: endpoint,
};
return dto;
}
return Promise.resolve(errorDTO);
} catch (error) {
const errorDTO: ListDIDRulesDTO = {
status: 'error',
Expand All @@ -224,11 +228,15 @@ export default class RucioDIDGateway implements DIDGatewayOutputPort {
async listDIDContents(rucioAuthToken: string, scope: string, name: string): Promise<ListDIDDTO> {
try {
const endpoint = new ListDIDContentsEndpoint(rucioAuthToken, scope, name);
await endpoint.fetch();
return {
status: 'success',
stream: endpoint,
};
const errorDTO: ListDIDDTO | undefined = await endpoint.fetch();
if (!errorDTO) {
const dto: ListDIDDTO = {
status: 'success',
stream: endpoint,
};
return dto;
}
return Promise.resolve(errorDTO);
} catch (error) {
const errorDTO: ListDIDRulesDTO = {
status: 'error',
Expand Down
13 changes: 9 additions & 4 deletions src/lib/infrastructure/presenter/list-did-rules-presenter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,17 +37,22 @@ export default class ListDIDRulesPresenter
}

streamResponseModelToViewModel(responseModel: ListDIDRulesResponse): DIDRulesViewModel {
let subscription = undefined;
if (responseModel.subscription_name && responseModel.subscription_account) {
subscription = {
name: responseModel.subscription_name,
account: responseModel.subscription_account,
};
}

const viewModel: DIDRulesViewModel = {
status: 'success',
id: responseModel.id,
name: responseModel.name,
state: responseModel.state,
account: responseModel.account,
last_modified: responseModel.last_modified,
subscription: {
name: responseModel.subscription_name ?? '',
account: responseModel.subscription_account ?? '',
},
subscription: subscription,
};
return viewModel;
}
Expand Down
12 changes: 5 additions & 7 deletions src/lib/sdk/postprocessing-pipeline-elements.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,14 +117,12 @@ export abstract class BaseStreamingPostProcessingPipelineElement<
* @returns The ResponseModel or ErrorModel returned, based on processing of the DTO.
*/
processGatewayResponse(responseModel: TResponseModel, dto: TDTO): TResponseModel | TErrorModel {
if (dto.status === 'success') {
const data = this.transformResponseModel(responseModel, dto);
const status = data.status;
if (status === 'success') {
return data as TResponseModel;
}
return data as TErrorModel;
const data = this.transformResponseModel(responseModel, dto);
const status = data.status;
if (status === 'success') {
return data as TResponseModel;
}

const commonError: BaseErrorResponseModel | undefined = handleCommonGatewayErrors<TDTO>(dto);
if (commonError) {
return commonError as TErrorModel;
Expand Down
43 changes: 37 additions & 6 deletions test/api/did/list-did-contents.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ import { ListDIDContentsControllerParameters } from '@/lib/infrastructure/contro
import { ListDIDContentsRequest } from '@/lib/core/usecase-models/list-did-contents-usecase-models';

describe('List DID Contents Feature tests', () => {
beforeEach(() => {
afterEach(() => {
fetchMock.dontMock();
});
it('should list DID contents', async () => {
fetchMock.doMock();
const didListContentsMockEndpoint: MockEndpoint = {
url: `${MockRucioServerFactory.RUCIO_HOST}/dids/test/dataset1/dids`,
Expand Down Expand Up @@ -45,12 +48,7 @@ describe('List DID Contents Feature tests', () => {
};

MockRucioServerFactory.createMockRucioServer(true, [didListContentsMockEndpoint]);
});

afterEach(() => {
fetchMock.dontMock();
});
it('should list DID contents', async () => {
const res = MockHttpStreamableResponseFactory.getMockResponse();

const listDIDContentsController = appContainer.get<BaseController<ListDIDContentsControllerParameters, ListDIDContentsRequest>>(
Expand Down Expand Up @@ -98,4 +96,37 @@ describe('List DID Contents Feature tests', () => {
did_type: DIDType.FILE,
});
});

it('should return a 404 response for an unknown DID', async () => {
fetchMock.doMock();
const didListContentsMockEndpoint: MockEndpoint = {
url: `${MockRucioServerFactory.RUCIO_HOST}/dids/test/dataset1/dids`,
method: 'GET',
includes: '/dataset1/dids',
response: {
status: 404,
headers: {
'Content-Type': 'application/x-json-stream',
},
body: '',
},
};

MockRucioServerFactory.createMockRucioServer(true, [didListContentsMockEndpoint]);

const res = MockHttpStreamableResponseFactory.getMockResponse();

const listDIDContentsController = appContainer.get<BaseController<ListDIDContentsControllerParameters, ListDIDContentsRequest>>(
CONTROLLERS.LIST_DID_CONTENTS,
);
const listDIDContentsControllerParams: ListDIDContentsControllerParameters = {
response: res as unknown as NextApiResponse,
rucioAuthToken: MockRucioServerFactory.VALID_RUCIO_TOKEN,
name: 'dataset1',
scope: 'test',
};

await listDIDContentsController.execute(listDIDContentsControllerParams);
expect(res.statusCode).toEqual(404);
});
});
Loading
Loading