@@ -10,11 +10,15 @@ import (
1010 "encoding/json"
1111 "errors"
1212 "fmt"
13+ "net/http"
14+ "net/http/httptest"
15+ "net/url"
1316 "os"
1417 "path/filepath"
1518 "sync"
1619 "testing"
1720
21+ "github.com/nginx/agent/v3/internal/config"
1822 "github.com/nginx/agent/v3/internal/model"
1923
2024 "github.com/nginx/agent/v3/pkg/files"
@@ -1173,3 +1177,175 @@ rQHX6DP4w6IwZY8JB8LS
11731177 })
11741178 }
11751179}
1180+
1181+ func TestFileManagerService_DetermineFileActions_ExternalFile (t * testing.T ) {
1182+ ctx := context .Background ()
1183+ tempDir := t .TempDir ()
1184+ fileName := filepath .Join (tempDir , "external.conf" )
1185+
1186+ modifiedFiles := map [string ]* model.FileCache {
1187+ fileName : {
1188+ File : & mpi.File {
1189+ FileMeta : & mpi.FileMeta {
1190+ Name : fileName ,
1191+ },
1192+ ExternalDataSource : & mpi.ExternalDataSource {Location : "http://example.com/file" },
1193+ },
1194+ },
1195+ }
1196+
1197+ fakeFileServiceClient := & v1fakes.FakeFileServiceClient {}
1198+ fileManagerService := NewFileManagerService (fakeFileServiceClient , types .AgentConfig (), & sync.RWMutex {})
1199+ fileManagerService .agentConfig .AllowedDirectories = []string {tempDir }
1200+
1201+ diff , err := fileManagerService .DetermineFileActions (ctx , map [string ]* mpi.File {}, modifiedFiles )
1202+ require .NoError (t , err )
1203+
1204+ fc , ok := diff [fileName ]
1205+ require .True (t , ok , "expected file to be present in diff" )
1206+ assert .Equal (t , model .ExternalFile , fc .Action )
1207+ }
1208+
1209+ func TestFileManagerService_downloadExternalFiles_Cases (t * testing.T ) {
1210+ type tc struct {
1211+ name string
1212+ handler http.HandlerFunc
1213+ allowedDomains []string
1214+ maxBytes int
1215+ expectError bool
1216+ expectErrContains string
1217+ expectTempFile bool
1218+ expectContent []byte
1219+ expectHeaderETag string
1220+ expectHeaderLastMod string
1221+ }
1222+
1223+ tests := []tc {
1224+ {
1225+ name : "Success" ,
1226+ handler : func (w http.ResponseWriter , r * http.Request ) {
1227+ w .Header ().Set ("ETag" , "test-etag" )
1228+ w .Header ().Set ("Last-Modified" , "Mon, 02 Jan 2006 15:04:05 MST" )
1229+ w .WriteHeader (200 )
1230+ _ , _ = w .Write ([]byte ("external file content" ))
1231+ },
1232+ allowedDomains : nil , // will be set per test from ts
1233+ maxBytes : 0 ,
1234+ expectError : false ,
1235+ expectTempFile : true ,
1236+ expectContent : []byte ("external file content" ),
1237+ expectHeaderETag : "test-etag" ,
1238+ expectHeaderLastMod : "Mon, 02 Jan 2006 15:04:05 MST" ,
1239+ },
1240+ {
1241+ name : "NotModified" ,
1242+ handler : func (w http.ResponseWriter , r * http.Request ) {
1243+ w .WriteHeader (http .StatusNotModified )
1244+ },
1245+ allowedDomains : nil ,
1246+ maxBytes : 0 ,
1247+ expectError : false ,
1248+ expectTempFile : false ,
1249+ expectContent : nil ,
1250+ expectHeaderETag : "" ,
1251+ expectHeaderLastMod : "" ,
1252+ },
1253+ {
1254+ name : "NotAllowedDomain" ,
1255+ handler : func (w http.ResponseWriter , r * http.Request ) {
1256+ w .WriteHeader (200 )
1257+ _ , _ = w .Write ([]byte ("external file content" ))
1258+ },
1259+ allowedDomains : []string {"not-the-host" },
1260+ maxBytes : 0 ,
1261+ expectError : true ,
1262+ expectErrContains : "not in the allowed domains" ,
1263+ expectTempFile : false ,
1264+ },
1265+ {
1266+ name : "NotFound" ,
1267+ handler : func (w http.ResponseWriter , r * http.Request ) {
1268+ w .WriteHeader (http .StatusNotFound )
1269+ },
1270+ allowedDomains : nil ,
1271+ maxBytes : 0 ,
1272+ expectError : true ,
1273+ expectErrContains : "status code 404" ,
1274+ expectTempFile : false ,
1275+ },
1276+ }
1277+
1278+ for _ , test := range tests {
1279+ t .Run (test .name , func (t * testing.T ) {
1280+ ctx := context .Background ()
1281+ tempDir := t .TempDir ()
1282+ fileName := filepath .Join (tempDir , "external.conf" )
1283+
1284+ ts := httptest .NewServer (http .HandlerFunc (test .handler ))
1285+ defer ts .Close ()
1286+
1287+ u , err := url .Parse (ts .URL )
1288+ require .NoError (t , err )
1289+ host := u .Hostname ()
1290+
1291+ fakeFileServiceClient := & v1fakes.FakeFileServiceClient {}
1292+ fileManagerService := NewFileManagerService (fakeFileServiceClient , types .AgentConfig (), & sync.RWMutex {})
1293+
1294+ // If the test provided allowedDomains, use it; otherwise allow this test server's host
1295+ if test .allowedDomains == nil {
1296+ fileManagerService .agentConfig .ExternalDataSource = & config.ExternalDataSource {
1297+ ProxyURL : config.ProxyURL {URL : "" },
1298+ AllowedDomains : []string {host },
1299+ MaxBytes : int64 (test .maxBytes ),
1300+ }
1301+ } else {
1302+ fileManagerService .agentConfig .ExternalDataSource = & config.ExternalDataSource {
1303+ ProxyURL : config.ProxyURL {URL : "" },
1304+ AllowedDomains : test .allowedDomains ,
1305+ MaxBytes : int64 (test .maxBytes ),
1306+ }
1307+ }
1308+
1309+ fileManagerService .fileActions = map [string ]* model.FileCache {
1310+ fileName : {
1311+ File : & mpi.File {
1312+ FileMeta : & mpi.FileMeta {Name : fileName },
1313+ ExternalDataSource : & mpi.ExternalDataSource {Location : ts .URL },
1314+ },
1315+ Action : model .ExternalFile ,
1316+ },
1317+ }
1318+
1319+ err = fileManagerService .downloadUpdatedFilesToTempLocation (ctx )
1320+
1321+ if test .expectError {
1322+ require .Error (t , err )
1323+ if test .expectErrContains != "" {
1324+ assert .Contains (t , err .Error (), test .expectErrContains )
1325+ }
1326+ // ensure no temp file left
1327+ _ , statErr := os .Stat (tempFilePath (fileName ))
1328+ assert .True (t , os .IsNotExist (statErr ))
1329+ return
1330+ }
1331+
1332+ require .NoError (t , err )
1333+
1334+ if test .expectTempFile {
1335+ b , readErr := os .ReadFile (tempFilePath (fileName ))
1336+ require .NoError (t , readErr )
1337+ assert .Equal (t , test .expectContent , b )
1338+
1339+ h , ok := fileManagerService .newExternalFileHeaders [fileName ]
1340+ require .True (t , ok )
1341+ assert .Equal (t , test .expectHeaderETag , h .ETag )
1342+ assert .Equal (t , test .expectHeaderLastMod , h .LastModified )
1343+
1344+ _ = os .Remove (tempFilePath (fileName ))
1345+ } else {
1346+ _ , statErr := os .Stat (tempFilePath (fileName ))
1347+ assert .True (t , os .IsNotExist (statErr ))
1348+ }
1349+ })
1350+ }
1351+ }
0 commit comments