Skip to content

Commit

Permalink
Merge pull request #58 from aserto-dev/consolideate_config
Browse files Browse the repository at this point in the history
validate and consolidate config
  • Loading branch information
gimmyxd authored Dec 7, 2023
2 parents f72a6e1 + 4a64d69 commit 4f92b88
Show file tree
Hide file tree
Showing 4 changed files with 417 additions and 82 deletions.
279 changes: 276 additions & 3 deletions __tests__/directory/v3/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ import { createAsyncIterable } from "@connectrpc/connect/protocol";
import * as connectNode from "@connectrpc/connect-node";

import {
nullExporterProxy,
nullImporterProxy,
nullModelProxy,
nullReaderProxy,
nullWriterProxy,
} from "../../../lib/directory/v3/null";
import {
ConfigError,
DirectoryServiceV3,
DirectoryV3,
EtagMismatchError,
Expand Down Expand Up @@ -193,6 +201,247 @@ describe("DirectoryV3", () => {
expect(directory.ModelClient).toBeDefined();
});

describe("Reader", () => {
it("inherits base config", () => {
const mockTransport = jest.spyOn(connectNode, "createGrpcTransport");
const mockFs = jest
.spyOn(fs, "readFileSync")
.mockImplementation((path: fs.PathOrFileDescriptor) => {
return path as string;
});

const directory = DirectoryServiceV3({
tenantId: "tenantId",
apiKey: "apiKey",
});

expect(directory).toBeInstanceOf(DirectoryV3);
expect(directory.ReaderClient).toBeDefined();

mockFs.mockReset();
mockTransport.mockReset();
});

it("allows to be configured individually", () => {
const mockTransport = jest.spyOn(connectNode, "createGrpcTransport");
const mockFs = jest
.spyOn(fs, "readFileSync")
.mockImplementation((path: fs.PathOrFileDescriptor) => {
return path as string;
});

const directory = DirectoryServiceV3({
reader: {
tenantId: "tenantId",
apiKey: "apiKey",
},
});

expect(directory).toBeInstanceOf(DirectoryV3);
expect(directory.ReaderClient).toBeDefined();
expect(mockTransport.mock.calls).toEqual([
[
expect.objectContaining({
baseUrl: "https://directory.prod.aserto.com:8443",
httpVersion: "2",
nodeOptions: { rejectUnauthorized: true },
}),
],
]);
mockFs.mockReset();
mockTransport.mockReset();
});

it("overwrites base config", () => {
const mockTransport = jest.spyOn(connectNode, "createGrpcTransport");
const mockFs = jest
.spyOn(fs, "readFileSync")
.mockImplementation((path: fs.PathOrFileDescriptor) => {
return path as string;
});

const directory = DirectoryServiceV3({
reader: {
url: "readerurl",
tenantId: "tenantId",
apiKey: "apiKey",
},
});

expect(directory).toBeInstanceOf(DirectoryV3);
expect(directory.ReaderClient).toBeDefined();
expect(mockTransport.mock.calls).toEqual([
[
expect.objectContaining({
baseUrl: "https://readerurl",
httpVersion: "2",
nodeOptions: { rejectUnauthorized: true },
}),
],
]);
mockFs.mockReset();
});

describe("when config is missing", () => {
const directory = DirectoryServiceV3({
writer: {
tenantId: "tenantId",
apiKey: "apiKey",
},
});

it("is defined as a proxy", () => {
expect(directory.ReaderClient).toBe(nullReaderProxy);
});

it("throws ClientNotConfigured Error when called", async () => {
await expect(directory.objects({ objectType: "" })).rejects.toThrow(
ConfigError
);

await expect(directory.objects({ objectType: "" })).rejects.toThrow(
`Cannot call 'getObjects', 'Reader' is not configured.`
);
});
});
});

describe("Writer", () => {
it("inherits base config", () => {
const directory = DirectoryServiceV3({
tenantId: "tenantId",
apiKey: "apiKey",
});

expect(directory).toBeInstanceOf(DirectoryV3);
expect(directory.WriterClient).toBeDefined();
});

describe("when config is missing", () => {
const directory = DirectoryServiceV3({
reader: {
tenantId: "tenantId",
apiKey: "apiKey",
},
});

it("is defined as a proxy", () => {
expect(directory.WriterClient).toBe(nullWriterProxy);
});

it("throws ClientNotConfigured Error when called", async () => {
await expect(directory.setObject({})).rejects.toThrow(ConfigError);

await expect(directory.setObject({})).rejects.toThrow(
`Cannot call 'setObject', 'Writer' is not configured.`
);
});
});
});

describe("Importer", () => {
it("inherits base config", () => {
const directory = DirectoryServiceV3({
tenantId: "tenantId",
apiKey: "apiKey",
});

expect(directory).toBeInstanceOf(DirectoryV3);
expect(directory.ImporterClient).toBeDefined();
});

describe("when config is missing", () => {
const directory = DirectoryServiceV3({
reader: {
tenantId: "tenantId",
apiKey: "apiKey",
},
});

it("is defined as a proxy", () => {
expect(directory.ImporterClient).toBe(nullImporterProxy);
});

it("throws ClientNotConfigured Error when called", async () => {
await expect(directory.import(createAsyncIterable([]))).rejects.toThrow(
ConfigError
);

await expect(directory.import(createAsyncIterable([]))).rejects.toThrow(
`Cannot call 'import', 'Importer' is not configured.`
);
});
});
});

describe("Exporter", () => {
it("inherits base config", () => {
const directory = DirectoryServiceV3({
tenantId: "tenantId",
apiKey: "apiKey",
});

expect(directory).toBeInstanceOf(DirectoryV3);
expect(directory.ExporterClient).toBeDefined();
});

describe("when config is missing", () => {
const directory = DirectoryServiceV3({
reader: {
tenantId: "tenantId",
apiKey: "apiKey",
},
});

it("is defined as a proxy", () => {
expect(directory.ExporterClient).toBe(nullExporterProxy);
});

it("throws ClientNotConfigured Error when called", async () => {
await expect(directory.export({ options: "all" })).rejects.toThrow(
ConfigError
);

await expect(directory.export({ options: "all" })).rejects.toThrow(
`Cannot call 'export', 'Exporter' is not configured.`
);
});
});
});

describe("Model", () => {
it("inherits base config", () => {
const directory = DirectoryServiceV3({
tenantId: "tenantId",
apiKey: "apiKey",
});

expect(directory).toBeInstanceOf(DirectoryV3);
expect(directory.ModelClient).toBeDefined();
});

describe("when config is missing", () => {
const directory = DirectoryServiceV3({
reader: {
tenantId: "tenantId",
apiKey: "apiKey",
},
});

it("is defined as a proxy", () => {
expect(directory.ModelClient).toBe(nullModelProxy);
});

it("throws ClientNotConfigured Error when called", async () => {
await expect(directory.deleteManifest()).rejects.toThrow(ConfigError);

await expect(directory.deleteManifest()).rejects.toThrow(
`Cannot call 'deleteManifest', 'Model' is not configured.`
);
});
});
});

describe("checkPermission", () => {
it("calls checkPermission with valid params", async () => {
const mockCheckPermission = jest
Expand Down Expand Up @@ -505,7 +754,15 @@ describe("DirectoryV3", () => {
.spyOn(directory.WriterClient, "setObject")
.mockRejectedValue(new Error("Directory service error"));

const params = { objectType: "user" };
const params = {
object: {
type: "user",
id: "test-user",
properties: {
displayName: "test user",
},
},
};
await expect(directory.setObject(params)).rejects.toThrow(
"Directory service error"
);
Expand All @@ -520,7 +777,15 @@ describe("DirectoryV3", () => {
new ConnectError("Invalid argument", Code.InvalidArgument)
);

const params = {};
const params = {
object: {
type: "user",
id: "test-user",
properties: {
displayName: "test user",
},
},
};

// error class
await expect(directory.setObject(params)).rejects.toThrow(
Expand All @@ -541,7 +806,15 @@ describe("DirectoryV3", () => {
new ConnectError("Invalid argument", Code.FailedPrecondition)
);

const params = {};
const params = {
object: {
type: "user",
id: "test-user",
properties: {
displayName: "test user",
},
},
};

// error class
await expect(directory.setObject(params)).rejects.toThrow(
Expand Down
1 change: 1 addition & 0 deletions lib/directory/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* @extends Error
*/
class DirectoryServiceError extends Error {}
export class ConfigError extends DirectoryServiceError {}
/**
* Object or Relation is not found.
* Extends the DirectoryServiceError class.
Expand Down
Loading

0 comments on commit 4f92b88

Please sign in to comment.