99from unittest .mock import patch
1010import asyncio
1111import base64
12+ import gzip
1213import http .server
14+ import posixpath
1315import os , os .path
1416import socketserver
1517import stat
2325from bob .archive import DummyArchive , HttpArchive , getArchiver
2426from bob .errors import BuildError
2527from bob .utils import runInEventLoop , getProcessPoolExecutor
28+ from bob .webdav import HTTPException
2629
2730DOWNLOAD_ARITFACT = b'\x00 ' * 20
2831NOT_EXISTS_ARTIFACT = b'\x01 ' * 20
2932WRONG_VERSION_ARTIFACT = b'\x02 ' * 20
3033ERROR_UPLOAD_ARTIFACT = b'\x03 ' * 20
3134ERROR_DOWNLOAD_ARTIFACT = b'\x04 ' * 20
3235BROKEN_ARTIFACT = b'\xba \xdc \x0f \xfe ' * 5
36+ VALID_ARTIFACT = b'\x05 ' * 20
37+ EMPTY_AUDIT = '{"artifact":{"variant-id":"1","build-id":"1","artifact-id":"1","result-hash":"1","meta":"1","build":"1","dependencies":{}}, "references":[]}'
3338
3439UPLOAD1_ARTIFACT = b'\x10 ' * 20
3540UPLOAD2_ARTIFACT = b'\x11 ' * 20
@@ -63,17 +68,23 @@ def run(coro):
6368
6469class Base :
6570
66- def __createArtifact (self , bid , version = "1" ):
71+ def _createArtifact (self , bid , version = "1" , valid_data = False ):
6772 bid = hexlify (bid ).decode ("ascii" )
6873 name = os .path .join (self .repo .name , bid [0 :2 ], bid [2 :4 ], bid [4 :] + "-1.tgz" )
6974 os .makedirs (os .path .dirname (name ), exist_ok = True )
70- return self .__createArtifactByName (name , version )
75+ return self .__createArtifactByName (name , version , valid_data )
7176
72- def __createArtifactByName (self , name , version = "1" ):
77+ def __createArtifactByName (self , name , version = "1" , valid_data = False ):
7378 pax = { 'bob-archive-vsn' : version }
7479 with tarfile .open (name , "w|gz" , format = tarfile .PAX_FORMAT , pax_headers = pax ) as tar :
7580 with NamedTemporaryFile () as audit :
76- audit .write (b'AUDIT' )
81+ if valid_data :
82+ # add valid empty audit file
83+ gzf = gzip .GzipFile (mode = 'wb' , fileobj = audit )
84+ gzf .write (EMPTY_AUDIT .encode ('utf-8' ))
85+ gzf .close ()
86+ else :
87+ audit .write (b'AUDIT' )
7788 audit .seek (0 )
7889 tar .addfile (tar .gettarinfo (arcname = "meta/audit.json.gz" , fileobj = audit ), audit )
7990 with TemporaryDirectory () as content :
@@ -83,7 +94,7 @@ def __createArtifactByName(self, name, version="1"):
8394
8495 return name
8596
86- def __createBuildId (self , bid ):
97+ def _createBuildId (self , bid ):
8798 bid = hexlify (bid ).decode ("ascii" )
8899 name = os .path .join (self .repo .name , bid [0 :2 ], bid [2 :4 ], bid [4 :] + "-1.buildid" )
89100 os .makedirs (os .path .dirname (name ), exist_ok = True )
@@ -94,12 +105,6 @@ def __createBuildId(self, bid):
94105 def setUp (self ):
95106 # create repo
96107 self .repo = TemporaryDirectory ()
97-
98- # add artifacts
99- self .dummyFileName = self .__createArtifact (DOWNLOAD_ARITFACT )
100- self .__createArtifact (WRONG_VERSION_ARTIFACT , "0" )
101- self .__createBuildId (DOWNLOAD_ARITFACT )
102-
103108 self .executor = getProcessPoolExecutor ()
104109
105110 def tearDown (self ):
@@ -172,6 +177,10 @@ def __getSingleArchiveInstance(self, spec):
172177 def setUp (self ):
173178 super ().setUp ()
174179
180+ # add artifacts
181+ self .dummyFileName = self ._createArtifact (DOWNLOAD_ARITFACT )
182+ self ._createArtifact (WRONG_VERSION_ARTIFACT , "0" )
183+ self ._createBuildId (DOWNLOAD_ARITFACT )
175184 # create ERROR_DOWNLOAD_ARTIFACT that is there but cannot be opened
176185 bid = hexlify (ERROR_DOWNLOAD_ARTIFACT ).decode ("ascii" )
177186 os .makedirs (os .path .join (self .repo .name , bid [0 :2 ], bid [2 :4 ], bid [4 :] + "-1.tgz" ), exist_ok = True )
@@ -682,6 +691,7 @@ class TestHttpArchiveRetries(Base, TestCase):
682691
683692 def setUp (self ):
684693 super ().setUp ()
694+ self .VALID_FILE = self ._createArtifact (VALID_ARTIFACT , valid_data = True )
685695 self .spec = {'backend' : 'http' , 'name' : 'http-archive' , 'flags' : ['download' , 'upload' , 'managed' ]}
686696
687697 def _getHttpArchiveInstance (self , port ):
@@ -698,7 +708,7 @@ def _testRetries(self, r):
698708 with TemporaryDirectory () as tmp :
699709 audit = os .path .join (tmp , "audit.json.gz" )
700710 content = os .path .join (tmp , "workspace" )
701- self .assertTrue (run (archive .downloadPackage (DummyStep (), DOWNLOAD_ARITFACT , audit , content ,
711+ self .assertTrue (run (archive .downloadPackage (DummyStep (), VALID_ARTIFACT , audit , content ,
702712 executor = self .executor )))
703713 # server fails one more time than retries in archive sepc -> fail
704714 with HttpServerMock (repoPath = self .repo .name , retries = r + 1 ) as srv :
@@ -707,7 +717,7 @@ def _testRetries(self, r):
707717 with TemporaryDirectory () as tmp :
708718 audit = os .path .join (tmp , "audit.json.gz" )
709719 content = os .path .join (tmp , "workspace" )
710- self .assertFalse (run (archive .downloadPackage (DummyStep (), DOWNLOAD_ARITFACT , audit , content ,
720+ self .assertFalse (run (archive .downloadPackage (DummyStep (), VALID_ARTIFACT , audit , content ,
711721 executor = self .executor )))
712722
713723 def testRetriesWithNoRetries (self ):
@@ -718,3 +728,53 @@ def testRetriesWithOneRetry(self):
718728
719729 def testRetriesWithMultipleRetries (self ):
720730 self ._testRetries (5 )
731+
732+ def testRetriesList (self ):
733+ self .spec ['retries' ] = 1
734+ with HttpServerMock (repoPath = self .repo .name , retries = 1 ) as srv :
735+ archive = self ._getHttpArchiveInstance (srv .port )
736+ self .assertIsNotNone (archive ._listDir ('/' ))
737+ with HttpServerMock (repoPath = self .repo .name , retries = 2 ) as srv :
738+ archive = self ._getHttpArchiveInstance (srv .port )
739+ with self .assertRaises (HTTPException ):
740+ archive ._listDir ('/' )
741+
742+ def testRetriesStat (self ):
743+ bid = hexlify (VALID_ARTIFACT ).decode ("ascii" )
744+ filepath = posixpath .join (bid [0 :2 ], bid [2 :4 ], bid [4 :] + "-1.tgz" )
745+ self .spec ['retries' ] = 1
746+ with HttpServerMock (repoPath = self .repo .name , retries = 1 ) as srv :
747+ archive = self ._getHttpArchiveInstance (srv .port )
748+ self .assertIsNotNone (archive ._stat (filepath ))
749+ with HttpServerMock (repoPath = self .repo .name , retries = 2 ) as srv :
750+ archive = self ._getHttpArchiveInstance (srv .port )
751+ with self .assertRaises (HTTPException ):
752+ archive ._stat (filepath )
753+
754+ def testRetriesDelete (self ):
755+ filename = 'test'
756+ filepath = os .path .join (self .repo .name , filename )
757+ with open (filepath , 'w' ) as f :
758+ f .write ('test' )
759+ self .spec ['retries' ] = 1
760+ with HttpServerMock (repoPath = self .repo .name , retries = 1 ) as srv :
761+ archive = self ._getHttpArchiveInstance (srv .port )
762+ self .assertIsNone (archive ._delete (filename ))
763+ with open (filepath , 'w' ) as f :
764+ f .write ('test' )
765+ with HttpServerMock (repoPath = self .repo .name , retries = 2 ) as srv :
766+ archive = self ._getHttpArchiveInstance (srv .port )
767+ with self .assertRaises (HTTPException ):
768+ archive ._delete (filename )
769+
770+ def testRetriesAudit (self ):
771+ bid = hexlify (VALID_ARTIFACT ).decode ("ascii" )
772+ filepath = posixpath .join (bid [0 :2 ], bid [2 :4 ], bid [4 :] + "-1.tgz" )
773+ self .spec ['retries' ] = 1
774+ with HttpServerMock (repoPath = self .repo .name , retries = 1 ) as srv :
775+ archive = self ._getHttpArchiveInstance (srv .port )
776+ self .assertIsNotNone (archive ._getAudit (filepath ))
777+ with HttpServerMock (repoPath = self .repo .name , retries = 2 ) as srv :
778+ archive = self ._getHttpArchiveInstance (srv .port )
779+ with self .assertRaises (HTTPException ):
780+ archive ._getAudit (filepath )
0 commit comments