@@ -6,8 +6,11 @@ import (
66 "errors"
77 "fmt"
88 "os"
9+ "os/exec"
910 "path/filepath"
11+ "runtime"
1012 "sort"
13+ "strings"
1114
1215 "github.com/aptly-dev/aptly/aptly"
1316 "github.com/aptly-dev/aptly/database"
@@ -550,6 +553,165 @@ func (s *PublishedRepoSuite) TestPublishAppStreamAcquireByHash(c *C) {
550553 c .Check (filepath .Join (base , "main/dep11/by-hash/SHA256" ), PathExists )
551554}
552555
556+ // setupSmallTempFS points TMPDIR at a ~1MB filesystem so that Publish's
557+ // temporary index files run out of space mid-write. Follows the DiskFullSuite
558+ // convention: /smallfs is pre-mounted in CI (see docker-unit-test), a loopback
559+ // mount is created when running as root, otherwise the test is skipped.
560+ func (s * PublishedRepoSuite ) setupSmallTempFS (c * C ) func () {
561+ if runtime .GOOS != "linux" {
562+ c .Skip ("disk full tests only run on Linux" )
563+ }
564+
565+ mountPoint := "/smallfs"
566+ mounted := false
567+ if os .Geteuid () == 0 {
568+ mountPoint = filepath .Join (c .MkDir (), "smallfs" )
569+ c .Assert (os .MkdirAll (mountPoint , 0777 ), IsNil )
570+ fsImage := filepath .Join (c .MkDir (), "small.img" )
571+ c .Assert (exec .Command ("dd" , "if=/dev/zero" , "of=" + fsImage , "bs=1M" , "count=1" ).Run (), IsNil )
572+ c .Assert (exec .Command ("mkfs.ext4" , "-F" , fsImage ).Run (), IsNil )
573+ c .Assert (exec .Command ("mount" , "-o" , "loop" , fsImage , mountPoint ).Run (), IsNil )
574+ mounted = true
575+ } else if _ , err := os .Stat (mountPoint ); err != nil {
576+ c .Skip ("/smallfs is not mounted" )
577+ }
578+
579+ // remove leftovers from other tests sharing the mount
580+ entries , err := os .ReadDir (mountPoint )
581+ c .Assert (err , IsNil )
582+ for _ , entry := range entries {
583+ if entry .Name () == "lost+found" {
584+ continue
585+ }
586+ c .Assert (os .RemoveAll (filepath .Join (mountPoint , entry .Name ())), IsNil )
587+ }
588+
589+ oldTMPDIR , hadTMPDIR := os .LookupEnv ("TMPDIR" )
590+ c .Assert (os .Setenv ("TMPDIR" , mountPoint ), IsNil )
591+
592+ return func () {
593+ if hadTMPDIR {
594+ _ = os .Setenv ("TMPDIR" , oldTMPDIR )
595+ } else {
596+ _ = os .Unsetenv ("TMPDIR" )
597+ }
598+ if mounted {
599+ _ = exec .Command ("umount" , mountPoint ).Run ()
600+ }
601+ }
602+ }
603+
604+ func (s * PublishedRepoSuite ) TestPublishSkelFiles (c * C ) {
605+ skelDir := c .MkDir ()
606+ dir := filepath .Join (skelDir , "ppa" , "dists" , "squeeze" , "main" )
607+ c .Assert (os .MkdirAll (filepath .Join (dir , "extra" ), 0755 ), IsNil )
608+ c .Assert (os .WriteFile (filepath .Join (dir , "top.txt" ), []byte ("top-level skel file\n " ), 0644 ), IsNil )
609+ c .Assert (os .WriteFile (filepath .Join (dir , "extra" , "metadata.json" ), []byte ("{\" nested\" : true}\n " ), 0644 ), IsNil )
610+
611+ err := s .repo .Publish (s .packagePool , s .provider , s .factory , & NullSigner {}, nil , false , skelDir )
612+ c .Assert (err , IsNil )
613+
614+ base := filepath .Join (s .publishedStorage .PublicPath (), "ppa/dists/squeeze/main" )
615+
616+ published , err := os .ReadFile (filepath .Join (base , "top.txt" ))
617+ c .Assert (err , IsNil )
618+ c .Check (string (published ), Equals , "top-level skel file\n " )
619+
620+ published , err = os .ReadFile (filepath .Join (base , "extra" , "metadata.json" ))
621+ c .Assert (err , IsNil )
622+ c .Check (string (published ), Equals , "{\" nested\" : true}\n " )
623+
624+ // Release file should reference skel files
625+ rf , err := os .Open (filepath .Join (s .publishedStorage .PublicPath (), "ppa/dists/squeeze/Release" ))
626+ c .Assert (err , IsNil )
627+ defer func () { _ = rf .Close () }()
628+
629+ cfr := NewControlFileReader (rf , true , false )
630+ st , err := cfr .ReadStanza ()
631+ c .Assert (err , IsNil )
632+
633+ c .Check (st ["SHA256" ], Matches , "(?s).*main/top\\ .txt.*" )
634+ c .Check (st ["SHA256" ], Matches , "(?s).*main/extra/metadata\\ .json.*" )
635+ }
636+
637+ func (s * PublishedRepoSuite ) TestPublishSkelFilesWalkError (c * C ) {
638+ if runtime .GOOS == "windows" {
639+ c .Skip ("a file in the middle of a path is reported as not-exist on Windows" )
640+ }
641+
642+ // "dists" is a regular file, so walking skelDir/ppa/dists/squeeze/main
643+ // fails with ENOTDIR, which is not swallowed as a not-exist error
644+ skelDir := c .MkDir ()
645+ c .Assert (os .MkdirAll (filepath .Join (skelDir , "ppa" ), 0755 ), IsNil )
646+ c .Assert (os .WriteFile (filepath .Join (skelDir , "ppa" , "dists" ), []byte ("not a directory" ), 0644 ), IsNil )
647+
648+ err := s .repo .Publish (s .packagePool , s .provider , s .factory , & NullSigner {}, nil , false , skelDir )
649+ c .Assert (err , ErrorMatches , "unable to get skeleton files: .*" )
650+ }
651+
652+ func (s * PublishedRepoSuite ) TestPublishSkelFilesIndexError (c * C ) {
653+ // each name stays within NAME_MAX, but BufWriter flattens the relative
654+ // path into a single temporary file name that exceeds it
655+ skelDir := c .MkDir ()
656+ dir := filepath .Join (skelDir , "ppa" , "dists" , "squeeze" , "main" , strings .Repeat ("a" , 200 ))
657+ c .Assert (os .MkdirAll (dir , 0755 ), IsNil )
658+ c .Assert (os .WriteFile (filepath .Join (dir , strings .Repeat ("b" , 200 )), []byte ("skel content" ), 0644 ), IsNil )
659+
660+ err := s .repo .Publish (s .packagePool , s .provider , s .factory , & NullSigner {}, nil , false , skelDir )
661+ c .Assert (err , ErrorMatches , "unable to generate skeleton index: .*" )
662+ }
663+
664+ func (s * PublishedRepoSuite ) TestPublishSkelFilesOpenError (c * C ) {
665+ if runtime .GOOS == "windows" || os .Geteuid () == 0 {
666+ c .Skip ("requires POSIX permissions and a non-root user" )
667+ }
668+
669+ skelDir := c .MkDir ()
670+ dir := filepath .Join (skelDir , "ppa" , "dists" , "squeeze" , "main" )
671+ c .Assert (os .MkdirAll (dir , 0755 ), IsNil )
672+ skelFile := filepath .Join (dir , "InRelease" )
673+ c .Assert (os .WriteFile (skelFile , []byte ("skel content" ), 0644 ), IsNil )
674+ c .Assert (os .Chmod (skelFile , 0 ), IsNil )
675+
676+ err := s .repo .Publish (s .packagePool , s .provider , s .factory , & NullSigner {}, nil , false , skelDir )
677+ c .Assert (err , ErrorMatches , "unable to read skeleton file: .*" )
678+ }
679+
680+ func (s * PublishedRepoSuite ) TestPublishSkelFilesWriteError (c * C ) {
681+ cleanup := s .setupSmallTempFS (c )
682+ defer cleanup ()
683+
684+ skelDir := c .MkDir ()
685+ dir := filepath .Join (skelDir , "ppa" , "dists" , "squeeze" , "main" )
686+ c .Assert (os .MkdirAll (dir , 0755 ), IsNil )
687+ c .Assert (os .WriteFile (filepath .Join (dir , "Contents-huge" ), bytes .Repeat ([]byte {'x' }, 2 * 1024 * 1024 ), 0644 ), IsNil )
688+
689+ err := s .repo .Publish (s .packagePool , s .provider , s .factory , & NullSigner {}, nil , false , skelDir )
690+ c .Assert (err , ErrorMatches , "unable to write skeleton file: .*" )
691+ }
692+
693+ func (s * PublishedRepoSuite ) TestPublishAppStreamIndexError (c * C ) {
694+ // flattened temporary file name for the index exceeds NAME_MAX
695+ s .snapshot .AppStreamFiles = map [string ]string {
696+ "main/" + strings .Repeat ("a" , 200 ) + "/" + strings .Repeat ("b" , 200 ): s .importAppStreamFile (c , "Components-amd64.yml.gz" , []byte ("DEP-11 content\n " )),
697+ }
698+
699+ err := s .repo .Publish (s .packagePool , s .provider , s .factory , & NullSigner {}, nil , false , "" )
700+ c .Assert (err , ErrorMatches , "unable to generate AppStream index: .*" )
701+ }
702+
703+ func (s * PublishedRepoSuite ) TestPublishAppStreamWriteError (c * C ) {
704+ cleanup := s .setupSmallTempFS (c )
705+ defer cleanup ()
706+
707+ s .snapshot .AppStreamFiles = map [string ]string {
708+ "main/dep11/Components-amd64.yml.gz" : s .importAppStreamFile (c , "Components-amd64.yml.gz" , bytes .Repeat ([]byte {'x' }, 2 * 1024 * 1024 )),
709+ }
710+
711+ err := s .repo .Publish (s .packagePool , s .provider , s .factory , & NullSigner {}, nil , false , "" )
712+ c .Assert (err , ErrorMatches , "unable to write AppStream file: .*" )
713+ }
714+
553715func (s * PublishedRepoSuite ) TestPublishNoSigner (c * C ) {
554716 err := s .repo .Publish (s .packagePool , s .provider , s .factory , nil , nil , false , "" )
555717 c .Assert (err , IsNil )
0 commit comments