mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-12-27 12:51:41 +00:00
Shell: Integrate Cloudshell to existing shells (#2098)
* first draft * refactored code * ux fix * add custom header support and fix ui * minor changes * hide last command also * remove logger * bug fixes * updated loick file * fix tests * moved files * update readme * documentation update * fix compilationerror * undefined check handle * format fix * format fix * fix lints * format fix * fix unrelatred test * code refator * fix format * ut fix * cgmanifest * Revert "cgmanifest" This reverts commit 2e76a6926ee0d3d4e0510f2e04e03446c2ca8c47. * fix snap * test fix * formatting code * updated xterm * include username in command * cloudshell add exit * fix test * format fix * tets fix * fix multiple open cloudshell calls * socket time out after 20 min * remove unused code * 120 min * Addressed comments
This commit is contained in:
337
src/Explorer/Tabs/CloudShellTab/Data/CloudShellClient.test.tsx
Normal file
337
src/Explorer/Tabs/CloudShellTab/Data/CloudShellClient.test.tsx
Normal file
@@ -0,0 +1,337 @@
|
||||
import { armRequest } from "../../../../Utils/arm/request";
|
||||
import { NetworkType, OsType, SessionType, ShellType } from "../Models/DataModels";
|
||||
import {
|
||||
connectTerminal,
|
||||
getUserSettings,
|
||||
provisionConsole,
|
||||
putEphemeralUserSettings,
|
||||
registerCloudShellProvider,
|
||||
verifyCloudShellProviderRegistration,
|
||||
} from "./CloudShellClient";
|
||||
|
||||
// Instead of redeclaring fetch, modify the global context
|
||||
/* eslint-disable @typescript-eslint/no-namespace */
|
||||
declare global {
|
||||
namespace NodeJS {
|
||||
interface Global {
|
||||
fetch: jest.Mock;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* eslint-enable @typescript-eslint/no-namespace */
|
||||
|
||||
// Define mock endpoint
|
||||
const MOCK_ARM_ENDPOINT = "https://mock-management.azure.com";
|
||||
|
||||
// Mock dependencies
|
||||
jest.mock("uuid", () => ({
|
||||
v4: jest.fn().mockReturnValue("mocked-uuid"),
|
||||
}));
|
||||
|
||||
jest.mock("../../../../ConfigContext", () => ({
|
||||
configContext: {
|
||||
ARM_ENDPOINT: "https://mock-management.azure.com",
|
||||
},
|
||||
}));
|
||||
|
||||
jest.mock("../../../../UserContext", () => ({
|
||||
userContext: {
|
||||
authorizationToken: "Bearer mock-token",
|
||||
},
|
||||
}));
|
||||
|
||||
jest.mock("../../../../Utils/arm/request");
|
||||
|
||||
jest.mock("../Utils/CommonUtils", () => ({
|
||||
getLocale: jest.fn().mockReturnValue("en-US"),
|
||||
}));
|
||||
|
||||
// Properly mock fetch with correct typings
|
||||
const mockJsonPromise = jest.fn();
|
||||
global.fetch = jest.fn().mockImplementationOnce(() => {
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
json: mockJsonPromise,
|
||||
text: jest.fn().mockResolvedValue(""),
|
||||
headers: new Headers(),
|
||||
} as unknown as Promise<Response>;
|
||||
}) as jest.Mock;
|
||||
|
||||
describe("CloudShellClient", () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
mockJsonPromise.mockClear();
|
||||
});
|
||||
|
||||
// Reset all mocks after all tests
|
||||
afterAll(() => {
|
||||
jest.resetAllMocks();
|
||||
jest.restoreAllMocks();
|
||||
if (global.fetch) {
|
||||
delete global.fetch;
|
||||
}
|
||||
});
|
||||
|
||||
describe("getUserSettings", () => {
|
||||
it("should call armRequest with correct parameters and return settings", async () => {
|
||||
const mockSettings = { properties: { preferredLocation: "eastus" } };
|
||||
(armRequest as jest.Mock).mockResolvedValueOnce(mockSettings);
|
||||
|
||||
const result = await getUserSettings();
|
||||
|
||||
expect(armRequest).toHaveBeenCalledWith({
|
||||
host: MOCK_ARM_ENDPOINT,
|
||||
path: "/providers/Microsoft.Portal/userSettings/cloudconsole",
|
||||
method: "GET",
|
||||
apiVersion: "2023-02-01-preview",
|
||||
});
|
||||
expect(result).toEqual(mockSettings);
|
||||
});
|
||||
|
||||
it("should handle errors when settings retrieval fails", async () => {
|
||||
const mockError = new Error("Failed to get user settings");
|
||||
(armRequest as jest.Mock).mockRejectedValueOnce(mockError);
|
||||
|
||||
await expect(getUserSettings()).rejects.toThrow("Failed to get user settings");
|
||||
|
||||
expect(armRequest).toHaveBeenCalledWith({
|
||||
host: MOCK_ARM_ENDPOINT,
|
||||
path: "/providers/Microsoft.Portal/userSettings/cloudconsole",
|
||||
method: "GET",
|
||||
apiVersion: "2023-02-01-preview",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("putEphemeralUserSettings", () => {
|
||||
it("should call armRequest with default network settings", async () => {
|
||||
const mockResponse = { id: "settings-id" };
|
||||
(armRequest as jest.Mock).mockResolvedValueOnce(mockResponse);
|
||||
|
||||
const result = await putEphemeralUserSettings("sub-id", "eastus");
|
||||
|
||||
expect(armRequest).toHaveBeenCalledWith({
|
||||
host: MOCK_ARM_ENDPOINT,
|
||||
path: "/providers/Microsoft.Portal/userSettings/cloudconsole",
|
||||
method: "PUT",
|
||||
apiVersion: "2023-02-01-preview",
|
||||
body: {
|
||||
properties: {
|
||||
preferredOsType: OsType.Linux,
|
||||
preferredShellType: ShellType.Bash,
|
||||
preferredLocation: "eastus",
|
||||
networkType: NetworkType.Default,
|
||||
sessionType: SessionType.Ephemeral,
|
||||
userSubscription: "sub-id",
|
||||
vnetSettings: {},
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(result).toEqual(mockResponse);
|
||||
});
|
||||
|
||||
it("should call armRequest with isolated network settings", async () => {
|
||||
const mockVNetSettings = { subnetId: "test-subnet" };
|
||||
const mockResponse = { id: "settings-id" };
|
||||
(armRequest as jest.Mock).mockResolvedValueOnce(mockResponse);
|
||||
|
||||
await putEphemeralUserSettings("sub-id", "eastus", mockVNetSettings);
|
||||
|
||||
expect(armRequest).toHaveBeenCalledWith({
|
||||
host: MOCK_ARM_ENDPOINT,
|
||||
path: "/providers/Microsoft.Portal/userSettings/cloudconsole",
|
||||
method: "PUT",
|
||||
apiVersion: "2023-02-01-preview",
|
||||
body: {
|
||||
properties: {
|
||||
preferredOsType: OsType.Linux,
|
||||
preferredShellType: ShellType.Bash,
|
||||
preferredLocation: "eastus",
|
||||
networkType: NetworkType.Isolated,
|
||||
sessionType: SessionType.Ephemeral,
|
||||
userSubscription: "sub-id",
|
||||
vnetSettings: mockVNetSettings,
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("should handle errors when updating settings fails", async () => {
|
||||
const mockError = new Error("Failed to update user settings");
|
||||
(armRequest as jest.Mock).mockRejectedValueOnce(mockError);
|
||||
|
||||
await expect(putEphemeralUserSettings("sub-id", "eastus")).rejects.toThrow("Failed to update user settings");
|
||||
|
||||
expect(armRequest).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("verifyCloudShellProviderRegistration", () => {
|
||||
it("should call armRequest with correct parameters", async () => {
|
||||
const mockResponse = { registrationState: "Registered" };
|
||||
(armRequest as jest.Mock).mockResolvedValueOnce(mockResponse);
|
||||
|
||||
const result = await verifyCloudShellProviderRegistration("sub-id");
|
||||
|
||||
expect(armRequest).toHaveBeenCalledWith({
|
||||
host: MOCK_ARM_ENDPOINT,
|
||||
path: "/subscriptions/sub-id/providers/Microsoft.CloudShell",
|
||||
method: "GET",
|
||||
apiVersion: "2022-12-01",
|
||||
});
|
||||
expect(result).toEqual(mockResponse);
|
||||
});
|
||||
|
||||
it("should handle errors when verification fails", async () => {
|
||||
const mockError = new Error("Failed to verify provider registration");
|
||||
(armRequest as jest.Mock).mockRejectedValueOnce(mockError);
|
||||
|
||||
await expect(verifyCloudShellProviderRegistration("sub-id")).rejects.toThrow(
|
||||
"Failed to verify provider registration",
|
||||
);
|
||||
|
||||
expect(armRequest).toHaveBeenCalledWith({
|
||||
host: MOCK_ARM_ENDPOINT,
|
||||
path: "/subscriptions/sub-id/providers/Microsoft.CloudShell",
|
||||
method: "GET",
|
||||
apiVersion: "2022-12-01",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("registerCloudShellProvider", () => {
|
||||
it("should call armRequest with correct parameters", async () => {
|
||||
const mockResponse = { operationId: "op-id" };
|
||||
(armRequest as jest.Mock).mockResolvedValueOnce(mockResponse);
|
||||
|
||||
const result = await registerCloudShellProvider("sub-id");
|
||||
|
||||
expect(armRequest).toHaveBeenCalledWith({
|
||||
host: MOCK_ARM_ENDPOINT,
|
||||
path: "/subscriptions/sub-id/providers/Microsoft.CloudShell/register",
|
||||
method: "POST",
|
||||
apiVersion: "2022-12-01",
|
||||
});
|
||||
expect(result).toEqual(mockResponse);
|
||||
});
|
||||
|
||||
it("should handle errors when registration fails", async () => {
|
||||
const mockError = new Error("Failed to register provider");
|
||||
(armRequest as jest.Mock).mockRejectedValueOnce(mockError);
|
||||
|
||||
await expect(registerCloudShellProvider("sub-id")).rejects.toThrow("Failed to register provider");
|
||||
|
||||
expect(armRequest).toHaveBeenCalledWith({
|
||||
host: MOCK_ARM_ENDPOINT,
|
||||
path: "/subscriptions/sub-id/providers/Microsoft.CloudShell/register",
|
||||
method: "POST",
|
||||
apiVersion: "2022-12-01",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("provisionConsole", () => {
|
||||
it("should call armRequest with correct parameters", async () => {
|
||||
const mockResponse = { uri: "https://shell.azure.com/console123" };
|
||||
(armRequest as jest.Mock).mockResolvedValueOnce(mockResponse);
|
||||
|
||||
const result = await provisionConsole("eastus");
|
||||
|
||||
expect(armRequest).toHaveBeenCalledWith({
|
||||
host: MOCK_ARM_ENDPOINT,
|
||||
path: "providers/Microsoft.Portal/consoles/default",
|
||||
method: "PUT",
|
||||
apiVersion: "2023-02-01-preview",
|
||||
customHeaders: {
|
||||
"x-ms-console-preferred-location": "eastus",
|
||||
},
|
||||
body: {
|
||||
properties: {
|
||||
osType: OsType.Linux,
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(result).toEqual(mockResponse);
|
||||
});
|
||||
|
||||
it("should handle errors when console provisioning fails", async () => {
|
||||
const mockError = new Error("Failed to provision console");
|
||||
(armRequest as jest.Mock).mockRejectedValueOnce(mockError);
|
||||
|
||||
await expect(provisionConsole("eastus")).rejects.toThrow("Failed to provision console");
|
||||
|
||||
expect(armRequest).toHaveBeenCalledWith({
|
||||
host: MOCK_ARM_ENDPOINT,
|
||||
path: "providers/Microsoft.Portal/consoles/default",
|
||||
method: "PUT",
|
||||
apiVersion: "2023-02-01-preview",
|
||||
customHeaders: {
|
||||
"x-ms-console-preferred-location": "eastus",
|
||||
},
|
||||
body: {
|
||||
properties: {
|
||||
osType: OsType.Linux,
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("connectTerminal", () => {
|
||||
it("should call fetch with correct parameters", async () => {
|
||||
const consoleUri = "https://shell.azure.com/console123";
|
||||
const size = { rows: 24, cols: 80 };
|
||||
const mockTerminalResponse = { id: "terminal-id", socketUri: "wss://shell.azure.com/socket" };
|
||||
|
||||
// Setup the mock response
|
||||
mockJsonPromise.mockResolvedValueOnce(mockTerminalResponse);
|
||||
|
||||
const result = await connectTerminal(consoleUri, size);
|
||||
|
||||
expect(global.fetch).toHaveBeenCalledWith(
|
||||
"https://shell.azure.com/console123/terminals?cols=80&rows=24&version=2019-01-01&shell=bash",
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
Accept: "application/json",
|
||||
"Content-Type": "application/json",
|
||||
"Content-Length": "2",
|
||||
Authorization: "Bearer mock-token",
|
||||
"x-ms-client-request-id": "mocked-uuid",
|
||||
"Accept-Language": "en-US",
|
||||
},
|
||||
body: "{}",
|
||||
},
|
||||
);
|
||||
expect(mockJsonPromise).toHaveBeenCalled();
|
||||
expect(result).toEqual(mockTerminalResponse);
|
||||
});
|
||||
|
||||
it("should handle errors when terminal connection fails", async () => {
|
||||
const consoleUri = "https://shell.azure.com/console123";
|
||||
const size = { rows: 24, cols: 80 };
|
||||
|
||||
// Mock fetch to return a failed response
|
||||
global.fetch = jest.fn().mockImplementationOnce(() => {
|
||||
return {
|
||||
ok: false,
|
||||
status: 500,
|
||||
statusText: "Internal Server Error",
|
||||
json: jest.fn().mockRejectedValue(new Error("Failed to parse JSON")),
|
||||
text: jest.fn().mockResolvedValue("Server Error"),
|
||||
headers: new Headers(),
|
||||
} as unknown as Promise<Response>;
|
||||
});
|
||||
|
||||
await expect(connectTerminal(consoleUri, size)).rejects.toThrow(
|
||||
"Failed to connect to terminal: 500 Internal Server Error",
|
||||
);
|
||||
|
||||
expect(global.fetch).toHaveBeenCalledWith(
|
||||
"https://shell.azure.com/console123/terminals?cols=80&rows=24&version=2019-01-01&shell=bash",
|
||||
expect.any(Object),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user