Docker / build (push) Has been cancelled
При синке UserAPI цена и период берутся по server-plan.id из индекса тарифов, а не остаются нулевыми. Co-authored-by: Cursor <[email protected]>
171 lines
4.6 KiB
TypeScript
171 lines
4.6 KiB
TypeScript
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
import { closeDb, getSqlite } from '@cfdm/db'
|
|
import { resetTestDb } from '@cfdm/db/test-setup'
|
|
import { providerAccountsRepository } from '@cfdm/db/repositories/provider-accounts'
|
|
|
|
import { syncFromUserApi } from './sync.js'
|
|
import type { UserApiSyncAccount } from './context.js'
|
|
|
|
vi.mock('./operations.js', () => ({
|
|
fetchServersWithDetails: vi.fn(),
|
|
fetchBalance: vi.fn(),
|
|
fetchTariffList: vi.fn(),
|
|
fetchPlanCostIndex: vi.fn(),
|
|
fetchOperations: vi.fn(),
|
|
}))
|
|
|
|
import {
|
|
fetchBalance,
|
|
fetchOperations,
|
|
fetchPlanCostIndex,
|
|
fetchServersWithDetails,
|
|
fetchTariffList,
|
|
} from './operations.js'
|
|
|
|
function makeAccount(apiType: 'macloud' | 'vdsina'): UserApiSyncAccount {
|
|
return {
|
|
id: `acc-${apiType}`,
|
|
providerId: `prov-${apiType}`,
|
|
name: `${apiType} Account`,
|
|
panelUrl: '',
|
|
currency: 'RUB',
|
|
billingMode: 'daily',
|
|
notes: '',
|
|
apiType,
|
|
apiBaseUrl:
|
|
apiType === 'macloud'
|
|
? 'https://userapi.macloud.ru/v1'
|
|
: 'https://userapi.vdsina.com/v1',
|
|
apiCredentials: 'secret-token',
|
|
apiToken: 'secret-token',
|
|
balanceApi: null,
|
|
balanceCurrency: null,
|
|
balanceUpdatedAt: null,
|
|
enoughmoneyto: '',
|
|
balanceAlertBelow: null,
|
|
}
|
|
}
|
|
|
|
describe('syncFromUserApi', () => {
|
|
beforeEach(() => {
|
|
resetTestDb()
|
|
vi.mocked(fetchServersWithDetails).mockResolvedValue([
|
|
{
|
|
id: 100,
|
|
name: 'Server #100',
|
|
status: 'active',
|
|
end: '2029-01-01',
|
|
ip: { ip: '1.2.3.4', type: '4' },
|
|
template: { name: 'Debian 12' },
|
|
datacenter: { id: 1, name: 'DC1', country: 'ru' },
|
|
'server-plan': { id: 13, name: '2 RAM / 1 CPU / 40 NVMe' },
|
|
data: { cpu: { value: 1 }, ram: { value: 2 }, disk: { value: 40 } },
|
|
},
|
|
])
|
|
vi.mocked(fetchBalance).mockResolvedValue({
|
|
balance: 500,
|
|
currency: 'RUB',
|
|
enoughmoneyto: '2029-12-01',
|
|
})
|
|
vi.mocked(fetchTariffList).mockResolvedValue([
|
|
{
|
|
externalId: '13',
|
|
datacenterKey: '11',
|
|
datacenterName: 'Cloud',
|
|
name: '2 RAM / 1 CPU / 40 NVMe',
|
|
desc: '',
|
|
vcpu: 1,
|
|
ramGb: 2,
|
|
diskGb: 40,
|
|
diskType: 'NVMe',
|
|
virtualization: 'KVM',
|
|
channel: '',
|
|
location: 'Cloud',
|
|
country: '',
|
|
cpuModel: '',
|
|
orderAvailable: true,
|
|
price: '1.55 ₽/день',
|
|
},
|
|
])
|
|
vi.mocked(fetchPlanCostIndex).mockResolvedValue(
|
|
new Map([
|
|
[
|
|
'13',
|
|
{
|
|
id: 13,
|
|
name: '2 RAM / 1 CPU / 40 NVMe',
|
|
cost: 1.55,
|
|
period: 'day',
|
|
},
|
|
],
|
|
]),
|
|
)
|
|
vi.mocked(fetchOperations).mockResolvedValue([
|
|
{
|
|
id: 999,
|
|
purse: 'real',
|
|
type: 1,
|
|
status: 1,
|
|
summ: '200',
|
|
created: '2025-03-01 10:00:00',
|
|
comment: 'Top up',
|
|
},
|
|
])
|
|
})
|
|
|
|
afterEach(() => {
|
|
closeDb()
|
|
})
|
|
|
|
it('syncs macloud account with correct id prefix', async () => {
|
|
getSqlite()
|
|
.prepare(
|
|
`INSERT INTO providers (id, name, apiType, apiBaseUrl) VALUES ('prov-macloud', 'Macloud', 'macloud', 'https://userapi.macloud.ru/v1')`,
|
|
)
|
|
.run()
|
|
providerAccountsRepository.create({
|
|
id: 'acc-macloud',
|
|
providerId: 'prov-macloud',
|
|
name: 'Macloud',
|
|
apiCredentials: 'secret-token',
|
|
})
|
|
|
|
const result = await syncFromUserApi(makeAccount('macloud'))
|
|
|
|
expect(result.vpsCount).toBe(1)
|
|
expect(result.paymentsCount).toBe(1)
|
|
expect(result.tariffsCount).toBe(1)
|
|
expect(result.balance?.balance).toBe(500)
|
|
|
|
const vps = getSqlite().prepare('SELECT id, notes, dailyRate, tariffType FROM vps WHERE id = ?').get('vps-macloud-acc-macloud-100') as {
|
|
id: string
|
|
notes: string
|
|
dailyRate: number
|
|
tariffType: string
|
|
}
|
|
expect(vps.notes).toContain('macloud-100')
|
|
expect(vps.dailyRate).toBe(1.55)
|
|
expect(vps.tariffType).toBe('daily')
|
|
})
|
|
|
|
it('syncs vdsina account with vdsina id prefix', async () => {
|
|
getSqlite()
|
|
.prepare(
|
|
`INSERT INTO providers (id, name, apiType, apiBaseUrl) VALUES ('prov-vdsina', 'VDSina', 'vdsina', 'https://userapi.vdsina.com/v1')`,
|
|
)
|
|
.run()
|
|
providerAccountsRepository.create({
|
|
id: 'acc-vdsina',
|
|
providerId: 'prov-vdsina',
|
|
name: 'VDSina',
|
|
apiCredentials: 'secret-token',
|
|
})
|
|
|
|
const result = await syncFromUserApi(makeAccount('vdsina'))
|
|
|
|
expect(result.vpsCount).toBe(1)
|
|
const vps = getSqlite().prepare('SELECT id FROM vps WHERE id = ?').get('vps-vdsina-acc-vdsina-100')
|
|
expect(vps).toBeTruthy()
|
|
})
|
|
})
|