Skip to content
Draft
Changes from all commits
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
150 changes: 148 additions & 2 deletions packages/cli-kit/src/public/node/os.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
import {platformAndArch} from './os.js'
import {describe, test, expect, vi} from 'vitest'
import {platformAndArch, username} from './os.js'
import {execa} from 'execa'
import {describe, test, expect, vi, beforeEach, afterEach} from 'vitest'
import {userInfo as osUserInfo} from 'os'

vi.mock('node:process')
vi.mock('execa')
vi.mock('os', async (importOriginal) => {
const actual = await importOriginal<typeof import('os')>()
return {
...actual,
userInfo: vi.fn(),
}
})
vi.mock('./output.js')

describe('platformAndArch', () => {
test("returns the right architecture when it's x64", () => {
Expand Down Expand Up @@ -40,3 +51,138 @@ describe('platformAndArch', () => {
expect(got.arch).toEqual('arm64')
})
})

describe('username', () => {
beforeEach(() => {
vi.stubEnv('SUDO_USER', '')
vi.stubEnv('C9_USER', '')
vi.stubEnv('LOGNAME', '')
vi.stubEnv('USER', '')
vi.stubEnv('LNAME', '')
vi.stubEnv('USERNAME', '')
})

afterEach(() => {
vi.unstubAllEnvs()
})

test('returns SUDO_USER if set', async () => {
vi.stubEnv('SUDO_USER', 'sudo-user-name')

const got = await username()

expect(got).toEqual('sudo-user-name')
expect(osUserInfo).not.toHaveBeenCalled()
expect(execa).not.toHaveBeenCalled()
})

test('returns USER if USER is set and SUDO_USER/C9_USER/LOGNAME are not', async () => {
vi.stubEnv('USER', 'user-name')

const got = await username()

expect(got).toEqual('user-name')
expect(osUserInfo).not.toHaveBeenCalled()
expect(execa).not.toHaveBeenCalled()
})

test('returns C9_USER if set and SUDO_USER is not', async () => {
vi.stubEnv('C9_USER', 'c9-user-name')
const got = await username()
expect(got).toEqual('c9-user-name')
})

test('returns LOGNAME if set and SUDO_USER/C9_USER are not', async () => {
vi.stubEnv('LOGNAME', 'logname-user-name')
const got = await username()
expect(got).toEqual('logname-user-name')
})

test('returns LNAME if set and SUDO_USER/C9_USER/LOGNAME/USER are not', async () => {
vi.stubEnv('LNAME', 'lname-user-name')
const got = await username()
expect(got).toEqual('lname-user-name')
})

test('returns USERNAME if set and others are not', async () => {
vi.stubEnv('USERNAME', 'username-user-name')
const got = await username()
expect(got).toEqual('username-user-name')
})

test('returns os.userInfo().username if set and environment variables are not', async () => {
vi.mocked(osUserInfo).mockReturnValue({username: 'userInfo-username'} as any)

const got = await username()

expect(got).toEqual('userInfo-username')
expect(osUserInfo).toHaveBeenCalled()
expect(execa).not.toHaveBeenCalled()
})

test('falls back to execa if os.userInfo() throws an error', async () => {
vi.mocked(osUserInfo).mockImplementation(() => {
throw new Error('userInfo error')
})
vi.mocked(execa).mockResolvedValue({stdout: 'id-username'} as any)

const got = await username('linux')

expect(got).toEqual('id-username')
expect(osUserInfo).toHaveBeenCalled()
expect(execa).toHaveBeenCalled()
})

test('on win32 platform, queries whoami and cleans domain prefix', async () => {
vi.mocked(osUserInfo).mockImplementation(() => {
throw new Error('userInfo error')
})
vi.mocked(execa).mockResolvedValueOnce({stdout: 'MYDOMAIN\\test-win-user'} as any)

const got = await username('win32')

expect(got).toEqual('test-win-user')
expect(execa).toHaveBeenCalledWith('whoami')
})

test('on non-win32 platform, queries uid and then resolves it to a name', async () => {
vi.mocked(osUserInfo).mockImplementation(() => {
throw new Error('userInfo error')
})
vi.mocked(execa)
.mockResolvedValueOnce({stdout: '1001'} as any)
.mockResolvedValueOnce({stdout: 'posix-user-name'} as any)

const got = await username('linux')

expect(got).toEqual('posix-user-name')
expect(execa).toHaveBeenCalledWith('id', ['-u'])
expect(execa).toHaveBeenCalledWith('id', ['-un', '1001'])
})

test('on non-win32 platform, falls back to id prefix when resolving uid fails', async () => {
vi.mocked(osUserInfo).mockImplementation(() => {
throw new Error('userInfo error')
})
vi.mocked(execa)
.mockResolvedValueOnce({stdout: '1001'} as any)
.mockRejectedValueOnce(new Error('id -un failed'))

const got = await username('darwin')

expect(got).toEqual('no-username-1001')
expect(execa).toHaveBeenCalledWith('id', ['-u'])
expect(execa).toHaveBeenCalledWith('id', ['-un', '1001'])
})

test('returns null when top-level execa throws an error', async () => {
vi.mocked(osUserInfo).mockImplementation(() => {
throw new Error('userInfo error')
})
vi.mocked(execa).mockRejectedValueOnce(new Error('whoami failed'))

const got = await username('win32')

expect(got).toBeNull()
})
})
Loading