/**
* Azure Tools Tests
*/
import { jest } from '@jest/globals';
import {
azureCheckCli,
azureAcrSetup,
azureContainerAppsDeploy,
setCommandRunner
} from '../src/tools.js';
describe('Azure Tools', () => {
let mockRunner;
beforeEach(() => {
mockRunner = jest.fn();
setCommandRunner(mockRunner);
});
describe('azureCheckCli', () => {
test('should pass all checks when Azure CLI is configured', async () => {
mockRunner
.mockResolvedValueOnce({ success: true, stdout: 'azure-cli 2.55.0', stderr: '' })
.mockResolvedValueOnce({ success: true, stdout: 'My Subscription\t12345678-1234-1234-1234-123456789012', stderr: '' });
const result = await azureCheckCli();
expect(result.content[0].text).toContain('[OK] Azure CLI');
expect(result.content[0].text).toContain('[OK] Logged in to Azure');
expect(result.content[0].text).toContain('My Subscription');
});
test('should fail when Azure CLI is not installed', async () => {
mockRunner.mockResolvedValueOnce({
success: false,
error: 'command not found: az',
stdout: '',
stderr: ''
});
const result = await azureCheckCli();
expect(result.content[0].text).toContain('[FAIL] Azure CLI not installed');
expect(result.content[0].text).toContain('https://docs.microsoft.com/cli/azure/install-azure-cli');
});
test('should fail when not logged in', async () => {
mockRunner
.mockResolvedValueOnce({ success: true, stdout: 'azure-cli 2.55.0', stderr: '' })
.mockResolvedValueOnce({ success: false, error: 'Please run az login', stdout: '', stderr: '' });
const result = await azureCheckCli();
expect(result.content[0].text).toContain('[OK] Azure CLI');
expect(result.content[0].text).toContain('[FAIL] Not logged in to Azure');
expect(result.content[0].text).toContain('az login');
});
});
describe('azureAcrSetup', () => {
test('should reject invalid registry name - too short', async () => {
const result = await azureAcrSetup({
name: 'abc',
resource_group: 'myapp-rg',
location: 'westus2',
sku: 'Basic'
});
expect(result.content[0].text).toContain('Invalid registry name');
expect(result.content[0].text).toContain('5-50 characters');
});
test('should reject invalid registry name - contains hyphen', async () => {
const result = await azureAcrSetup({
name: 'my-registry',
resource_group: 'myapp-rg',
location: 'westus2',
sku: 'Basic'
});
expect(result.content[0].text).toContain('Invalid registry name');
expect(result.content[0].text).toContain('Alphanumeric only');
});
test('should reject invalid registry name - contains underscore', async () => {
const result = await azureAcrSetup({
name: 'my_registry',
resource_group: 'myapp-rg',
location: 'westus2',
sku: 'Basic'
});
expect(result.content[0].text).toContain('Invalid registry name');
});
test('should accept valid registry name', async () => {
mockRunner
.mockResolvedValueOnce({ success: true, stdout: '', stderr: '' }) // rg check
.mockResolvedValueOnce({ success: true, stdout: '{"id": "..."}', stderr: '' }); // acr create
const result = await azureAcrSetup({
name: 'myappacr2024',
resource_group: 'myapp-rg',
location: 'westus2',
sku: 'Basic'
});
expect(result.content[0].text).toContain('Registry created successfully');
expect(result.content[0].text).toContain('myappacr2024');
});
test('should create resource group if it does not exist', async () => {
mockRunner
.mockResolvedValueOnce({ success: false, error: 'not found', stderr: '' }) // rg check fails
.mockResolvedValueOnce({ success: true, stdout: '{"id": "..."}', stderr: '' }) // rg create
.mockResolvedValueOnce({ success: true, stdout: '{"id": "..."}', stderr: '' }); // acr create
const result = await azureAcrSetup({
name: 'myappacr',
resource_group: 'new-rg',
location: 'westus2',
sku: 'Basic'
});
expect(result.content[0].text).toContain('Creating resource group');
expect(result.content[0].text).toContain('Resource group created');
});
test('should handle resource group creation failure', async () => {
mockRunner
.mockResolvedValueOnce({ success: false, error: 'not found', stderr: '' }) // rg check fails
.mockResolvedValueOnce({ success: false, error: 'permission denied', stderr: 'permission denied' }); // rg create fails
const result = await azureAcrSetup({
name: 'myappacr',
resource_group: 'new-rg',
location: 'westus2',
sku: 'Basic'
});
expect(result.content[0].text).toContain('Failed to create resource group');
});
test('should handle ACR creation failure - name taken', async () => {
mockRunner
.mockResolvedValueOnce({ success: true, stdout: '', stderr: '' }) // rg check
.mockResolvedValueOnce({ success: false, error: 'NameNotAvailable', stderr: 'The registry name is already in use' });
const result = await azureAcrSetup({
name: 'existingacr',
resource_group: 'myapp-rg',
location: 'westus2',
sku: 'Basic'
});
expect(result.content[0].text).toContain('Failed to create registry');
});
});
describe('azureContainerAppsDeploy', () => {
test('should create environment if it does not exist', async () => {
mockRunner
.mockResolvedValueOnce({ success: false, error: 'not found', stderr: '' }) // env check
.mockResolvedValueOnce({ success: true, stdout: '', stderr: '' }) // env create
.mockResolvedValueOnce({ success: true, stdout: '', stderr: '' }) // app create
.mockResolvedValueOnce({ success: true, stdout: 'myapp.azurecontainerapps.io', stderr: '' }); // get url
const result = await azureContainerAppsDeploy({
app_name: 'myapp',
resource_group: 'myapp-rg',
image: 'myacr.azurecr.io/myapp:latest',
environment: '',
port: 8080,
cpu: '0.5',
memory: '1Gi'
});
expect(result.content[0].text).toContain('Creating Container Apps environment');
expect(result.content[0].text).toContain('Environment created');
expect(result.content[0].text).toContain('Deployment successful');
});
test('should deploy successfully with existing environment', async () => {
mockRunner
.mockResolvedValueOnce({ success: true, stdout: '{"id": "..."}', stderr: '' }) // env exists
.mockResolvedValueOnce({ success: true, stdout: '', stderr: '' }) // app create
.mockResolvedValueOnce({ success: true, stdout: 'myapp.azurecontainerapps.io', stderr: '' }); // get url
const result = await azureContainerAppsDeploy({
app_name: 'myapp',
resource_group: 'myapp-rg',
image: 'myacr.azurecr.io/myapp:latest',
environment: 'existing-env',
port: 8080,
cpu: '0.5',
memory: '1Gi'
});
expect(result.content[0].text).not.toContain('Creating Container Apps environment');
expect(result.content[0].text).toContain('Deployment successful');
expect(result.content[0].text).toContain('https://myapp.azurecontainerapps.io');
});
test('should handle environment creation failure', async () => {
mockRunner
.mockResolvedValueOnce({ success: false, error: 'not found', stderr: '' }) // env check
.mockResolvedValueOnce({ success: false, error: 'quota exceeded', stderr: 'quota exceeded' }); // env create fails
const result = await azureContainerAppsDeploy({
app_name: 'myapp',
resource_group: 'myapp-rg',
image: 'myacr.azurecr.io/myapp:latest',
environment: '',
port: 8080,
cpu: '0.5',
memory: '1Gi'
});
expect(result.content[0].text).toContain('Failed to create environment');
});
test('should handle deployment failure', async () => {
mockRunner
.mockResolvedValueOnce({ success: true, stdout: '{"id": "..."}', stderr: '' }) // env exists
.mockResolvedValueOnce({ success: false, error: 'image not found', stderr: 'image not found' }); // app create fails
const result = await azureContainerAppsDeploy({
app_name: 'myapp',
resource_group: 'myapp-rg',
image: 'myacr.azurecr.io/nonexistent:latest',
environment: 'myenv',
port: 8080,
cpu: '0.5',
memory: '1Gi'
});
expect(result.content[0].text).toContain('Failed to deploy');
});
test('should detect ACR image and add registry args', async () => {
mockRunner
.mockResolvedValueOnce({ success: true, stdout: '{"id": "..."}', stderr: '' })
.mockResolvedValueOnce({ success: true, stdout: '', stderr: '' })
.mockResolvedValueOnce({ success: true, stdout: 'myapp.azurecontainerapps.io', stderr: '' });
await azureContainerAppsDeploy({
app_name: 'myapp',
resource_group: 'myapp-rg',
image: 'mycompanyacr.azurecr.io/myapp:v1',
environment: 'myenv',
port: 3000,
cpu: '1',
memory: '2Gi'
});
expect(mockRunner).toHaveBeenCalledWith(
expect.stringContaining('--registry-server mycompanyacr.azurecr.io'),
expect.anything()
);
});
test('should not add registry args for non-ACR images', async () => {
mockRunner
.mockResolvedValueOnce({ success: true, stdout: '{"id": "..."}', stderr: '' })
.mockResolvedValueOnce({ success: true, stdout: '', stderr: '' })
.mockResolvedValueOnce({ success: true, stdout: 'myapp.azurecontainerapps.io', stderr: '' });
await azureContainerAppsDeploy({
app_name: 'myapp',
resource_group: 'myapp-rg',
image: 'nginx:latest',
environment: 'myenv',
port: 80,
cpu: '0.25',
memory: '0.5Gi'
});
// The second call is the deploy command
const deployCall = mockRunner.mock.calls[1][0];
expect(deployCall).not.toContain('--registry-server');
});
});
});