@@ -2,8 +2,11 @@ const chai = require('chai');
22const chaiHttp = require ( 'chai-http' ) ;
33const sinon = require ( 'sinon' ) ;
44const express = require ( 'express' ) ;
5+ const fs = require ( 'fs' ) ;
6+ const path = require ( 'path' ) ;
57const usersRouter = require ( '../../../src/service/routes/users' ) . default ;
68const db = require ( '../../../src/db' ) ;
9+ const { DuplicateSSHKeyError, UserNotFoundError } = require ( '../../../src/errors/DatabaseErrors' ) ;
710
811const { expect } = chai ;
912chai . use ( chaiHttp ) ;
@@ -64,4 +67,89 @@ describe('Users API', function () {
6467 admin : false ,
6568 } ) ;
6669 } ) ;
70+
71+ describe ( 'POST /users/:username/ssh-keys' , function ( ) {
72+ let authenticatedApp ;
73+ const validPublicKey = fs
74+ . readFileSync ( path . join ( __dirname , '../../.ssh/host_key.pub' ) , 'utf8' )
75+ . trim ( ) ;
76+
77+ before ( function ( ) {
78+ authenticatedApp = express ( ) ;
79+ authenticatedApp . use ( express . json ( ) ) ;
80+ authenticatedApp . use ( ( req , res , next ) => {
81+ req . user = { username : 'alice' , admin : true } ;
82+ next ( ) ;
83+ } ) ;
84+ authenticatedApp . use ( '/users' , usersRouter ) ;
85+ } ) ;
86+
87+ it ( 'should return 409 when SSH key is already used by another user' , async function ( ) {
88+ const publicKey = validPublicKey ;
89+
90+ sinon . stub ( db , 'addPublicKey' ) . rejects ( new DuplicateSSHKeyError ( 'bob' ) ) ;
91+
92+ const res = await chai
93+ . request ( authenticatedApp )
94+ . post ( '/users/alice/ssh-keys' )
95+ . send ( { publicKey } ) ;
96+
97+ expect ( res ) . to . have . status ( 409 ) ;
98+ expect ( res . body ) . to . have . property ( 'error' ) ;
99+ expect ( res . body . error ) . to . include ( "already in use by user 'bob'" ) ;
100+ } ) ;
101+
102+ it ( 'should return 404 when user not found' , async function ( ) {
103+ const publicKey = validPublicKey ;
104+
105+ sinon . stub ( db , 'addPublicKey' ) . rejects ( new UserNotFoundError ( 'nonexistent' ) ) ;
106+
107+ const res = await chai
108+ . request ( authenticatedApp )
109+ . post ( '/users/nonexistent/ssh-keys' )
110+ . send ( { publicKey } ) ;
111+
112+ expect ( res ) . to . have . status ( 404 ) ;
113+ expect ( res . body ) . to . have . property ( 'error' ) ;
114+ expect ( res . body . error ) . to . include ( 'User not found' ) ;
115+ } ) ;
116+
117+ it ( 'should return 201 when SSH key is added successfully' , async function ( ) {
118+ const publicKey = validPublicKey ;
119+
120+ sinon . stub ( db , 'addPublicKey' ) . resolves ( ) ;
121+
122+ const res = await chai
123+ . request ( authenticatedApp )
124+ . post ( '/users/alice/ssh-keys' )
125+ . send ( { publicKey } ) ;
126+
127+ expect ( res ) . to . have . status ( 201 ) ;
128+ expect ( res . body ) . to . have . property ( 'message' ) ;
129+ expect ( res . body . message ) . to . equal ( 'SSH key added successfully' ) ;
130+ } ) ;
131+
132+ it ( 'should return 400 when public key is missing' , async function ( ) {
133+ const res = await chai . request ( authenticatedApp ) . post ( '/users/alice/ssh-keys' ) . send ( { } ) ;
134+
135+ expect ( res ) . to . have . status ( 400 ) ;
136+ expect ( res . body ) . to . have . property ( 'error' ) ;
137+ expect ( res . body . error ) . to . include ( 'Public key is required' ) ;
138+ } ) ;
139+
140+ it ( 'should return 500 for unexpected errors' , async function ( ) {
141+ const publicKey = validPublicKey ;
142+
143+ sinon . stub ( db , 'addPublicKey' ) . rejects ( new Error ( 'Database connection failed' ) ) ;
144+
145+ const res = await chai
146+ . request ( authenticatedApp )
147+ . post ( '/users/alice/ssh-keys' )
148+ . send ( { publicKey } ) ;
149+
150+ expect ( res ) . to . have . status ( 500 ) ;
151+ expect ( res . body ) . to . have . property ( 'error' ) ;
152+ expect ( res . body . error ) . to . include ( 'Failed to add SSH key' ) ;
153+ } ) ;
154+ } ) ;
67155} ) ;
0 commit comments