1515package flag_optimizations
1616
1717import (
18+ "bufio"
19+ "encoding/json"
20+ "fmt"
1821 "os"
1922 "path/filepath"
2023 "strings"
2124 "testing"
2225
26+ "github.com/googlecloudplatform/gcsfuse/v3/cfg"
27+ "github.com/googlecloudplatform/gcsfuse/v3/internal/kernelparams"
2328 "github.com/googlecloudplatform/gcsfuse/v3/tools/integration_tests/util/client"
2429 "github.com/googlecloudplatform/gcsfuse/v3/tools/integration_tests/util/setup"
2530 "github.com/stretchr/testify/assert"
2631 "github.com/stretchr/testify/require"
32+ "golang.org/x/sys/unix"
2733)
2834
2935////////////////////////////////////////////////////////////////////////
@@ -35,6 +41,44 @@ func tearDownOptimizationTest(t *testing.T) {
3541 setup .UnmountGCSFuseWithConfig (& testEnv .cfg )
3642}
3743
44+ ////////////////////////////////////////////////////////////////////////
45+ // Helpers
46+ ////////////////////////////////////////////////////////////////////////
47+
48+ func validateConfigValues (t * testing.T , logFile string , requiredLogKey string , expectedConfig map [string ]interface {}) {
49+ // Open log file to verify config
50+ file , err := os .Open (logFile )
51+ require .NoError (t , err )
52+ defer file .Close ()
53+
54+ var configFound bool
55+ scanner := bufio .NewScanner (file )
56+ for scanner .Scan () {
57+ var entry map [string ]interface {}
58+ if err := json .Unmarshal (scanner .Bytes (), & entry ); err != nil {
59+ // Skip non-JSON lines (e.g. command invocation)
60+ continue
61+ }
62+ // Check if the log entry contains the required key
63+ if _ , ok := entry [requiredLogKey ]; ! ok {
64+ continue
65+ }
66+
67+ if fullConfigMap , ok := entry ["Full Config" ].(map [string ]interface {}); ok {
68+ configFound = true
69+ for key , expectedVal := range expectedConfig {
70+ var actualVal interface {}
71+ if valMap , ok := fullConfigMap [key ].(map [string ]interface {}); ok {
72+ actualVal = valMap ["final_value" ]
73+ }
74+ assert .EqualValues (t , expectedVal , actualVal , "Config %q mismatch" , key )
75+ }
76+ break
77+ }
78+ }
79+ assert .True (t , configFound , "GCSFuse Config log not found" )
80+ }
81+
3882////////////////////////////////////////////////////////////////////////
3983// Test Functions
4084////////////////////////////////////////////////////////////////////////
@@ -64,6 +108,67 @@ func TestImplicitDirsNotEnabled(t *testing.T) {
64108 }
65109}
66110
111+ func TestZonalBucketOptimizations_LogVerification (t * testing.T ) {
112+ if setup .IsDynamicMount (testEnv .mountDir , testEnv .rootDir ) {
113+ t .Skip ("Skipping test for dynamic mounting" )
114+ }
115+
116+ flagsSet := setup .BuildFlagSets (testEnv .cfg , testEnv .bucketType , t .Name ())
117+ for _ , flags := range flagsSet {
118+ t .Run (strings .Join (flags , "_" ), func (t * testing.T ) {
119+ mustMountGCSFuseAndSetupTestDir (flags , testEnv .ctx , testEnv .storageClient )
120+ defer tearDownOptimizationTest (t )
121+
122+ expectedConfig := map [string ]interface {}{
123+ "file-system.enable-kernel-reader" : true ,
124+ "file-system.max-read-ahead-kb" : 16384 ,
125+ "file-system.max-background" : cfg .DefaultMaxBackground (),
126+ "file-system.congestion-threshold" : cfg .DefaultCongestionThreshold (),
127+ }
128+ validateConfigValues (t , testEnv .cfg .LogFile , "Applied optimizations for bucket-type: " , expectedConfig )
129+ })
130+ }
131+ }
132+
133+ func TestZonalBucketOptimizations_KernelParamVerification (t * testing.T ) {
134+ if setup .IsDynamicMount (testEnv .mountDir , testEnv .rootDir ) {
135+ t .Skip ("Skipping test for dynamic mounting" )
136+ }
137+
138+ flagsSet := setup .BuildFlagSets (testEnv .cfg , testEnv .bucketType , t .Name ())
139+ for _ , flags := range flagsSet {
140+ t .Run (strings .Join (flags , "_" ), func (t * testing.T ) {
141+ mustMountGCSFuseAndSetupTestDir (flags , testEnv .ctx , testEnv .storageClient )
142+ defer tearDownOptimizationTest (t )
143+
144+ // Verify kernel parameters in /sys
145+ var stat unix.Stat_t
146+ err := unix .Stat (setup .MntDir (), & stat )
147+ require .NoError (t , err )
148+ devMajor := unix .Major (stat .Dev )
149+ devMinor := unix .Minor (stat .Dev )
150+ readAheadPath , err := kernelparams .PathForParam (kernelparams .MaxReadAheadKb , devMajor , devMinor )
151+ require .NoError (t , err )
152+ maxBackgroundPath , err := kernelparams .PathForParam (kernelparams .MaxBackgroundRequests , devMajor , devMinor )
153+ require .NoError (t , err )
154+ congestionThresholdPath , err := kernelparams .PathForParam (kernelparams .CongestionWindowThreshold , devMajor , devMinor )
155+ require .NoError (t , err )
156+ expected := map [string ]string {
157+ readAheadPath : "16384" ,
158+ maxBackgroundPath : fmt .Sprintf ("%d" , cfg .DefaultMaxBackground ()),
159+ congestionThresholdPath : fmt .Sprintf ("%d" , cfg .DefaultCongestionThreshold ()),
160+ }
161+
162+ for path , val := range expected {
163+ content , err := os .ReadFile (path )
164+
165+ require .NoError (t , err )
166+ assert .Equal (t , val , strings .TrimSpace (string (content )))
167+ }
168+ })
169+ }
170+ }
171+
67172func TestRenameDirLimitNotSet (t * testing.T ) {
68173 flagsSet := setup .BuildFlagSets (testEnv .cfg , testEnv .bucketType , t .Name ())
69174 for _ , flags := range flagsSet {
0 commit comments