func TestFetchImageCache(t *testing.T) { dir, err := ioutil.TempDir("", "fetch-image-cache") if err != nil { t.Fatalf("error creating tempdir: %v", err) } defer os.RemoveAll(dir) s, err := imagestore.NewStore(dir) if err != nil { t.Fatalf("unexpected error %v", err) } defer s.Dump(false) ks, ksPath, err := keystore.NewTestKeystore() if err != nil { t.Errorf("unexpected error %v", err) } defer os.RemoveAll(ksPath) key := keystoretest.KeyMap["example.com/app"] if _, err := ks.StoreTrustedKeyPrefix("example.com/app", bytes.NewBufferString(key.ArmoredPublicKey)); err != nil { t.Fatalf("unexpected error %v", err) } a, err := aci.NewBasicACI(dir, "example.com/app") defer a.Close() if err != nil { t.Fatalf("unexpected error %v", err) } // Rewind the ACI if _, err := a.Seek(0, 0); err != nil { t.Fatalf("unexpected error %v", err) } asc, err := aci.NewDetachedSignature(key.ArmoredPrivateKey, a) if err != nil { t.Fatalf("unexpected error %v", err) } // Rewind the ACI if _, err := a.Seek(0, 0); err != nil { t.Fatalf("unexpected error %v", err) } aciBody, err := ioutil.ReadAll(a) if err != nil { t.Fatalf("unexpected error: %v", err) } ascBody, err := ioutil.ReadAll(asc) if err != nil { t.Fatalf("unexpected error: %v", err) } nocacheServer := &cachingServerHandler{ aciBody: aciBody, ascBody: ascBody, etag: "", maxAge: 0, t: t, } etagServer := &cachingServerHandler{ aciBody: aciBody, ascBody: ascBody, etag: "123456789", maxAge: 0, t: t, } maxAgeServer := &cachingServerHandler{ aciBody: aciBody, ascBody: ascBody, etag: "", maxAge: 10, t: t, } etagMaxAgeServer := &cachingServerHandler{ aciBody: aciBody, ascBody: ascBody, etag: "123456789", maxAge: 10, t: t, } nocacheTS := httptest.NewServer(nocacheServer) defer nocacheTS.Close() etagTS := httptest.NewServer(etagServer) defer etagTS.Close() maxAgeTS := httptest.NewServer(maxAgeServer) defer maxAgeTS.Close() etagMaxAgeTS := httptest.NewServer(etagMaxAgeServer) defer etagMaxAgeTS.Close() type testData struct { URL string etag string cacheMaxAge int shouldUseCached bool } tests := []testData{ {nocacheTS.URL, "", 0, false}, {etagTS.URL, "123456789", 0, true}, {maxAgeTS.URL, "", 10, true}, {etagMaxAgeTS.URL, "123456789", 10, true}, } testFn := func(tt testData, useRedirect bool) { aciURL := fmt.Sprintf("%s/app.aci", tt.URL) if useRedirect { redirectingTS := httptest.NewServer(&redirectingServerHandler{destServer: tt.URL}) defer redirectingTS.Close() aciURL = fmt.Sprintf("%s/app.aci", redirectingTS.URL) } ft := &image.Fetcher{ S: s, Ks: ks, InsecureFlags: secureFlags, // Skip local store NoStore: true, } _, err = ft.FetchImage(aciURL, "", apps.AppImageURL) if err != nil { t.Fatalf("unexpected error: %v", err) } rem, _, err := s.GetRemote(aciURL) if err != nil { t.Fatalf("Error getting remote info: %v\n", err) } if rem.ETag != tt.etag { t.Errorf("expected remote to have a ETag header argument") } if rem.CacheMaxAge != tt.cacheMaxAge { t.Errorf("expected max-age header argument to be %q", tt.cacheMaxAge) } downloadTime := rem.DownloadTime _, err = ft.FetchImage(aciURL, "", apps.AppImageURL) if err != nil { t.Fatalf("unexpected error: %v", err) } rem, _, err = s.GetRemote(aciURL) if err != nil { t.Fatalf("Error getting remote info: %v\n", err) } if rem.ETag != tt.etag { t.Errorf("expected remote to have a ETag header argument") } if rem.CacheMaxAge != tt.cacheMaxAge { t.Errorf("expected max-age header argument to be %q", tt.cacheMaxAge) } if tt.shouldUseCached { if downloadTime != rem.DownloadTime { t.Errorf("expected current download time to be the same as the previous one (no download) but they differ") } } else { if downloadTime == rem.DownloadTime { t.Errorf("expected current download time to be different from the previous one (new image download) but they are the same") } } if err := s.RemoveACI(rem.BlobKey); err != nil { t.Fatalf("unexpected error: %v", err) } } // repeat the tests with and without a redirecting server for i := 0; i <= 1; i++ { useRedirect := false if i == 1 { useRedirect = true } for _, tt := range tests { testFn(tt, useRedirect) } } }
func TestFetchImage(t *testing.T) { dir, err := ioutil.TempDir("", "fetch-image") if err != nil { t.Fatalf("error creating tempdir: %v", err) } defer os.RemoveAll(dir) s, err := store.NewStore(dir) if err != nil { t.Fatalf("unexpected error %v", err) } defer s.Dump(false) ks, ksPath, err := keystore.NewTestKeystore() if err != nil { t.Errorf("unexpected error %v", err) } defer os.RemoveAll(ksPath) key := keystoretest.KeyMap["example.com/app"] if _, err := ks.StoreTrustedKeyPrefix("example.com/app", bytes.NewBufferString(key.ArmoredPublicKey)); err != nil { t.Fatalf("unexpected error %v", err) } a, err := aci.NewBasicACI(dir, "example.com/app") defer a.Close() if err != nil { t.Fatalf("unexpected error %v", err) } // Rewind the ACI if _, err := a.Seek(0, 0); err != nil { t.Fatalf("unexpected error %v", err) } asc, err := aci.NewDetachedSignature(key.ArmoredPrivateKey, a) if err != nil { t.Fatalf("unexpected error %v", err) } // Rewind the ACI. if _, err := a.Seek(0, 0); err != nil { t.Fatalf("unexpected error %v", err) } ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { switch filepath.Ext(r.URL.Path) { case ".aci": io.Copy(w, a) return case ".asc": io.Copy(w, asc) return default: t.Fatalf("unknown extension %v", r.URL.Path) } })) defer ts.Close() ft := &fetcher{ imageActionData: imageActionData{ s: s, ks: ks, }, } _, err = ft.fetchImage(fmt.Sprintf("%s/app.aci", ts.URL), "", true) if err != nil { t.Fatalf("unexpected error: %v", err) } }
func TestFetchImageCache(t *testing.T) { dir, err := ioutil.TempDir("", "fetch-image-cache") if err != nil { t.Fatalf("error creating tempdir: %v", err) } defer os.RemoveAll(dir) s, err := store.NewStore(dir) if err != nil { t.Fatalf("unexpected error %v", err) } defer s.Dump(false) ks, ksPath, err := keystore.NewTestKeystore() if err != nil { t.Errorf("unexpected error %v", err) } defer os.RemoveAll(ksPath) key := keystoretest.KeyMap["example.com/app"] if _, err := ks.StoreTrustedKeyPrefix("example.com/app", bytes.NewBufferString(key.ArmoredPublicKey)); err != nil { t.Fatalf("unexpected error %v", err) } a, err := aci.NewBasicACI(dir, "example.com/app") defer a.Close() if err != nil { t.Fatalf("unexpected error %v", err) } // Rewind the ACI if _, err := a.Seek(0, 0); err != nil { t.Fatalf("unexpected error %v", err) } asc, err := aci.NewDetachedSignature(key.ArmoredPrivateKey, a) if err != nil { t.Fatalf("unexpected error %v", err) } // Rewind the ACI if _, err := a.Seek(0, 0); err != nil { t.Fatalf("unexpected error %v", err) } aciBody, err := ioutil.ReadAll(a) if err != nil { t.Fatalf("unexpected error: %v", err) } ascBody, err := ioutil.ReadAll(asc) if err != nil { t.Fatalf("unexpected error: %v", err) } nocacheServer := &cachingServerHandler{ aciBody: aciBody, ascBody: ascBody, etag: "", maxAge: 0, t: t, } etagServer := &cachingServerHandler{ aciBody: aciBody, ascBody: ascBody, etag: "123456789", maxAge: 0, t: t, } maxAgeServer := &cachingServerHandler{ aciBody: aciBody, ascBody: ascBody, etag: "", maxAge: 10, t: t, } etagMaxAgeServer := &cachingServerHandler{ aciBody: aciBody, ascBody: ascBody, etag: "123456789", maxAge: 10, t: t, } nocacheTS := httptest.NewServer(nocacheServer) defer nocacheTS.Close() etagTS := httptest.NewServer(etagServer) defer etagTS.Close() maxAgeTS := httptest.NewServer(maxAgeServer) defer maxAgeTS.Close() etagMaxAgeTS := httptest.NewServer(etagMaxAgeServer) defer etagMaxAgeTS.Close() tests := []struct { URL string etag string cacheMaxAge int shouldUseCached bool }{ {nocacheTS.URL, "", 0, false}, {etagTS.URL, "123456789", 0, true}, {maxAgeTS.URL, "", 10, true}, {etagMaxAgeTS.URL, "123456789", 10, true}, } for _, tt := range tests { ft := &fetcher{ imageActionData: imageActionData{ s: s, ks: ks, }, } aciURL := fmt.Sprintf("%s/app.aci", tt.URL) _, err = ft.fetchImage(aciURL, "", true) if err != nil { t.Fatalf("unexpected error: %v", err) } rem, _, err := s.GetRemote(aciURL) if err != nil { t.Fatalf("Error getting remote info: %v\n", err) } if rem.ETag != tt.etag { t.Errorf("expected remote to have a ETag header argument") } if rem.CacheMaxAge != tt.cacheMaxAge { t.Errorf("expected max-age header argument to be %q", tt.cacheMaxAge) } downloadTime := rem.DownloadTime _, err = ft.fetchImage(aciURL, "", true) if err != nil { t.Fatalf("unexpected error: %v", err) } rem, _, err = s.GetRemote(aciURL) if err != nil { t.Fatalf("Error getting remote info: %v\n", err) } if rem.ETag != tt.etag { t.Errorf("expected remote to have a ETag header argument") } if rem.CacheMaxAge != tt.cacheMaxAge { t.Errorf("expected max-age header argument to be %q", tt.cacheMaxAge) } if tt.shouldUseCached { if downloadTime != rem.DownloadTime { t.Errorf("expected current download time to be the same of the previous one (no download) but they differ") } } else { if downloadTime == rem.DownloadTime { t.Errorf("expected current download time to be different from the previous one (new image download) but they are the same") } } if err := s.RemoveACI(rem.BlobKey); err != nil { t.Fatalf("unexpected error: %v", err) } } }