@@ -24,6 +24,7 @@ import (
24
24
"fmt"
25
25
"io"
26
26
"os"
27
+ "path"
27
28
"path/filepath"
28
29
"reflect"
29
30
"strconv"
@@ -2844,6 +2845,199 @@ func TestStore_UntagErrorPath(t *testing.T) {
2844
2845
}
2845
2846
}
2846
2847
2848
+ func TestStore_GC (t * testing.T ) {
2849
+ tempDir := t .TempDir ()
2850
+ s , err := New (tempDir )
2851
+ if err != nil {
2852
+ t .Fatal ("New() error =" , err )
2853
+ }
2854
+ ctx := context .Background ()
2855
+
2856
+ // generate test content
2857
+ var blobs [][]byte
2858
+ var descs []ocispec.Descriptor
2859
+ appendBlob := func (mediaType string , blob []byte ) {
2860
+ blobs = append (blobs , blob )
2861
+ descs = append (descs , ocispec.Descriptor {
2862
+ MediaType : mediaType ,
2863
+ Digest : digest .FromBytes (blob ),
2864
+ Size : int64 (len (blob )),
2865
+ })
2866
+ }
2867
+ generateManifest := func (config ocispec.Descriptor , subject * ocispec.Descriptor , layers ... ocispec.Descriptor ) {
2868
+ manifest := ocispec.Manifest {
2869
+ Config : config ,
2870
+ Subject : subject ,
2871
+ Layers : layers ,
2872
+ }
2873
+ manifestJSON , err := json .Marshal (manifest )
2874
+ if err != nil {
2875
+ t .Fatal (err )
2876
+ }
2877
+ appendBlob (ocispec .MediaTypeImageManifest , manifestJSON )
2878
+ }
2879
+ generateImageIndex := func (manifests ... ocispec.Descriptor ) {
2880
+ index := ocispec.Index {
2881
+ Manifests : manifests ,
2882
+ }
2883
+ indexJSON , err := json .Marshal (index )
2884
+ if err != nil {
2885
+ t .Fatal (err )
2886
+ }
2887
+ appendBlob (ocispec .MediaTypeImageIndex , indexJSON )
2888
+ }
2889
+ generateArtifactManifest := func (blobs ... ocispec.Descriptor ) {
2890
+ var manifest spec.Artifact
2891
+ manifest .Blobs = append (manifest .Blobs , blobs ... )
2892
+ manifestJSON , err := json .Marshal (manifest )
2893
+ if err != nil {
2894
+ t .Fatal (err )
2895
+ }
2896
+ appendBlob (spec .MediaTypeArtifactManifest , manifestJSON )
2897
+ }
2898
+
2899
+ appendBlob (ocispec .MediaTypeImageConfig , []byte ("config" )) // Blob 0
2900
+ appendBlob (ocispec .MediaTypeImageLayer , []byte ("blob" )) // Blob 1
2901
+ appendBlob (ocispec .MediaTypeImageLayer , []byte ("dangling layer" )) // Blob 2, dangling layer
2902
+ generateManifest (descs [0 ], nil , descs [1 ]) // Blob 3, valid manifest
2903
+ generateManifest (descs [0 ], & descs [3 ], descs [1 ]) // Blob 4, referrer of a valid manifest, not in index.json, should be cleaned with current implementation
2904
+ appendBlob (ocispec .MediaTypeImageLayer , []byte ("dangling layer 2" )) // Blob 5, dangling layer
2905
+ generateArtifactManifest (descs [4 ]) // blob 6, dangling artifact
2906
+ generateManifest (descs [0 ], & descs [5 ], descs [1 ]) // Blob 7, referrer of a dangling manifest
2907
+ appendBlob (ocispec .MediaTypeImageLayer , []byte ("dangling layer 3" )) // Blob 8, dangling layer
2908
+ generateArtifactManifest (descs [6 ]) // blob 9, dangling artifact
2909
+ generateImageIndex (descs [7 ], descs [5 ]) // blob 10, dangling image index
2910
+ appendBlob (ocispec .MediaTypeImageLayer , []byte ("garbage layer 1" )) // Blob 11, garbage layer 1
2911
+ generateManifest (descs [0 ], nil , descs [4 ]) // Blob 12, garbage manifest 1
2912
+ appendBlob (ocispec .MediaTypeImageConfig , []byte ("garbage config" )) // Blob 13, garbage config
2913
+ appendBlob (ocispec .MediaTypeImageLayer , []byte ("garbage layer 2" )) // Blob 14, garbage layer 2
2914
+ generateManifest (descs [6 ], nil , descs [7 ]) // Blob 15, garbage manifest 2
2915
+ generateManifest (descs [0 ], & descs [13 ], descs [1 ]) // Blob 16, referrer of a garbage manifest
2916
+
2917
+ // push blobs 0 - blobs 10 into s
2918
+ for i := 0 ; i <= 10 ; i ++ {
2919
+ err := s .Push (ctx , descs [i ], bytes .NewReader (blobs [i ]))
2920
+ if err != nil {
2921
+ t .Errorf ("failed to push test content to src: %d: %v" , i , err )
2922
+ }
2923
+ }
2924
+
2925
+ // remove blobs 4 - blobs 10 from index.json
2926
+ for i := 4 ; i <= 10 ; i ++ {
2927
+ s .tagResolver .Untag (string (descs [i ].Digest ))
2928
+ }
2929
+ s .SaveIndex ()
2930
+
2931
+ // push blobs 11 - blobs 16 into s.storage, making them garbage as their metadata
2932
+ // doesn't exist in s
2933
+ for i := 11 ; i < len (blobs ); i ++ {
2934
+ err := s .storage .Push (ctx , descs [i ], bytes .NewReader (blobs [i ]))
2935
+ if err != nil {
2936
+ t .Errorf ("failed to push test content to src: %d: %v" , i , err )
2937
+ }
2938
+ }
2939
+
2940
+ // confirm that all the blobs are in the storage
2941
+ for i := 11 ; i < len (blobs ); i ++ {
2942
+ exists , err := s .Exists (ctx , descs [i ])
2943
+ if err != nil {
2944
+ t .Fatal (err )
2945
+ }
2946
+ if ! exists {
2947
+ t .Fatalf ("descs[%d] should exist" , i )
2948
+ }
2949
+ }
2950
+
2951
+ // perform GC
2952
+ if err = s .GC (ctx ); err != nil {
2953
+ t .Fatal (err )
2954
+ }
2955
+
2956
+ // verify existence
2957
+ wantExistence := []bool {true , true , false , true , false , false , false , false , false , false , false , false , false , false , false , false , false }
2958
+ for i , wantValue := range wantExistence {
2959
+ exists , err := s .Exists (ctx , descs [i ])
2960
+ if err != nil {
2961
+ t .Fatal (err )
2962
+ }
2963
+ if exists != wantValue {
2964
+ t .Fatalf ("want existence %d to be %v, got %v" , i , wantValue , exists )
2965
+ }
2966
+ }
2967
+ }
2968
+
2969
+ func TestStore_GCErrorPath (t * testing.T ) {
2970
+ tempDir := t .TempDir ()
2971
+ s , err := New (tempDir )
2972
+ if err != nil {
2973
+ t .Fatal ("New() error =" , err )
2974
+ }
2975
+ ctx := context .Background ()
2976
+
2977
+ // generate test content
2978
+ var blobs [][]byte
2979
+ var descs []ocispec.Descriptor
2980
+ appendBlob := func (mediaType string , blob []byte ) {
2981
+ blobs = append (blobs , blob )
2982
+ descs = append (descs , ocispec.Descriptor {
2983
+ MediaType : mediaType ,
2984
+ Digest : digest .FromBytes (blob ),
2985
+ Size : int64 (len (blob )),
2986
+ })
2987
+ }
2988
+ appendBlob (ocispec .MediaTypeImageLayer , []byte ("valid blob" )) // Blob 0
2989
+
2990
+ // push the valid blob
2991
+ err = s .Push (ctx , descs [0 ], bytes .NewReader (blobs [0 ]))
2992
+ if err != nil {
2993
+ t .Error ("failed to push test content to src" )
2994
+ }
2995
+
2996
+ // write random contents
2997
+ algPath := path .Join (tempDir , "blobs" )
2998
+ dgstPath := path .Join (algPath , "sha256" )
2999
+ if err := os .WriteFile (path .Join (algPath , "other" ), []byte ("random" ), 0444 ); err != nil {
3000
+ t .Fatal ("error calling WriteFile(), error =" , err )
3001
+ }
3002
+ if err := os .WriteFile (path .Join (dgstPath , "other2" ), []byte ("random2" ), 0444 ); err != nil {
3003
+ t .Fatal ("error calling WriteFile(), error =" , err )
3004
+ }
3005
+
3006
+ // perform GC
3007
+ if err = s .GC (ctx ); err != nil {
3008
+ t .Fatal (err )
3009
+ }
3010
+
3011
+ appendBlob (ocispec .MediaTypeImageLayer , []byte ("valid blob 2" )) // Blob 1
3012
+
3013
+ // push the valid blob
3014
+ err = s .Push (ctx , descs [1 ], bytes .NewReader (blobs [1 ]))
3015
+ if err != nil {
3016
+ t .Error ("failed to push test content to src" )
3017
+ }
3018
+
3019
+ // unknown algorithm
3020
+ if err := os .Mkdir (path .Join (algPath , "sha666" ), 0777 ); err != nil {
3021
+ t .Fatal (err )
3022
+ }
3023
+ if err = s .GC (ctx ); err != nil {
3024
+ t .Fatal ("this error should be silently ignored" )
3025
+ }
3026
+
3027
+ // os.Remove() error
3028
+ badDigest := digest .FromBytes ([]byte ("bad digest" )).Encoded ()
3029
+ badPath := path .Join (algPath , "sha256" , badDigest )
3030
+ if err := os .Mkdir (badPath , 0777 ); err != nil {
3031
+ t .Fatal (err )
3032
+ }
3033
+ if err := os .WriteFile (path .Join (badPath , "whatever" ), []byte ("extra content" ), 0444 ); err != nil {
3034
+ t .Fatal ("error calling WriteFile(), error =" , err )
3035
+ }
3036
+ if err = s .GC (ctx ); err == nil {
3037
+ t .Fatal ("expect an error when os.Remove()" )
3038
+ }
3039
+ }
3040
+
2847
3041
func equalDescriptorSet (actual []ocispec.Descriptor , expected []ocispec.Descriptor ) bool {
2848
3042
if len (actual ) != len (expected ) {
2849
3043
return false
@@ -2863,3 +3057,15 @@ func equalDescriptorSet(actual []ocispec.Descriptor, expected []ocispec.Descript
2863
3057
}
2864
3058
return true
2865
3059
}
3060
+
3061
+ func Test_isContextDone (t * testing.T ) {
3062
+ ctx := context .Background ()
3063
+ ctx , cancel := context .WithCancel (ctx )
3064
+ if err := isContextDone (ctx ); err != nil {
3065
+ t .Errorf ("expect error = %v, got %v" , nil , err )
3066
+ }
3067
+ cancel ()
3068
+ if err := isContextDone (ctx ); err != context .Canceled {
3069
+ t .Errorf ("expect error = %v, got %v" , context .Canceled , err )
3070
+ }
3071
+ }
0 commit comments