@@ -7,8 +7,12 @@ import express from 'express';
77import { Types } from 'mongoose' ;
88import request from 'supertest' ;
99
10- import { getLoggedInAgent , getServer } from '@/fixtures' ;
10+ import {
11+ getLoggedInAgent as getFixtureLoggedInAgent ,
12+ getServer ,
13+ } from '@/fixtures' ;
1114import { appErrorHandler } from '@/middleware/error' ;
15+ import Connection from '@/models/connection' ;
1216import { Source } from '@/models/source' ;
1317import sourcesRouter from '@/routers/api/sources' ;
1418
@@ -43,6 +47,27 @@ const MOCK_METRIC_SOURCE: Omit<Extract<TSource, { kind: 'metric' }>, 'id'> = {
4347 } ,
4448} ;
4549
50+ const createTestConnection = ( team : Types . ObjectId , id : string ) =>
51+ Connection . create ( {
52+ _id : id ,
53+ team,
54+ name : 'Test Connection' ,
55+ host : 'http://localhost:8123' ,
56+ username : 'default' ,
57+ password : 'password' ,
58+ } ) ;
59+
60+ const getLoggedInAgent = async ( server : ReturnType < typeof getServer > ) => {
61+ const result = await getFixtureLoggedInAgent ( server ) ;
62+
63+ await Promise . all ( [
64+ createTestConnection ( result . team . _id , MOCK_SOURCE . connection ) ,
65+ createTestConnection ( result . team . _id , MOCK_METRIC_SOURCE . connection ) ,
66+ ] ) ;
67+
68+ return result ;
69+ } ;
70+
4671describe ( 'sources router' , ( ) => {
4772 const server = getServer ( ) ;
4873
@@ -103,6 +128,87 @@ describe('sources router', () => {
103128 expect ( sources ) . toHaveLength ( 1 ) ;
104129 } ) ;
105130
131+ describe ( 'connection validation' , ( ) => {
132+ it ( 'POST / - returns 400 for a malformed connection id' , async ( ) => {
133+ const { agent } = await getLoggedInAgent ( server ) ;
134+
135+ await agent
136+ . post ( '/sources' )
137+ . send ( { ...MOCK_SOURCE , connection : 'not-an-object-id' } )
138+ . expect ( 400 ) ;
139+ } ) ;
140+
141+ it ( 'POST / - returns 400 for a nonexistent connection id' , async ( ) => {
142+ const { agent } = await getLoggedInAgent ( server ) ;
143+
144+ await agent
145+ . post ( '/sources' )
146+ . send ( {
147+ ...MOCK_SOURCE ,
148+ connection : new Types . ObjectId ( ) . toString ( ) ,
149+ } )
150+ . expect ( 400 ) ;
151+ } ) ;
152+
153+ it ( 'POST / - returns 400 for another team connection' , async ( ) => {
154+ const { agent } = await getLoggedInAgent ( server ) ;
155+ const otherConnection = await createTestConnection (
156+ new Types . ObjectId ( ) ,
157+ new Types . ObjectId ( ) . toString ( ) ,
158+ ) ;
159+
160+ await agent
161+ . post ( '/sources' )
162+ . send ( {
163+ ...MOCK_SOURCE ,
164+ connection : otherConnection . _id . toString ( ) ,
165+ } )
166+ . expect ( 400 ) ;
167+ } ) ;
168+
169+ it ( 'PUT /:id - rejects an inaccessible connection without changing the source' , async ( ) => {
170+ const { agent, team } = await getLoggedInAgent ( server ) ;
171+ const source = await Source . create ( {
172+ ...MOCK_SOURCE ,
173+ team : team . _id ,
174+ } ) ;
175+ const otherConnection = await createTestConnection (
176+ new Types . ObjectId ( ) ,
177+ new Types . ObjectId ( ) . toString ( ) ,
178+ ) ;
179+
180+ await agent
181+ . put ( `/sources/${ source . _id } ` )
182+ . send ( {
183+ ...MOCK_SOURCE ,
184+ id : source . _id . toString ( ) ,
185+ connection : otherConnection . _id . toString ( ) ,
186+ } )
187+ . expect ( 400 ) ;
188+
189+ const unchanged = await Source . findById ( source . _id ) ;
190+ expect ( unchanged ?. name ) . toBe ( MOCK_SOURCE . name ) ;
191+ expect ( unchanged ?. connection . toString ( ) ) . toBe ( MOCK_SOURCE . connection ) ;
192+ } ) ;
193+
194+ it ( 'PUT /:id - returns 400 for a nonexistent connection id' , async ( ) => {
195+ const { agent, team } = await getLoggedInAgent ( server ) ;
196+ const source = await Source . create ( {
197+ ...MOCK_SOURCE ,
198+ team : team . _id ,
199+ } ) ;
200+
201+ await agent
202+ . put ( `/sources/${ source . _id } ` )
203+ . send ( {
204+ ...MOCK_SOURCE ,
205+ id : source . _id . toString ( ) ,
206+ connection : new Types . ObjectId ( ) . toString ( ) ,
207+ } )
208+ . expect ( 400 ) ;
209+ } ) ;
210+ } ) ;
211+
106212 it ( 'POST / - returns 400 when request body is invalid' , async ( ) => {
107213 const { agent } = await getLoggedInAgent ( server ) ;
108214
@@ -284,7 +390,7 @@ describe('sources router', () => {
284390 const metricSource = await Source . create ( {
285391 kind : SourceKind . Metric ,
286392 name : 'Test Metric Source' ,
287- connection : new Types . ObjectId ( ) . toString ( ) ,
393+ connection : MOCK_METRIC_SOURCE . connection ,
288394 from : {
289395 databaseName : 'test_db' ,
290396 tableName : 'otel_metrics' ,
@@ -346,7 +452,7 @@ describe('sources router', () => {
346452 const metricSource = await Source . create ( {
347453 kind : SourceKind . Metric ,
348454 name : 'Test Metric Source' ,
349- connection : new Types . ObjectId ( ) . toString ( ) ,
455+ connection : MOCK_METRIC_SOURCE . connection ,
350456 from : {
351457 databaseName : 'test_db' ,
352458 tableName : 'otel_metrics' ,
@@ -693,7 +799,7 @@ describe('sources router', () => {
693799 it ( 'successfully updates a legacy Session source when timestampValueExpression is provided' , async ( ) => {
694800 const { agent, team } = await getLoggedInAgent ( server ) ;
695801
696- const connectionId = new Types . ObjectId ( ) ;
802+ const connectionId = new Types . ObjectId ( MOCK_SOURCE . connection ) ;
697803 const result = await Source . collection . insertOne ( {
698804 kind : SourceKind . Session ,
699805 name : 'Legacy Session' ,
@@ -841,6 +947,10 @@ describe('sources router', () => {
841947
842948 it ( 'POST / - creates a source when team id is a string' , async ( ) => {
843949 const app = getLocalAppModeApp ( ) ;
950+ await createTestConnection (
951+ new Types . ObjectId ( '_local_team_' ) ,
952+ MOCK_SOURCE . connection ,
953+ ) ;
844954
845955 const response = await request ( app )
846956 . post ( '/sources' )
@@ -858,6 +968,10 @@ describe('sources router', () => {
858968
859969 it ( 'PUT /:id - updates a source when team id is a string' , async ( ) => {
860970 const app = getLocalAppModeApp ( ) ;
971+ await createTestConnection (
972+ new Types . ObjectId ( '_local_team_' ) ,
973+ MOCK_SOURCE . connection ,
974+ ) ;
861975
862976 const source = await Source . create ( {
863977 ...MOCK_SOURCE ,
@@ -991,7 +1105,7 @@ describe('sources router', () => {
9911105 const traceSource : Omit < Extract < TSource , { kind : 'trace' } > , 'id' > = {
9921106 kind : SourceKind . Trace ,
9931107 name : 'Trace with text index pref' ,
994- connection : new Types . ObjectId ( ) . toString ( ) ,
1108+ connection : MOCK_SOURCE . connection ,
9951109 from : { databaseName : 'test_db' , tableName : 'otel_traces' } ,
9961110 timestampValueExpression : 'Timestamp' ,
9971111 defaultTableSelectExpression : '*' ,
0 commit comments