Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions packages/agents-a365-runtime/src/utility.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import { TurnContext } from '@microsoft/agents-hosting';
import * as jwt from 'jsonwebtoken';
import { type } from 'os';
Comment thread
JesuTerraz marked this conversation as resolved.
Outdated

/**
* Utility class providing helper methods for agent runtime operations.
Expand Down Expand Up @@ -47,4 +48,24 @@

return agenticAppId;
}

Comment thread
JesuTerraz marked this conversation as resolved.
public static GetUserAgentHeader(orchestrator: string = ""): string {
Comment thread
JesuTerraz marked this conversation as resolved.
Outdated
const packageJson = require('../../package.json');

Check failure on line 53 in packages/agents-a365-runtime/src/utility.ts

View workflow job for this annotation

GitHub Actions / Node.js SDK (18)

A `require()` style import is forbidden

Check failure on line 53 in packages/agents-a365-runtime/src/utility.ts

View workflow job for this annotation

GitHub Actions / Node.js SDK (20)

A `require()` style import is forbidden
const version = packageJson.version || 'unknown';
return `Agent365SDK/${version} ${this.ResolveOsType()}; Node.js/; ${orchestrator}`;
Comment thread
JesuTerraz marked this conversation as resolved.
Outdated
Comment thread
JesuTerraz marked this conversation as resolved.
Outdated
}

private static ResolveOsType(): string {
Comment thread
JesuTerraz marked this conversation as resolved.
Outdated
const osType = type();
switch (osType) {
case 'Windows_NT':
return 'Windows';
case 'Darwin':
return 'macOS';
case 'Linux':
return 'Linux';
default:
return osType;
}
}
}
192 changes: 192 additions & 0 deletions tests/common/utility.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
import { Utility } from '@microsoft/agents-a365-runtime';
Comment thread
JesuTerraz marked this conversation as resolved.
Outdated
import * as jwt from 'jsonwebtoken';

describe('Utility', () => {
describe('GetAppIdFromToken', () => {
it('returns default GUID for empty token', () => {
// Arrange
const emptyToken = '';
const undefinedToken = undefined as any;

// Act
const result1 = Utility.GetAppIdFromToken(emptyToken);
const result2 = Utility.GetAppIdFromToken(undefinedToken);

// Assert
expect(result1).toBe('00000000-0000-0000-0000-000000000000');
expect(result2).toBe('00000000-0000-0000-0000-000000000000');
});

it('returns empty string for invalid token', () => {
// Arrange
const invalidToken = 'not-a-jwt';

// Act
const result = Utility.GetAppIdFromToken(invalidToken);

// Assert
expect(result).toBe('');
});

it('returns appid claim if present', () => {
// Arrange
const payload = { appid: 'test-appid' };
const token = jwt.sign(payload, 'secret');

// Act
const result = Utility.GetAppIdFromToken(token);

// Assert
expect(result).toBe('test-appid');
});

it('returns azp claim if appid is missing', () => {
// Arrange
const payload = { azp: 'test-azp' };
const token = jwt.sign(payload, 'secret');

// Act
const result = Utility.GetAppIdFromToken(token);

// Assert
expect(result).toBe('test-azp');
});

it('returns empty string if neither appid nor azp', () => {
// Arrange
const payload = { foo: 'bar' };
const token = jwt.sign(payload, 'secret');

// Act
const result = Utility.GetAppIdFromToken(token);

// Assert
expect(result).toBe('');
});
});

describe('ResolveAgentIdentity', () => {
const createMockContext = (isAgentic: boolean, agenticId?: string) => ({
activity: {
isAgenticRequest: () => isAgentic,
getAgenticInstanceId: () => agenticId,
},
}) as any;

it('returns agentic instance ID if isAgenticRequest is true', () => {
// Arrange
const ctx = createMockContext(true, 'agentic-id-123');
const token = 'token';

// Act
const result = Utility.ResolveAgentIdentity(ctx, token);

// Assert
expect(result).toBe('agentic-id-123');
});

it('returns empty string if isAgenticRequest is true but no agenticId', () => {
// Arrange
const ctx = createMockContext(true, undefined);
const token = 'token';

// Act
const result = Utility.ResolveAgentIdentity(ctx, token);

// Assert
expect(result).toBe('');
});

it('falls back to GetAppIdFromToken if not agentic', () => {
// Arrange
const ctx = createMockContext(false);
const token = 'token';
const spy = jest.spyOn(Utility, 'GetAppIdFromToken').mockReturnValue('fallback-id');

// Act
const result = Utility.ResolveAgentIdentity(ctx, token);

// Assert
expect(result).toBe('fallback-id');
spy.mockRestore();
});
});

describe('GetUserAgentHeader', () => {
it('returns string containing version, OS, and orchestrator', () => {
// Arrange
const orchestrator = 'orch';

// Act
const header = Utility.GetUserAgentHeader(orchestrator);

// Assert
expect(header).toMatch(/Agent365SDK\/.+ (Windows|Linux|macOS|.+); Node\.js\/; orch/);
});

it('works without orchestrator passed', () => {
// Arrange

// Act
const header = Utility.GetUserAgentHeader();

// Assert
expect(header).toMatch(/Agent365SDK\/.+ (Windows|Linux|macOS|.+); Node\.js\/; /);
});
});

describe('ResolveOsType', () => {
afterEach(() => {
jest.resetModules();
jest.clearAllMocks();
});

it('returns "Windows" for Windows_NT', () => {
// Arrange
jest.mock('os', () => ({ type: () => 'Windows_NT' }), { virtual: true });
const { Utility } = require('@microsoft/agents-a365-runtime');

// Act
const result = Utility.ResolveOsType();

// Assert
expect(result).toBe('Windows');
});

it('returns "macOS" for Darwin', () => {
// Arrange
jest.mock('os', () => ({ type: () => 'Darwin' }), { virtual: true });
const { Utility } = require('@microsoft/agents-a365-runtime');

// Act
const result = Utility.ResolveOsType();

// Assert
expect(result).toBe('macOS');
});

it('returns "Linux" for Linux', () => {
// Arrange
jest.mock('os', () => ({ type: () => 'Linux' }), { virtual: true });
const { Utility } = require('@microsoft/agents-a365-runtime');

// Act
const result = Utility.ResolveOsType();

// Assert
expect(result).toBe('Linux');
});

it('returns type for unknown OS', () => {
// Arrange
jest.mock('os', () => ({ type: () => 'OtherOS' }), { virtual: true });
const { Utility } = require('@microsoft/agents-a365-runtime');

// Act
const result = Utility.ResolveOsType();

// Assert
expect(result).toBe('OtherOS');
});
});
});
Loading