pull/30984/merge
Artem Vdovin 8 hours ago committed by GitHub
commit b450b56e93
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -17,6 +17,7 @@ limitations under the License.
package repo // import "helm.sh/helm/v4/pkg/repo/v1"
import (
"bytes"
"crypto/rand"
"encoding/base64"
"encoding/json"
@ -28,6 +29,7 @@ import (
"path/filepath"
"strings"
"helm.sh/helm/v4/internal/fileutil"
"helm.sh/helm/v4/pkg/getter"
"helm.sh/helm/v4/pkg/helmpath"
)
@ -108,12 +110,13 @@ func (r *ChartRepository) DownloadIndexFile() (string, error) {
}
chartsFile := filepath.Join(r.CachePath, helmpath.CacheChartsFile(r.Config.Name))
os.MkdirAll(filepath.Dir(chartsFile), 0755)
os.WriteFile(chartsFile, []byte(charts.String()), 0644)
fileutil.AtomicWriteFile(chartsFile, bytes.NewReader([]byte(charts.String())), 0644)
// Create the index file in the cache directory
fname := filepath.Join(r.CachePath, helmpath.CacheIndexFile(r.Config.Name))
os.MkdirAll(filepath.Dir(fname), 0755)
return fname, os.WriteFile(fname, index, 0644)
return fname, fileutil.AtomicWriteFile(fname, bytes.NewReader(index), 0644)
}
type findChartInRepoURLOptions struct {

@ -22,8 +22,10 @@ import (
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"runtime"
"strings"
"sync"
"testing"
"time"
@ -31,6 +33,7 @@ import (
"helm.sh/helm/v4/pkg/cli"
"helm.sh/helm/v4/pkg/getter"
"helm.sh/helm/v4/pkg/helmpath"
)
type CustomGetter struct {
@ -91,6 +94,60 @@ func TestIndexCustomSchemeDownload(t *testing.T) {
}
}
func TestConcurrenyDownloadIndex(t *testing.T) {
srv, err := startLocalServerForTests(nil)
if err != nil {
t.Fatal(err)
}
defer srv.Close()
repo, err := NewChartRepository(&Entry{
Name: "nginx",
URL: srv.URL,
}, getter.All(&cli.EnvSettings{}))
if err != nil {
t.Fatalf("Problem loading chart repository from %s: %v", srv.URL, err)
}
repo.CachePath = t.TempDir()
// initial download index
idx, err := repo.DownloadIndexFile()
if err != nil {
t.Fatalf("Failed to download index file to %s: %v", idx, err)
}
indexFName := filepath.Join(repo.CachePath, helmpath.CacheIndexFile(repo.Config.Name))
var wg sync.WaitGroup
// Simultaneously start multiple goroutines that:
// 1) download index.yaml via DownloadIndexFile (write operation),
// 2) read index.yaml via LoadIndexFile (read operation).
// This checks for race conditions and ensures correct behavior under concurrent read/write access.
for range 150 {
wg.Add(1)
go func() {
defer wg.Done()
idx, err := repo.DownloadIndexFile()
if err != nil {
t.Errorf("Failed to download index file to %s: %v", idx, err)
}
}()
wg.Add(1)
go func() {
defer wg.Done()
_, err := LoadIndexFile(indexFName)
if err != nil {
t.Errorf("Failed to load index file: %v", err)
}
}()
}
wg.Wait()
}
// startLocalServerForTests Start the local helm server
func startLocalServerForTests(handler http.Handler) (*httptest.Server, error) {
if handler == nil {

Loading…
Cancel
Save