Skip to content

Commit

Permalink
feat(api): updateUserPool and describeUserPool support
Browse files Browse the repository at this point in the history
  • Loading branch information
jagregory committed Feb 16, 2022
1 parent 4fa9de5 commit fc62e8f
Show file tree
Hide file tree
Showing 9 changed files with 208 additions and 2 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ A _Good Enough_ offline emulator for [Amazon Cognito](https://aws.amazon.com/cog
| DescribeResourceServer ||
| DescribeRiskConfiguration ||
| DescribeUserImportJob ||
| DescribeUserPool | |
| DescribeUserPool | |
| DescribeUserPoolClient ||
| DescribeUserPoolDomain ||
| ForgetDevice ||
Expand Down Expand Up @@ -125,7 +125,7 @@ A _Good Enough_ offline emulator for [Amazon Cognito](https://aws.amazon.com/cog
| UpdateIdentityProvider ||
| UpdateResourceServer ||
| UpdateUserAttributes ||
| UpdateUserPool | |
| UpdateUserPool | |
| UpdateUserPoolClient | ✅² |
| UpdateUserPoolDomain ||
| VerifySoftwareToken ||
Expand Down
47 changes: 47 additions & 0 deletions integration-tests/aws-sdk/updateUserPool.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { withCognitoSdk } from "./setup";

describe(
"CognitoIdentityServiceProvider.updateUserPool",
withCognitoSdk((Cognito) => {
it("updates a user pool", async () => {
const client = Cognito();

// create the user pool client
const up = await client
.createUserPool({
PoolName: "pool",
MfaConfiguration: "OFF",
})
.promise();

const describeResponse = await client
.describeUserPool({
UserPoolId: up.UserPool?.Id!,
})
.promise();

expect(describeResponse.UserPool).toMatchObject({
Name: "pool",
MfaConfiguration: "OFF",
});

await client
.updateUserPool({
UserPoolId: up.UserPool?.Id!,
MfaConfiguration: "OPTIONAL",
})
.promise();

const describeResponseAfterUpdate = await client
.describeUserPool({
UserPoolId: up.UserPool?.Id!,
})
.promise();

expect(describeResponseAfterUpdate.UserPool).toMatchObject({
Name: "pool",
MfaConfiguration: "OPTIONAL",
});
});
})
);
1 change: 1 addition & 0 deletions src/__tests__/mockUserPoolService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export const newMockUserPoolService = (
saveGroup: jest.fn(),
saveUser: jest.fn(),
storeRefreshToken: jest.fn(),
update: jest.fn(),
});

export const newMockUserPoolServiceFactory = (
Expand Down
6 changes: 6 additions & 0 deletions src/services/userPoolService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ export interface UserPoolService {
): Promise<User | null>;
listGroups(ctx: Context): Promise<readonly Group[]>;
listUsers(ctx: Context): Promise<readonly User[]>;
update(ctx: Context, userPool: UserPool): Promise<void>;
removeUserFromGroup(ctx: Context, group: Group, user: User): Promise<void>;
saveGroup(ctx: Context, group: Group): Promise<void>;
saveUser(ctx: Context, user: User): Promise<void>;
Expand Down Expand Up @@ -314,6 +315,11 @@ export class UserPoolServiceImpl implements UserPoolService {
return Object.values(users);
}

public async update(ctx: Context, userPool: UserPool): Promise<void> {
ctx.logger.debug({ userPoolId: userPool.Id }, "UserPoolServiceImpl.update");
await this.dataStore.set(ctx, "Options", userPool);
}

public async saveUser(ctx: Context, user: User): Promise<void> {
ctx.logger.debug({ user }, "UserPoolServiceImpl.saveUser");

Expand Down
35 changes: 35 additions & 0 deletions src/targets/describeUserPool.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { newMockCognitoService } from "../__tests__/mockCognitoService";
import { newMockUserPoolService } from "../__tests__/mockUserPoolService";
import { TestContext } from "../__tests__/testContext";
import { CognitoService } from "../services";
import { DescribeUserPool, DescribeUserPoolTarget } from "./describeUserPool";
import * as TDB from "../__tests__/testDataBuilder";

describe("DescribeUserPool target", () => {
let describeUserPool: DescribeUserPoolTarget;
let mockCognitoService: jest.Mocked<CognitoService>;

beforeEach(() => {
mockCognitoService = newMockCognitoService(newMockUserPoolService());
describeUserPool = DescribeUserPool({
cognito: mockCognitoService,
});
});

it("returns an existing user pool", async () => {
const existingUserPool = TDB.userPool();
mockCognitoService.getUserPool.mockResolvedValue(
newMockUserPoolService(existingUserPool)
);

const result = await describeUserPool(TestContext, {
UserPoolId: existingUserPool.Id,
});

expect(result).toEqual({
UserPool: existingUserPool,
});
});

it.todo("throws resource not found for an invalid user pool");
});
26 changes: 26 additions & 0 deletions src/targets/describeUserPool.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import {
DescribeUserPoolRequest,
DescribeUserPoolResponse,
} from "aws-sdk/clients/cognitoidentityserviceprovider";
import { ResourceNotFoundError } from "../errors";
import { Services } from "../services";
import { userPoolToResponseObject } from "./responses";
import { Target } from "./Target";

export type DescribeUserPoolTarget = Target<
DescribeUserPoolRequest,
DescribeUserPoolResponse
>;

export const DescribeUserPool =
({ cognito }: Pick<Services, "cognito">): DescribeUserPoolTarget =>
async (ctx, req) => {
const userPool = await cognito.getUserPool(ctx, req.UserPoolId);
if (!userPool) {
throw new ResourceNotFoundError();
}

return {
UserPool: userPoolToResponseObject(userPool.config),
};
};
4 changes: 4 additions & 0 deletions src/targets/targets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { DeleteUser } from "./deleteUser";
import { DeleteUserAttributes } from "./deleteUserAttributes";
import { DeleteUserPool } from "./deleteUserPool";
import { DeleteUserPoolClient } from "./deleteUserPoolClient";
import { DescribeUserPool } from "./describeUserPool";
import { DescribeUserPoolClient } from "./describeUserPoolClient";
import { ForgotPassword } from "./forgotPassword";
import { GetGroup } from "./getGroup";
Expand All @@ -37,6 +38,7 @@ import { RevokeToken } from "./revokeToken";
import { SignUp } from "./signUp";
import { UpdateGroup } from "./updateGroup";
import { UpdateUserAttributes } from "./updateUserAttributes";
import { UpdateUserPool } from "./updateUserPool";
import { UpdateUserPoolClient } from "./updateUserPoolClient";
import { VerifyUserAttribute } from "./verifyUserAttribute";

Expand All @@ -63,6 +65,7 @@ export const Targets = {
DeleteUserAttributes,
DeleteUserPool,
DeleteUserPoolClient,
DescribeUserPool,
DescribeUserPoolClient,
ForgotPassword,
GetGroup,
Expand All @@ -79,6 +82,7 @@ export const Targets = {
SignUp,
UpdateGroup,
UpdateUserAttributes,
UpdateUserPool,
UpdateUserPoolClient,
VerifyUserAttribute,
} as const;
43 changes: 43 additions & 0 deletions src/targets/updateUserPool.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { newMockCognitoService } from "../__tests__/mockCognitoService";
import { newMockUserPoolService } from "../__tests__/mockUserPoolService";
import { TestContext } from "../__tests__/testContext";
import * as TDB from "../__tests__/testDataBuilder";
import { CognitoService, UserPoolService } from "../services";
import { UpdateUserPool, UpdateUserPoolTarget } from "./updateUserPool";

describe("UpdateUserPool target", () => {
let updateUserPool: UpdateUserPoolTarget;
let mockCognitoService: jest.Mocked<CognitoService>;
let mockUserPoolService: jest.Mocked<UserPoolService>;

beforeEach(() => {
mockUserPoolService = newMockUserPoolService();
mockCognitoService = newMockCognitoService(mockUserPoolService);

updateUserPool = UpdateUserPool({
cognito: mockCognitoService,
});
});

it("updates a user pool", async () => {
const existingUserPool = TDB.userPool({
Name: "name",
});

const userPoolService = newMockUserPoolService(existingUserPool);

mockCognitoService.getUserPool.mockResolvedValue(userPoolService);

await updateUserPool(TestContext, {
UserPoolId: existingUserPool.Id,
MfaConfiguration: "OPTIONAL",
});

expect(userPoolService.update).toHaveBeenCalledWith(TestContext, {
...existingUserPool,
MfaConfiguration: "OPTIONAL",
});
});

it.todo("throws if the user pool client doesn't exist");
});
44 changes: 44 additions & 0 deletions src/targets/updateUserPool.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import {
UpdateUserPoolRequest,
UpdateUserPoolResponse,
} from "aws-sdk/clients/cognitoidentityserviceprovider";
import { Services } from "../services";
import { UserPool } from "../services/userPoolService";
import { Target } from "./Target";

export type UpdateUserPoolTarget = Target<
UpdateUserPoolRequest,
UpdateUserPoolResponse
>;

type UpdateUserPoolServices = Pick<Services, "cognito">;

export const UpdateUserPool =
({ cognito }: UpdateUserPoolServices): UpdateUserPoolTarget =>
async (ctx, req) => {
const userPool = await cognito.getUserPool(ctx, req.UserPoolId);

const updatedUserPool: UserPool = {
...userPool.config,
AccountRecoverySetting: req.AccountRecoverySetting,
AdminCreateUserConfig: req.AdminCreateUserConfig,
AutoVerifiedAttributes: req.AutoVerifiedAttributes,
DeviceConfiguration: req.DeviceConfiguration,
EmailConfiguration: req.EmailConfiguration,
EmailVerificationMessage: req.EmailVerificationMessage,
EmailVerificationSubject: req.EmailVerificationSubject,
LambdaConfig: req.LambdaConfig,
MfaConfiguration: req.MfaConfiguration,
Policies: req.Policies,
SmsAuthenticationMessage: req.SmsAuthenticationMessage,
SmsConfiguration: req.SmsConfiguration,
SmsVerificationMessage: req.SmsVerificationMessage,
UserPoolAddOns: req.UserPoolAddOns,
UserPoolTags: req.UserPoolTags,
VerificationMessageTemplate: req.VerificationMessageTemplate,
};

await userPool.update(ctx, updatedUserPool);

return {};
};

0 comments on commit fc62e8f

Please sign in to comment.