55package upgrade
66
77import (
8- "bytes"
98 "context"
109 "crypto/tls"
1110 "fmt"
1211 "io"
1312 "net/http"
14- "net/http/httptest"
1513 "net/url"
1614 "os"
1715 "path/filepath"
1816 "runtime"
19- "strings"
2017 "sync"
2118 "testing"
2219 "time"
@@ -31,9 +28,7 @@ import (
3128 "github.com/elastic/elastic-agent-libs/transport/tlscommon"
3229 "github.com/elastic/elastic-agent/internal/pkg/agent/application/paths"
3330 "github.com/elastic/elastic-agent/internal/pkg/agent/application/upgrade/artifact"
34- downloadErrors "github.com/elastic/elastic-agent/internal/pkg/agent/application/upgrade/artifact/download/errors"
3531 upgradeErrors "github.com/elastic/elastic-agent/internal/pkg/agent/application/upgrade/artifact/download/errors"
36- "github.com/elastic/elastic-agent/internal/pkg/agent/application/upgrade/common"
3732 "github.com/elastic/elastic-agent/internal/pkg/agent/application/upgrade/details"
3833 "github.com/elastic/elastic-agent/internal/pkg/agent/errors"
3934 "github.com/elastic/elastic-agent/internal/pkg/config"
@@ -1316,59 +1311,94 @@ func (m *mockArtifactDownloader) withFleetServerURI(fleetServerURI string) {
13161311 m .fleetServerURI = fleetServerURI
13171312}
13181313
1319- type mockSender struct {}
1320-
1321- func (m * mockSender ) Send (ctx context.Context , method , path string , params url.Values , headers http.Header , body io.Reader ) (* http.Response , error ) {
1322- return nil , nil
1314+ type mockUnpacker struct {
1315+ returnPackageMetadata packageMetadata
1316+ returnPackageMetadataError error
1317+ returnUnpackResult UnpackResult
1318+ returnUnpackError error
13231319}
13241320
1325- func (m * mockSender ) URI () string {
1326- return "mockURI"
1321+ func (m * mockUnpacker ) getPackageMetadata ( archivePath string ) ( packageMetadata , error ) {
1322+ return m . returnPackageMetadata , m . returnPackageMetadataError
13271323}
13281324
1329- func TestSetClient (t * testing.T ) {
1330- log , _ := loggertest .New ("test" )
1331- upgrader := & Upgrader {
1332- log : log ,
1333- artifactDownloader : & mockArtifactDownloader {},
1334- }
1335-
1336- upgrader .SetClient (& mockSender {})
1337- require .Equal (t , "mockURI" , upgrader .artifactDownloader .(* mockArtifactDownloader ).fleetServerURI )
1325+ func (m * mockUnpacker ) unpack (version , archivePath , dataDir string , flavor string ) (UnpackResult , error ) {
1326+ return m .returnUnpackResult , m .returnUnpackError
13381327}
13391328
13401329func TestUpgradeErrorHandling (t * testing.T ) {
13411330 log , _ := loggertest .New ("test" )
13421331 testError := errors .New ("test error" )
1332+ type upgraderMocker func (upgrader * Upgrader )
13431333
13441334 type testCase struct {
13451335 isDiskSpaceErrorResult bool
13461336 expectedError error
1337+ upgraderMocker upgraderMocker
13471338 }
13481339
13491340 testCases := map [string ]testCase {
13501341 "should return error if downloadArtifact fails" : {
13511342 isDiskSpaceErrorResult : false ,
13521343 expectedError : testError ,
1344+ upgraderMocker : func (upgrader * Upgrader ) {
1345+ upgrader .artifactDownloader = & mockArtifactDownloader {
1346+ returnError : testError ,
1347+ }
1348+ },
1349+ },
1350+ "should return error if getPackageMetadata fails" : {
1351+ isDiskSpaceErrorResult : false ,
1352+ expectedError : testError ,
1353+ upgraderMocker : func (upgrader * Upgrader ) {
1354+ upgrader .artifactDownloader = & mockArtifactDownloader {}
1355+ upgrader .unpacker = & mockUnpacker {
1356+ returnPackageMetadataError : testError ,
1357+ }
1358+ },
1359+ },
1360+ "should return error if unpack fails" : {
1361+ isDiskSpaceErrorResult : false ,
1362+ expectedError : testError ,
1363+ upgraderMocker : func (upgrader * Upgrader ) {
1364+ upgrader .artifactDownloader = & mockArtifactDownloader {}
1365+ upgrader .extractAgentVersion = func (metadata packageMetadata , upgradeVersion string ) agentVersion {
1366+ return agentVersion {
1367+ version : upgradeVersion ,
1368+ snapshot : false ,
1369+ hash : metadata .hash ,
1370+ }
1371+ }
1372+ upgrader .unpacker = & mockUnpacker {
1373+ returnPackageMetadata : packageMetadata {
1374+ manifest : & v1.PackageManifest {},
1375+ hash : "hash" ,
1376+ },
1377+ returnUnpackError : testError ,
1378+ }
1379+ },
13531380 },
13541381 "should add disk space error to the error chain if downloadArtifact fails with disk space error" : {
13551382 isDiskSpaceErrorResult : true ,
13561383 expectedError : upgradeErrors .ErrInsufficientDiskSpace ,
1384+ upgraderMocker : func (upgrader * Upgrader ) {
1385+ upgrader .artifactDownloader = & mockArtifactDownloader {
1386+ returnError : upgradeErrors .ErrInsufficientDiskSpace ,
1387+ }
1388+ },
13571389 },
13581390 }
13591391
13601392 mockAgentInfo := info .NewAgent (t )
13611393 mockAgentInfo .On ("Version" ).Return ("9.0.0" )
13621394
1363- upgrader , err := NewUpgrader (log , & artifact.Config {}, mockAgentInfo )
1364- require .NoError (t , err )
1365-
1366- upgrader .artifactDownloader = & mockArtifactDownloader {
1367- returnError : testError ,
1368- }
1369-
13701395 for name , tc := range testCases {
13711396 t .Run (name , func (t * testing.T ) {
1397+ upgrader , err := NewUpgrader (log , & artifact.Config {}, mockAgentInfo )
1398+ require .NoError (t , err )
1399+
1400+ tc .upgraderMocker (upgrader )
1401+
13721402 upgrader .isDiskSpaceErrorFunc = func (err error ) bool {
13731403 return tc .isDiskSpaceErrorResult
13741404 }
@@ -1379,130 +1409,22 @@ func TestUpgradeErrorHandling(t *testing.T) {
13791409 }
13801410}
13811411
1382- func TestUpgradeUnpackErrors (t * testing.T ) {
1383- log , _ := loggertest .New ("test" )
1384-
1385- targetVersion := agtversion .NewParsedSemVer (3 , 4 , 5 , "SNAPSHOT" , "" )
1386- targetArtifactName , targetArchiveFiles := buildArchiveFiles (t , archiveFilesWithMoreComponents , targetVersion , "ghijkl" )
1387-
1388- // Get the content of the component file to be used in copy function
1389- // assertions. It will be used to make sure the error gets triggered in the
1390- // copy call in the unpacker and not the downloader.
1391- targetArchiveComponentsFileContent := ""
1392- for _ , file := range targetArchiveFiles {
1393- if file .fType == REGULAR {
1394- dir := filepath .Dir (file .path )
1395- if strings .HasSuffix (dir , "components" ) {
1396- targetArchiveComponentsFileContent = file .content
1397- break
1398- }
1399- }
1400- }
1412+ type mockSender struct {}
14011413
1402- // dir name of the versioned home
1403- // used to calculate component paths
1404- newVersionedDirName := "elastic-agent-3.4.5-SNAPSHOT-ghijkl"
1414+ func ( m * mockSender ) Send ( ctx context. Context , method , path string , params url. Values , headers http. Header , body io. Reader ) ( * http. Response , error ) {
1415+ return nil , nil
1416+ }
14051417
1406- mockAgentInfo := info .NewAgent (t )
1407- mockAgentInfo .On ("Version" ).Return (targetVersion .String ())
1408-
1409- upgradeDetails := details .NewDetails (targetVersion .String (), details .StateRequested , "test" )
1410-
1411- mockStdlibFuncs := []common.MockStdLibFuncName {common .CopyFuncName , common .OpenFileFuncName , common .MkdirAllFuncName }
1412-
1413- testCases := map [string ]struct {
1414- mockStdlibFunc common.MockStdLibFuncName
1415- mockReturnedError error
1416- expectedError error
1417- }{}
1418-
1419- for _ , mockStdlibFunc := range mockStdlibFuncs {
1420- for _ , te := range downloadErrors .OS_DiskSpaceErrors {
1421- testCases [fmt .Sprintf ("unpack_should_return_error_if_unpack_%s_fails: %v" , mockStdlibFunc , te )] = struct {
1422- mockStdlibFunc common.MockStdLibFuncName
1423- mockReturnedError error
1424- expectedError error
1425- }{
1426- mockStdlibFunc : mockStdlibFunc ,
1427- mockReturnedError : te ,
1428- expectedError : downloadErrors .ErrInsufficientDiskSpace ,
1429- }
1430- }
1418+ func (m * mockSender ) URI () string {
1419+ return "mockURI"
1420+ }
1421+ func TestSetClient (t * testing.T ) {
1422+ log , _ := loggertest .New ("test" )
1423+ upgrader := & Upgrader {
1424+ log : log ,
1425+ artifactDownloader : & mockArtifactDownloader {},
14311426 }
14321427
1433- for name , tc := range testCases {
1434- t .Run (name , func (t * testing.T ) {
1435- tempDir := t .TempDir ()
1436- paths .SetTop (tempDir )
1437- paths .SetDownloads (filepath .Join (tempDir , "downloads" ))
1438-
1439- targetArchive , err := createArchive (t , targetArtifactName , targetArchiveFiles )
1440- require .NoError (t , err )
1441-
1442- // Used to assert that the mkdirAll error is triggered in the
1443- // unpacker and not the downloader
1444- newComponentsDir := filepath .Join (paths .Data (), newVersionedDirName , "components" )
1445- // Used to assert that the openFile error is triggered in the
1446- // unpacker and not the downloader
1447- newComponentsFile := filepath .Join (newComponentsDir , "comp1" )
1448-
1449- t .Logf ("Created archive: %s" , targetArchive )
1450-
1451- server := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
1452- http .ServeFile (w , r , targetArchive )
1453- }))
1454- t .Cleanup (server .Close )
1455-
1456- config := artifact.Config {
1457- TargetDirectory : paths .Downloads (),
1458- SourceURI : server .URL ,
1459- RetrySleepInitDuration : 1 * time .Second ,
1460- HTTPTransportSettings : httpcommon.HTTPTransportSettings {
1461- Timeout : 1 * time .Second ,
1462- },
1463- }
1464-
1465- stdlibMocker := common .PrepareStdLibMocks (common.StdLibMocks {
1466- CopyMock : func (dst io.Writer , src io.Reader ) (int64 , error ) {
1467- // If the content is not the same as the target archive components file content,
1468- // write the content to the destination. This is to make
1469- // sure that the error is triggered in unpacker and not in downloader
1470- buf , err := io .ReadAll (src )
1471- require .NoError (t , err )
1472- if ! bytes .Equal (buf , []byte (targetArchiveComponentsFileContent )) {
1473- return io .Copy (dst , bytes .NewReader (buf ))
1474- }
1475-
1476- return 0 , tc .mockReturnedError
1477- },
1478- OpenFileMock : func (name string , flag int , perm os.FileMode ) (* os.File , error ) {
1479- // Make sure that the openFile error is triggered in the
1480- // unpacker and not the downloader
1481- if name != newComponentsFile {
1482- return os .OpenFile (name , flag , perm )
1483- }
1484-
1485- return nil , tc .mockReturnedError
1486- },
1487- MkdirAllMock : func (path string , perm os.FileMode ) error {
1488- // Make sure that the mkdirAll error is triggered in the
1489- // unpacker and not the downloader
1490- if path != newComponentsDir {
1491- return os .MkdirAll (path , perm )
1492- }
1493-
1494- return tc .mockReturnedError
1495- },
1496- })
1497-
1498- stdlibMocker (t , tc .mockStdlibFunc )
1499-
1500- upgrader , err := NewUpgrader (log , & config , mockAgentInfo )
1501- require .NoError (t , err )
1502-
1503- _ , err = upgrader .Upgrade (context .Background (), targetVersion .String (), server .URL , nil , upgradeDetails , true , true )
1504- require .ErrorIs (t , err , tc .expectedError , "expected error mismatch" )
1505- require .Equal (t , upgradeDetails .State , details .StateExtracting )
1506- })
1507- }
1428+ upgrader .SetClient (& mockSender {})
1429+ require .Equal (t , "mockURI" , upgrader .artifactDownloader .(* mockArtifactDownloader ).fleetServerURI )
15081430}
0 commit comments