func TestGC(t *testing.T) {
	fixture := hermittest.NewEnvTestFixture(t, nil).WithManifests(map[string]string{
		"test.hcl": `
			description = ""
			binaries = ["bin"]
			version "1" {
			  source = "www.example.com"
			}
		`,
		"test2.hcl": `
			description = ""
			binaries = ["bin"]
			version "1" {
			  source = "www.example.com"
			}
		`,
	})
	defer fixture.Clean()
	pkg1 := manifesttest.NewPkgBuilder(filepath.Join(fixture.RootDir(), "test")).
		WithSource("archive/testdata/archive.tar.gz").
		Result()
	_, err := fixture.Env.Install(fixture.P, pkg1)
	require.NoError(t, err)
	anotherEnv := fixture.NewEnv()
	pkg2 := manifesttest.NewPkgBuilder(filepath.Join(fixture.RootDir(), "test")).
		WithSource("archive/testdata/archive.tar.gz").
		WithName("test2").
		WithVersion("1").
		Result()
	_, err = anotherEnv.Install(fixture.P, pkg2)
	require.NoError(t, err)
	d := fixture.DAO()
	err = d.UpdatePackageWithUsage("/foo/bin", "invalid-pkg-1", &dao.Package{})
	require.NoError(t, err)
	db := fixture.BoltDB()
	err = db.Update(func(tx *bolt.Tx) error {
		return tx.ForEach(func(name []byte, b *bolt.Bucket) error {
			return b.Put([]byte("usedAt"), []byte("2000-01-01 01:01:01"))
		})
	})
	db.Close()
	require.NoError(t, err)
	err = os.RemoveAll(anotherEnv.EnvDir())
	require.NoError(t, err)
	err = fixture.Env.GC(fixture.P, time.Hour)
	require.NoError(t, err)
	usages1, err := d.GetKnownUsages(pkg1.Reference.String())
	require.NoError(t, err)
	usages2, err := d.GetKnownUsages(pkg2.Reference.String())
	require.NoError(t, err)
	require.Equal(t, 1, len(usages1))
	require.Equal(t, 0, len(usages2))
	p, err := d.GetPackage(pkg1.Reference.String())
	require.NoError(t, err)
	require.NotNil(t, p)
	p, _ = d.GetPackage(pkg2.Reference.String())
	require.Nil(t, p)
	p, _ = d.GetPackage("invalid-pkg-1")
	require.Nil(t, p)
	_, err = os.Stat(filepath.Join(fixture.State.PkgDir(), pkg1.Reference.String()))
	require.NoError(t, err)
	_, err = os.Stat(filepath.Join(fixture.State.PkgDir(), pkg2.Reference.String()))
	require.Equal(t, true, os.IsNotExist(err))
}
Tests that Garbage collection removes expired packages only if they are no longer referred from
any environment
package hermit_test
import (
	"github.com/cashapp/hermit"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"testing"
	"time"
	"github.com/stretchr/testify/require"
	bolt "go.etcd.io/bbolt"
	"github.com/cashapp/hermit/envars"
	"github.com/cashapp/hermit/hermittest"
	"github.com/cashapp/hermit/internal/dao"
	"github.com/cashapp/hermit/manifest"
	"github.com/cashapp/hermit/manifest/manifesttest"
)
func TestConflictingBinariesError(t *testing.T) {
	fixture := hermittest.NewEnvTestFixture(t, nil)
	defer fixture.Clean()
	pkg1 := manifesttest.NewPkgBuilder(fixture.RootDir()).
		WithSource("archive/testdata/archive.tar.gz").
		Result()
	pkg2 := manifesttest.NewPkgBuilder(fixture.RootDir()).
		WithSource("archive/testdata/archive.tar.gz").
		WithName("test2").
		WithVersion("1").
		Result()
	_, err := fixture.Env.Install(fixture.P, pkg1)
	require.NoError(t, err)
	_, err = fixture.Env.Install(fixture.P, pkg2)
	require.Errorf(t, err, "test2-1 can not be installed, the following binaries already exist: darwin_exe, linux_exe")
}
func TestUpdateTimestampOnInstall(t *testing.T) {
	calls := 0
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Add("ETag", "testtag")
		dat, _ := ioutil.ReadFile("archive/testdata/archive.tar.gz")
		_, err := w.Write(dat)
		require.NoError(t, err)
		calls++
	})
	fixture := hermittest.NewEnvTestFixture(t, handler)
	defer fixture.Clean()
	pkg := manifesttest.NewPkgBuilder(fixture.RootDir()).
		WithName("test").
		WithChannel("stable").
		WithUpdateInterval(1 * time.Hour).
		WithSource(fixture.Server.URL).
		Result()
	_, err := fixture.Env.Install(fixture.P, pkg)
	require.NoError(t, err)
	dbPkg := fixture.GetDBPackage("test@stable")
	actual := dbPkg.UpdateCheckedAt.Unix()
	require.GreaterOrEqual(t, time.Now().Add(1*time.Minute).Unix(), actual)
	require.LessOrEqual(t, time.Now().Add(-1*time.Minute).Unix(), actual)
	require.Equal(t, "testtag", dbPkg.Etag)
	require.Equal(t, 1, calls)
}
func TestEnsureUpToDate(t *testing.T) {
	etag := "first"
	data := "data"
	headCalls := 0
	getCalls := 0
	fail := false
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Add("ETag", etag)
		if fail {
			w.WriteHeader(500)
		} else if r.Method == "HEAD" {
			headCalls++
		} else if r.Method == "GET" {
			getCalls++
			tar := TestTarGz{map[string]string{"bin": data}}
			tar.Write(t, w)
		}
	})
	fixture := hermittest.NewEnvTestFixture(t, handler)
	defer fixture.Clean()
	dao := fixture.DAO()
	pkg := manifesttest.NewPkgBuilder(fixture.RootDir()).
		WithName("test").
		WithBinaries("bin").
		WithChannel("chan").
		WithUpdateInterval(1 * time.Hour).
		WithSource(fixture.Server.URL).
		Result()
	_, err := fixture.Env.Install(fixture.P, pkg)
	require.NoError(t, err)
	require.Equal(t, 1, getCalls)
	require.Equal(t, 0, headCalls)
	err = fixture.Env.EnsureChannelIsUpToDate(fixture.P, pkg)
	require.NoError(t, err)
	require.Equal(t, 1, getCalls)
	require.Equal(t, 0, headCalls)
	file, _ := ioutil.ReadFile(filepath.Join(pkg.Dest, "bin"))
	require.Equal(t, data, string(file))
	pkg.UpdatedAt = time.Now().Add(-2 * time.Hour)
	err = fixture.Env.EnsureChannelIsUpToDate(fixture.P, pkg)
	require.NoError(t, err)
	require.Equal(t, 1, getCalls)
	require.Equal(t, 1, headCalls)
	file, _ = ioutil.ReadFile(filepath.Join(pkg.Dest, "bin"))
	require.Equal(t, data, string(file))
	pkg.UpdatedAt = time.Now().Add(-2 * time.Hour)
	etag = "changed"
	data = strings.Repeat("other", 1024)
	err = fixture.Env.EnsureChannelIsUpToDate(fixture.P, pkg)
	require.NoError(t, err)
	require.Equal(t, 2, getCalls)
	require.Equal(t, 2, headCalls)
	file, _ = ioutil.ReadFile(filepath.Join(pkg.Dest, "bin"))
	require.Equal(t, data, string(file))
	dbPkg, err := dao.GetPackage(pkg.Reference.String())
	require.NoError(t, err)
	require.NotNil(t, dbPkg)
	fail = true
	pkg.UpdatedAt = time.Now().Add(-2 * time.Hour)
	err = fixture.Env.EnsureChannelIsUpToDate(fixture.P, pkg)
	require.NoError(t, err)
	dbPkg, err = dao.GetPackage(pkg.Reference.String())
	require.NoError(t, err)
	require.Equal(t, etag, dbPkg.Etag)
}