From 00d9eb6e52f0c2835c04c27111c5e0fa6da1b442 Mon Sep 17 00:00:00 2001 From: Maciej Wilk Date: Tue, 6 Oct 2026 16:12:36 +0200 Subject: [PATCH 01/18] Add int tests for NFS Space --- test/integration/nfs_spaces_test.go | 92 +++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 test/integration/nfs_spaces_test.go diff --git a/test/integration/nfs_spaces_test.go b/test/integration/nfs_spaces_test.go new file mode 100644 index 000000000..8d2a8a73e --- /dev/null +++ b/test/integration/nfs_spaces_test.go @@ -0,0 +1,92 @@ +package integration + +import ( + "context" + "testing" + + "github.com/linode/linodego/v2" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +var TestNFSSpaceCreateOptions = linodego.NFSSpaceCreateOptions{ + Label: "go-test-nfs-space-" + randLabel(), + Description: linodego.Pointer("Test description"), + Tags: linodego.Pointer([]string{"testing"}), +} + +func createNFSSpace( + t *testing.T, + fixtureYaml string, + modifiers ...func(opts *linodego.NFSSpaceCreateOptions), +) (*linodego.Client, *linodego.NFSSpace) { + t.Helper() + client, fixtureTeardown := createTestClient(t, fixtureYaml) + createOpts := TestNFSSpaceCreateOptions + + for _, modifier := range modifiers { + modifier(&createOpts) + } + + space, err := client.CreateNFSSpace(context.Background(), createOpts) + require.NoErrorf(t, err, "Error creating NFS Space: %v", err) + + t.Cleanup(func() { + if err := client.DeleteNFSSpace(context.Background(), space.ID); err != nil { + t.Errorf("Error deleting NFS Space: %v", err) + } + fixtureTeardown() + }) + + return client, space +} + +func verifyNFSSpace(t *testing.T, space *linodego.NFSSpace) { + t.Helper() + assert.Equal(t, TestNFSSpaceCreateOptions.Label, space.Label) + assert.Equal(t, TestNFSSpaceCreateOptions.Description, space.Description) + assert.Equal(t, TestNFSSpaceCreateOptions.Tags, linodego.Pointer(space.Tags)) + assert.NotNil(t, space.Status) + assertDateSet(t, space.Created) + assertDateSet(t, space.Updated) +} + +func TestNFSSpace_Create_smoke(t *testing.T) { + client, space := createNFSSpace(t, "fixtures/TestNFSSpace_Create") + verifyNFSSpace(t, space) + + spaceGet, err := client.GetNFSSpace(context.Background(), space.ID) + require.NoErrorf(t, err, "Error retrieving NFS Space: %v", err) + verifyNFSSpace(t, spaceGet) +} + +func TestNFSSpace_List(t *testing.T) { + client, space := createNFSSpace(t, "fixtures/TestNFSSpace_List") + + f := linodego.Filter{} + f.AddField(linodego.Eq, "label", space.Label) + filter, err := f.MarshalJSON() + if err != nil { + t.Fatalf("Failed to marshal filter: %v", err) + } + + spaceList, err := client.ListNFSSpaces(context.Background(), &linodego.ListOptions{Filter: string(filter)}) + require.NoErrorf(t, err, "Error listing NFS Spaces: %v", err) + assert.Len(t, spaceList, 1) + verifyNFSSpace(t, linodego.Pointer(spaceList[0])) +} + +func TestNFSSpace_Update(t *testing.T) { + client, space := createNFSSpace(t, "fixtures/TestNFSSpace_Update") + updateOpts := linodego.NFSSpaceUpdateOptions{ + Label: linodego.Pointer(space.Label + "-updated"), + Description: linodego.Pointer("Description updated"), + Tags: linodego.Pointer([]string{"updated"}), + } + + spaceUpdate, err := client.UpdateNFSSpace(context.Background(), space.ID, updateOpts) + require.NoErrorf(t, err, "Error updating NFS Space: %v", err) + assert.Equal(t, updateOpts.Label, linodego.Pointer(spaceUpdate.Label)) + assert.Equal(t, updateOpts.Description, spaceUpdate.Description) + assert.Equal(t, updateOpts.Tags, linodego.Pointer(spaceUpdate.Tags)) +} From 8ec4b8f4f65fa02a39c309fd992699e7cc64aa3d Mon Sep 17 00:00:00 2001 From: Maciej Wilk Date: Tue, 6 Oct 2026 16:18:56 +0200 Subject: [PATCH 02/18] Add dedicated test for GetNFSSpace --- test/integration/nfs_spaces_test.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/integration/nfs_spaces_test.go b/test/integration/nfs_spaces_test.go index 8d2a8a73e..10770f5f2 100644 --- a/test/integration/nfs_spaces_test.go +++ b/test/integration/nfs_spaces_test.go @@ -52,8 +52,12 @@ func verifyNFSSpace(t *testing.T, space *linodego.NFSSpace) { } func TestNFSSpace_Create_smoke(t *testing.T) { - client, space := createNFSSpace(t, "fixtures/TestNFSSpace_Create") + _, space := createNFSSpace(t, "fixtures/TestNFSSpace_Create") verifyNFSSpace(t, space) +} + +func TestNFSSpace_Get(t *testing.T) { + client, space := createNFSSpace(t, "fixtures/TestNFSSpace_Get") spaceGet, err := client.GetNFSSpace(context.Background(), space.ID) require.NoErrorf(t, err, "Error retrieving NFS Space: %v", err) From c905c1010f65495283f2b6629832f10df990cc3b Mon Sep 17 00:00:00 2001 From: Maciej Wilk Date: Wed, 7 Oct 2026 09:04:27 +0200 Subject: [PATCH 03/18] Modify a way of getting NFSSpaceCreateOptions --- test/integration/nfs_spaces_test.go | 38 +++++++++++++++-------------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/test/integration/nfs_spaces_test.go b/test/integration/nfs_spaces_test.go index 10770f5f2..6e908876a 100644 --- a/test/integration/nfs_spaces_test.go +++ b/test/integration/nfs_spaces_test.go @@ -9,20 +9,22 @@ import ( "github.com/stretchr/testify/require" ) -var TestNFSSpaceCreateOptions = linodego.NFSSpaceCreateOptions{ - Label: "go-test-nfs-space-" + randLabel(), - Description: linodego.Pointer("Test description"), - Tags: linodego.Pointer([]string{"testing"}), +func getNFSSpaceCreateOptions() linodego.NFSSpaceCreateOptions { + return linodego.NFSSpaceCreateOptions{ + Label: "go-test-nfs-space-" + randLabel(), + Description: linodego.Pointer("Test description"), + Tags: linodego.Pointer([]string{"testing"}), + } } func createNFSSpace( t *testing.T, fixtureYaml string, modifiers ...func(opts *linodego.NFSSpaceCreateOptions), -) (*linodego.Client, *linodego.NFSSpace) { +) (*linodego.Client, *linodego.NFSSpace, linodego.NFSSpaceCreateOptions) { t.Helper() client, fixtureTeardown := createTestClient(t, fixtureYaml) - createOpts := TestNFSSpaceCreateOptions + createOpts := getNFSSpaceCreateOptions() for _, modifier := range modifiers { modifier(&createOpts) @@ -38,34 +40,34 @@ func createNFSSpace( fixtureTeardown() }) - return client, space + return client, space, createOpts } -func verifyNFSSpace(t *testing.T, space *linodego.NFSSpace) { +func verifyNFSSpace(t *testing.T, space *linodego.NFSSpace, createOpts linodego.NFSSpaceCreateOptions) { t.Helper() - assert.Equal(t, TestNFSSpaceCreateOptions.Label, space.Label) - assert.Equal(t, TestNFSSpaceCreateOptions.Description, space.Description) - assert.Equal(t, TestNFSSpaceCreateOptions.Tags, linodego.Pointer(space.Tags)) + assert.Equal(t, createOpts.Label, space.Label) + assert.Equal(t, createOpts.Description, space.Description) + assert.Equal(t, createOpts.Tags, linodego.Pointer(space.Tags)) assert.NotNil(t, space.Status) assertDateSet(t, space.Created) assertDateSet(t, space.Updated) } func TestNFSSpace_Create_smoke(t *testing.T) { - _, space := createNFSSpace(t, "fixtures/TestNFSSpace_Create") - verifyNFSSpace(t, space) + _, space, createOpts := createNFSSpace(t, "fixtures/TestNFSSpace_Create") + verifyNFSSpace(t, space, createOpts) } func TestNFSSpace_Get(t *testing.T) { - client, space := createNFSSpace(t, "fixtures/TestNFSSpace_Get") + client, space, createOpts := createNFSSpace(t, "fixtures/TestNFSSpace_Get") spaceGet, err := client.GetNFSSpace(context.Background(), space.ID) require.NoErrorf(t, err, "Error retrieving NFS Space: %v", err) - verifyNFSSpace(t, spaceGet) + verifyNFSSpace(t, spaceGet, createOpts) } func TestNFSSpace_List(t *testing.T) { - client, space := createNFSSpace(t, "fixtures/TestNFSSpace_List") + client, space, createOpts := createNFSSpace(t, "fixtures/TestNFSSpace_List") f := linodego.Filter{} f.AddField(linodego.Eq, "label", space.Label) @@ -77,11 +79,11 @@ func TestNFSSpace_List(t *testing.T) { spaceList, err := client.ListNFSSpaces(context.Background(), &linodego.ListOptions{Filter: string(filter)}) require.NoErrorf(t, err, "Error listing NFS Spaces: %v", err) assert.Len(t, spaceList, 1) - verifyNFSSpace(t, linodego.Pointer(spaceList[0])) + verifyNFSSpace(t, linodego.Pointer(spaceList[0]), createOpts) } func TestNFSSpace_Update(t *testing.T) { - client, space := createNFSSpace(t, "fixtures/TestNFSSpace_Update") + client, space, _ := createNFSSpace(t, "fixtures/TestNFSSpace_Update") updateOpts := linodego.NFSSpaceUpdateOptions{ Label: linodego.Pointer(space.Label + "-updated"), Description: linodego.Pointer("Description updated"), From 67062339fe3f791332638d2a269a1752de5bbe5d Mon Sep 17 00:00:00 2001 From: Maciej Wilk Date: Wed, 7 Oct 2026 15:08:53 +0200 Subject: [PATCH 04/18] Add basic tests for NFS Filesystems --- regions.go | 1 + test/integration/nfs_filesystems_test.go | 139 +++++++++++++++++++++++ test/integration/nfs_spaces_test.go | 12 +- 3 files changed, 146 insertions(+), 6 deletions(-) create mode 100644 test/integration/nfs_filesystems_test.go diff --git a/regions.go b/regions.go index 7a4055260..ccf995dc1 100644 --- a/regions.go +++ b/regions.go @@ -43,6 +43,7 @@ const ( CapabilityMachineImages RegionCapability = "Machine Images" CapabilityMaintenancePolicy RegionCapability = "Maintenance Policy" CapabilityMetadata RegionCapability = "Metadata" + CapabilityNFSStorage RegionCapability = "NFS Storage" CapabilityNLB RegionCapability = "Network LoadBalancer" CapabilityNodeBalancers RegionCapability = "NodeBalancers" CapabilityObjectStorage RegionCapability = "Object Storage" diff --git a/test/integration/nfs_filesystems_test.go b/test/integration/nfs_filesystems_test.go new file mode 100644 index 000000000..fa5e4fba7 --- /dev/null +++ b/test/integration/nfs_filesystems_test.go @@ -0,0 +1,139 @@ +package integration + +import ( + "context" + "testing" + "time" + + "github.com/linode/linodego/v2" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func getNFSFilesystemCreateOptions(t *testing.T, client *linodego.Client) linodego.NFSFilesystemCreateOptions { + return linodego.NFSFilesystemCreateOptions{ + Label: "go-test-nfs-filesystem-mw-" + randLabel(), + Region: getRegionsWithCaps(t, client, []linodego.RegionCapability{linodego.CapabilityNFSStorage})[0], + MaxCapacityBytes: 1099511627776, + Tags: linodego.Pointer([]string{"testing"}), + // MaxFileCount: 1000000, + // ProtocolVersions: linodego.Pointer([]linodego.NFSProtocolVersion{linodego.NFSProtocolVersionV4}), + } +} + +func waitForNFSFilesystemDeleted( + ctx context.Context, + client *linodego.Client, + spaceID int, +) error { + ticker := time.NewTicker(5 * time.Second) + defer ticker.Stop() + + for { + select { + case <-ctx.Done(): + return ctx.Err() + case <-ticker.C: + filesystems, err := client.ListNFSFilesystems(ctx, spaceID, nil) + + if err == nil && len(filesystems) != 0 { + continue + } + + // if API returns [404] Not found, deletion is done + if linodego.IsNotFound(err) { + return nil + } + + return err + } + } +} + +func setupNFSFilesystem( + t *testing.T, + fixtureYaml string, + modifiers ...func(opts *linodego.NFSFilesystemCreateOptions), +) (*linodego.Client, *linodego.NFSSpace, *linodego.NFSFilesystem, linodego.NFSFilesystemCreateOptions) { + t.Helper() + client, fixtureTeardown := createTestClient(t, fixtureYaml) + createOpts := getNFSFilesystemCreateOptions(t, client) + + for _, modifier := range modifiers { + modifier(&createOpts) + } + + spaceCreateOpts := getNFSSpaceCreateOptions() + space, err := client.CreateNFSSpace(context.Background(), spaceCreateOpts) + require.NoErrorf(t, err, "Error creating NFS Space: %v", err) + + filesystem, err := client.CreateNFSFilesystem(context.Background(), space.ID, createOpts) + require.NoErrorf(t, err, "Error creating NFS Filesystem: %v", err) + + t.Cleanup(func() { + ctx, cancel := context.WithTimeout(context.Background(), 90*time.Second) + defer cancel() + + if err = client.DeleteNFSFilesystem(context.Background(), space.ID, filesystem.ID); err != nil { + t.Errorf("Error deleting NFS Filesystem: %v", err) + } + + err = waitForNFSFilesystemDeleted(ctx, client, space.ID) + require.NoErrorf(t, err, "Error waiting for NFS Filesystem to be deleted: %v", err) + + if err = client.DeleteNFSSpace(context.Background(), space.ID); err != nil { + t.Errorf("Error deleting NFS Space: %v", err) + } + + fixtureTeardown() + }) + + return client, space, filesystem, createOpts +} + +func verifyNFSFilesystemBasics(t *testing.T, space *linodego.NFSSpace, filesystem *linodego.NFSFilesystem, createOpts linodego.NFSFilesystemCreateOptions) { + t.Helper() + assert.Equal(t, space.ID, filesystem.SpaceID) + assert.Equal(t, createOpts.Label, filesystem.Label) + assert.Equal(t, createOpts.Region, filesystem.Region) + assert.Equal(t, createOpts.Tags, linodego.Pointer(filesystem.Tags)) + assert.NotNil(t, filesystem.Status) + assertDateSet(t, filesystem.Created) + assertDateSet(t, filesystem.Updated) +} + +func verifyNFSFilesystemDetails(t *testing.T, filesystem *linodego.NFSFilesystem, createOpts linodego.NFSFilesystemCreateOptions) { + t.Helper() + assert.NotEmpty(t, filesystem.ProtocolVersions) + assert.EqualValues(t, createOpts.MaxCapacityBytes, filesystem.MaxCapacityBytes) + assert.NotEmpty(t, filesystem.MountTargetIPs) + assert.NotNil(t, filesystem.MountTargetFQDN) + assert.NotNil(t, filesystem.Stats) + //assert.NotNil(t, filesystem.SnapshotUsageBytes) + //assert.NotNil(t, filesystem.LDAPConfigID) + //assert.NotNil(t, filesystem.SourceSnapshotID) +} + +func TestNFSFilesystem_Create_smoke(t *testing.T) { + _, space, filesystem, createOpts := setupNFSFilesystem(t, "fixtures/TestNFSFilesystem_Create") + verifyNFSFilesystemBasics(t, space, filesystem, createOpts) +} + +func TestNFSFilesystem_Get(t *testing.T) { + ctx := waitContext(t, 180*time.Second) + client, space, filesystem, createOpts := setupNFSFilesystem(t, "fixtures/TestNFSFilesystem_Get") + verifyNFSFilesystemBasics(t, space, filesystem, createOpts) + + // Wait for NFS Filesystem status to be 'active' + _, err := client.WaitForNFSFilesystemStatus( + ctx, + space.ID, + filesystem.ID, + linodego.NFSFilesystemStatusActive, + ) + require.NoErrorf(t, err, "Failed to wait for Filesystem status to be active: %s", err) + + filesystem, err = client.GetNFSFilesystemInSpace(context.Background(), space.ID, filesystem.ID) + require.NoErrorf(t, err, "Error retrieving NFS Filesystem in Space: %v", err) + verifyNFSFilesystemDetails(t, filesystem, createOpts) +} diff --git a/test/integration/nfs_spaces_test.go b/test/integration/nfs_spaces_test.go index 6e908876a..8d4f2edb0 100644 --- a/test/integration/nfs_spaces_test.go +++ b/test/integration/nfs_spaces_test.go @@ -17,7 +17,7 @@ func getNFSSpaceCreateOptions() linodego.NFSSpaceCreateOptions { } } -func createNFSSpace( +func setupNFSSpace( t *testing.T, fixtureYaml string, modifiers ...func(opts *linodego.NFSSpaceCreateOptions), @@ -34,7 +34,7 @@ func createNFSSpace( require.NoErrorf(t, err, "Error creating NFS Space: %v", err) t.Cleanup(func() { - if err := client.DeleteNFSSpace(context.Background(), space.ID); err != nil { + if err = client.DeleteNFSSpace(context.Background(), space.ID); err != nil { t.Errorf("Error deleting NFS Space: %v", err) } fixtureTeardown() @@ -54,12 +54,12 @@ func verifyNFSSpace(t *testing.T, space *linodego.NFSSpace, createOpts linodego. } func TestNFSSpace_Create_smoke(t *testing.T) { - _, space, createOpts := createNFSSpace(t, "fixtures/TestNFSSpace_Create") + _, space, createOpts := setupNFSSpace(t, "fixtures/TestNFSSpace_Create") verifyNFSSpace(t, space, createOpts) } func TestNFSSpace_Get(t *testing.T) { - client, space, createOpts := createNFSSpace(t, "fixtures/TestNFSSpace_Get") + client, space, createOpts := setupNFSSpace(t, "fixtures/TestNFSSpace_Get") spaceGet, err := client.GetNFSSpace(context.Background(), space.ID) require.NoErrorf(t, err, "Error retrieving NFS Space: %v", err) @@ -67,7 +67,7 @@ func TestNFSSpace_Get(t *testing.T) { } func TestNFSSpace_List(t *testing.T) { - client, space, createOpts := createNFSSpace(t, "fixtures/TestNFSSpace_List") + client, space, createOpts := setupNFSSpace(t, "fixtures/TestNFSSpace_List") f := linodego.Filter{} f.AddField(linodego.Eq, "label", space.Label) @@ -83,7 +83,7 @@ func TestNFSSpace_List(t *testing.T) { } func TestNFSSpace_Update(t *testing.T) { - client, space, _ := createNFSSpace(t, "fixtures/TestNFSSpace_Update") + client, space, _ := setupNFSSpace(t, "fixtures/TestNFSSpace_Update") updateOpts := linodego.NFSSpaceUpdateOptions{ Label: linodego.Pointer(space.Label + "-updated"), Description: linodego.Pointer("Description updated"), From cd64b0a205c2ca00a8850ccef56f20def0502af3 Mon Sep 17 00:00:00 2001 From: Maciej Wilk Date: Wed, 7 Oct 2026 16:42:21 +0200 Subject: [PATCH 05/18] Add more tests for NFS filesystem --- nfs_filesystems.go | 10 ++-- test/integration/nfs_filesystems_test.go | 58 +++++++++++++++++++++--- 2 files changed, 56 insertions(+), 12 deletions(-) diff --git a/nfs_filesystems.go b/nfs_filesystems.go index 3961dbf17..16077bdd8 100644 --- a/nfs_filesystems.go +++ b/nfs_filesystems.go @@ -63,9 +63,9 @@ type NFSFilesystemCreateOptions struct { // NFSFilesystemUpdateOptions contains fields accepted when updating an NFS Filesystem. type NFSFilesystemUpdateOptions struct { - Label *string `json:"label,omitzero"` - MaxCapacityBytes *int64 `json:"max_capacity_bytes,omitzero"` - Tags *[]string `json:"tags,omitzero"` + Label *string `json:"label,omitzero"` + // MaxCapacityBytes *int64 `json:"max_capacity_bytes,omitzero"` // TODO: Currently API says it is not editable field + Tags *[]string `json:"tags,omitzero"` } // NFSFilesystemStats represents collected NFS Filesystem usage statistics. @@ -141,8 +141,8 @@ func (n NFSFilesystem) GetCreateOptions() NFSFilesystemCreateOptions { // GetUpdateOptions returns the NFS Filesystem fields accepted by UpdateNFSFilesystem. func (n NFSFilesystem) GetUpdateOptions() NFSFilesystemUpdateOptions { result := NFSFilesystemUpdateOptions{ - Label: Pointer(n.Label), - MaxCapacityBytes: Pointer(n.MaxCapacityBytes), + Label: Pointer(n.Label), + // MaxCapacityBytes: Pointer(n.MaxCapacityBytes), // TODO: Currently API says it is not editable field } if n.Tags != nil { diff --git a/test/integration/nfs_filesystems_test.go b/test/integration/nfs_filesystems_test.go index fa5e4fba7..d9d0efd84 100644 --- a/test/integration/nfs_filesystems_test.go +++ b/test/integration/nfs_filesystems_test.go @@ -12,7 +12,7 @@ import ( func getNFSFilesystemCreateOptions(t *testing.T, client *linodego.Client) linodego.NFSFilesystemCreateOptions { return linodego.NFSFilesystemCreateOptions{ - Label: "go-test-nfs-filesystem-mw-" + randLabel(), + Label: "go-test-nfs-filesystem-" + randLabel(), Region: getRegionsWithCaps(t, client, []linodego.RegionCapability{linodego.CapabilityNFSStorage})[0], MaxCapacityBytes: 1099511627776, Tags: linodego.Pointer([]string{"testing"}), @@ -109,9 +109,9 @@ func verifyNFSFilesystemDetails(t *testing.T, filesystem *linodego.NFSFilesystem assert.NotEmpty(t, filesystem.MountTargetIPs) assert.NotNil(t, filesystem.MountTargetFQDN) assert.NotNil(t, filesystem.Stats) - //assert.NotNil(t, filesystem.SnapshotUsageBytes) - //assert.NotNil(t, filesystem.LDAPConfigID) - //assert.NotNil(t, filesystem.SourceSnapshotID) + // assert.NotNil(t, filesystem.SnapshotUsageBytes) + // assert.NotNil(t, filesystem.LDAPConfigID) + // assert.NotNil(t, filesystem.SourceSnapshotID) } func TestNFSFilesystem_Create_smoke(t *testing.T) { @@ -122,7 +122,6 @@ func TestNFSFilesystem_Create_smoke(t *testing.T) { func TestNFSFilesystem_Get(t *testing.T) { ctx := waitContext(t, 180*time.Second) client, space, filesystem, createOpts := setupNFSFilesystem(t, "fixtures/TestNFSFilesystem_Get") - verifyNFSFilesystemBasics(t, space, filesystem, createOpts) // Wait for NFS Filesystem status to be 'active' _, err := client.WaitForNFSFilesystemStatus( @@ -133,7 +132,52 @@ func TestNFSFilesystem_Get(t *testing.T) { ) require.NoErrorf(t, err, "Failed to wait for Filesystem status to be active: %s", err) - filesystem, err = client.GetNFSFilesystemInSpace(context.Background(), space.ID, filesystem.ID) + filesystemGet, err := client.GetNFSFilesystemInSpace(context.Background(), space.ID, filesystem.ID) require.NoErrorf(t, err, "Error retrieving NFS Filesystem in Space: %v", err) - verifyNFSFilesystemDetails(t, filesystem, createOpts) + verifyNFSFilesystemBasics(t, space, filesystemGet, createOpts) + verifyNFSFilesystemDetails(t, filesystemGet, createOpts) +} + +func TestNFSFilesystem_GetWithoutNFSSpace(t *testing.T) { + client, space, filesystem, createOpts := setupNFSFilesystem(t, "fixtures/TestNFSFilesystem_GetWithoutNFSSpace") + + filesystemGet, err := client.GetNFSFilesystem(context.Background(), filesystem.ID) + require.NoErrorf(t, err, "Error retrieving NFS Filesystem with no Space: %v", err) + verifyNFSFilesystemBasics(t, space, filesystemGet, createOpts) +} + +func TestNFSFilesystem_List(t *testing.T) { + client, space, filesystem, createOpts := setupNFSFilesystem(t, "fixtures/TestNFSFilesystem_List") + + f := linodego.Filter{} + f.AddField(linodego.Eq, "label", filesystem.Label) + filter, err := f.MarshalJSON() + if err != nil { + t.Fatalf("Failed to marshal filter: %v", err) + } + + filesystemList, err := client.ListNFSFilesystems(context.Background(), space.ID, &linodego.ListOptions{Filter: string(filter)}) + require.NoErrorf(t, err, "Error listing NFS Spaces: %v", err) + assert.Len(t, filesystemList, 1) + verifyNFSFilesystemBasics(t, space, linodego.Pointer(filesystemList[0]), createOpts) +} + +func TestNFSFilesystem_Update(t *testing.T) { + client, space, filesystem, createOpts := setupNFSFilesystem(t, "fixtures/TestNFSFilesystem_List") + + updateOpts := filesystem.GetUpdateOptions() + updateOpts.Label = linodego.Pointer(filesystem.Label + "-updated") + updateOpts.Tags = linodego.Pointer([]string{"updated"}) + // updateOpts.MaxCapacityBytes = linodego.Pointer(int64(1073741824)) // TODO: Currently API says it is not editable field + + filesystemUpdate, err := client.UpdateNFSFilesystem(context.Background(), space.ID, filesystem.ID, updateOpts) + require.NoErrorf(t, err, "Error updating NFS Space: %v", err) + + verifyOpts := linodego.NFSFilesystemCreateOptions{ + Label: *updateOpts.Label, + Region: createOpts.Region, + Tags: updateOpts.Tags, + // MaxCapacityBytes: *updateOpts.MaxCapacityBytes, // TODO: Currently API says it is not editable field + } + verifyNFSFilesystemBasics(t, space, filesystemUpdate, verifyOpts) } From 93aa45da1e93a57dc4ed2f363feb06ca40adc74a Mon Sep 17 00:00:00 2001 From: Maciej Wilk Date: Wed, 7 Oct 2026 16:43:31 +0200 Subject: [PATCH 06/18] Modify TestNFSSpace_Update and use GetUpdateOptions function --- test/integration/nfs_spaces_test.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/integration/nfs_spaces_test.go b/test/integration/nfs_spaces_test.go index 8d4f2edb0..826f57e8e 100644 --- a/test/integration/nfs_spaces_test.go +++ b/test/integration/nfs_spaces_test.go @@ -84,11 +84,11 @@ func TestNFSSpace_List(t *testing.T) { func TestNFSSpace_Update(t *testing.T) { client, space, _ := setupNFSSpace(t, "fixtures/TestNFSSpace_Update") - updateOpts := linodego.NFSSpaceUpdateOptions{ - Label: linodego.Pointer(space.Label + "-updated"), - Description: linodego.Pointer("Description updated"), - Tags: linodego.Pointer([]string{"updated"}), - } + + updateOpts := space.GetUpdateOptions() + updateOpts.Label = linodego.Pointer(space.Label + "-updated") + updateOpts.Description = linodego.Pointer("Description updated") + updateOpts.Tags = linodego.Pointer([]string{"updated"}) spaceUpdate, err := client.UpdateNFSSpace(context.Background(), space.ID, updateOpts) require.NoErrorf(t, err, "Error updating NFS Space: %v", err) From ca64c6b72a5e3b380c5ea009729774671d749414 Mon Sep 17 00:00:00 2001 From: Maciej Wilk Date: Thu, 8 Oct 2026 10:49:13 +0200 Subject: [PATCH 07/18] Add draft of Space Access Policy tests --- test/integration/nfs_spaces_test.go | 52 +++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/test/integration/nfs_spaces_test.go b/test/integration/nfs_spaces_test.go index 826f57e8e..923a38a3d 100644 --- a/test/integration/nfs_spaces_test.go +++ b/test/integration/nfs_spaces_test.go @@ -96,3 +96,55 @@ func TestNFSSpace_Update(t *testing.T) { assert.Equal(t, updateOpts.Description, spaceUpdate.Description) assert.Equal(t, updateOpts.Tags, linodego.Pointer(spaceUpdate.Tags)) } + +func TestNFSSpace_GetAccessPolicy_smoke(t *testing.T) { + //t.Skip("Access Policy is now fully developed yet") + client, space, _ := setupNFSSpace(t, "fixtures/TestNFSSpace_GetAccessPolicy") + + spaceAccPolicy, err := client.GetNFSSpaceAccessPolicy(context.Background(), space.ID) + require.NoErrorf(t, err, "Error getting NFS Space Access Policy: %v", err) + + assert.Equal(t, space.ID, spaceAccPolicy.SpaceID) + assert.Equal(t, space.Label, spaceAccPolicy.Label) + assert.Equal(t, linodego.NFSAccessPolicyStatusActive, spaceAccPolicy.Status) + assertDateSet(t, spaceAccPolicy.Created) + assert.Nil(t, spaceAccPolicy.Updated) +} + +func TestNFSSpace_UpdateAccessPolicy(t *testing.T) { + //t.Skip("Access Policy is now fully developed yet") + client, space, _ := setupNFSSpace(t, "fixtures/TestNFSSpace_UpdateAccessPolicy") + + vpc, _, vpcTeardown, err := createVPC(t, client, []vpcModifier{func(l *linodego.Client, opts *linodego.VPCCreateOptions) { + opts.Region = getRegionsWithCaps(t, client, []linodego.RegionCapability{linodego.CapabilityVPCs, linodego.CapabilityNFSStorage})[0] + }}...) + t.Cleanup(vpcTeardown) + require.NoErrorf(t, err, "Error creating VPC for Access Policy: %v", err) + + updateOpts := linodego.NFSSpaceAccessPolicyUpdateOptions{ + Label: linodego.Pointer(space.Label + "-updated"), + Enabled: linodego.Pointer(true), + VPCs: linodego.Pointer([]linodego.NFSSpaceAccessPolicyVPCOptions{ + { + ID: vpc.ID, + }, + }), + // MTLSCACert: linodego.Pointer("Test CA Certificate"), + MTLSMode: linodego.Pointer(linodego.NFSMTLSModeOptional), + } + + spaceAccPolicyUpdate, err := client.UpdateNFSSpaceAccessPolicy(context.Background(), space.ID, updateOpts) + require.NoErrorf(t, err, "Error updating NFS Space Access Policy: %v", err) + assert.Equal(t, space.ID, spaceAccPolicyUpdate.SpaceID) + // assert.Equal(t, updateOpts.Label, linodego.Pointer(spaceAccPolicyUpdate.Label)) + assert.True(t, spaceAccPolicyUpdate.Enabled) + assert.Equal(t, vpc.ID, spaceAccPolicyUpdate.VPCACL[0].ID) + assert.Nil(t, spaceAccPolicyUpdate.MTLSCACert) + assert.Equal(t, linodego.NFSMTLSModeOptional, spaceAccPolicyUpdate.MTLSMode) + // assert.Equal(t, "pending", spaceAccPolicyUpdate.Status) + assertDateSet(t, spaceAccPolicyUpdate.Updated) + + //spaceAccPolicy, err := client.GetNFSSpaceAccessPolicy(context.Background(), space.ID) + //require.NoErrorf(t, err, "Error getting NFS Space Access Policy: %v", err) + //assert.Equal(t, linodego.NFSAccessPolicyStatusActive, spaceAccPolicy.Status) +} From 7be5392d1d2dec586a71f4f96bfae83f40e0f84d Mon Sep 17 00:00:00 2001 From: Maciej Wilk Date: Thu, 8 Oct 2026 10:50:59 +0200 Subject: [PATCH 08/18] Add MaxFileCount field to NFSFilesystem structs --- nfs_filesystems.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/nfs_filesystems.go b/nfs_filesystems.go index 16077bdd8..77606d5f5 100644 --- a/nfs_filesystems.go +++ b/nfs_filesystems.go @@ -43,6 +43,7 @@ type NFSFilesystem struct { MountTargetIPs []string `json:"mount_target_ips"` MountTargetFQDN *string `json:"mount_target_fqdn"` MaxCapacityBytes int64 `json:"max_capacity_bytes"` + MaxFileCount int64 `json:"max_file_count"` SnapshotUsageBytes *int64 `json:"snapshot_usage_bytes"` LDAPConfigID *string `json:"ldap_config_id"` SourceSnapshotID *int `json:"source_snapshot_id"` @@ -57,6 +58,7 @@ type NFSFilesystemCreateOptions struct { Label string `json:"label"` Region string `json:"region"` MaxCapacityBytes int64 `json:"max_capacity_bytes"` + MaxFileCount *int64 `json:"max_file_count,omitzero"` ProtocolVersions *[]NFSProtocolVersion `json:"protocol_versions,omitzero"` Tags *[]string `json:"tags,omitzero"` } @@ -65,6 +67,7 @@ type NFSFilesystemCreateOptions struct { type NFSFilesystemUpdateOptions struct { Label *string `json:"label,omitzero"` // MaxCapacityBytes *int64 `json:"max_capacity_bytes,omitzero"` // TODO: Currently API says it is not editable field + // MaxFileCount *int64 `json:"max_file_count,omitzero"` // TODO: Currently API says it is not editable field Tags *[]string `json:"tags,omitzero"` } @@ -125,6 +128,7 @@ func (n NFSFilesystem) GetCreateOptions() NFSFilesystemCreateOptions { Label: n.Label, Region: n.Region, MaxCapacityBytes: n.MaxCapacityBytes, + MaxFileCount: Pointer(n.MaxFileCount), } if n.ProtocolVersions != nil { @@ -143,6 +147,7 @@ func (n NFSFilesystem) GetUpdateOptions() NFSFilesystemUpdateOptions { result := NFSFilesystemUpdateOptions{ Label: Pointer(n.Label), // MaxCapacityBytes: Pointer(n.MaxCapacityBytes), // TODO: Currently API says it is not editable field + // MaxFileCount: Pointer(n.MaxFileCount), // TODO: Currently API says it is not editable field } if n.Tags != nil { From 2b478d27c2242f243ad2eda28995c7b197186011 Mon Sep 17 00:00:00 2001 From: Maciej Wilk Date: Thu, 8 Oct 2026 10:52:26 +0200 Subject: [PATCH 09/18] Modify NFS Filesystem tests to use and check MaxFileCount --- test/integration/nfs_filesystems_test.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/test/integration/nfs_filesystems_test.go b/test/integration/nfs_filesystems_test.go index d9d0efd84..6fda1acf8 100644 --- a/test/integration/nfs_filesystems_test.go +++ b/test/integration/nfs_filesystems_test.go @@ -16,8 +16,8 @@ func getNFSFilesystemCreateOptions(t *testing.T, client *linodego.Client) linode Region: getRegionsWithCaps(t, client, []linodego.RegionCapability{linodego.CapabilityNFSStorage})[0], MaxCapacityBytes: 1099511627776, Tags: linodego.Pointer([]string{"testing"}), - // MaxFileCount: 1000000, - // ProtocolVersions: linodego.Pointer([]linodego.NFSProtocolVersion{linodego.NFSProtocolVersionV4}), + MaxFileCount: linodego.Pointer(int64(1500)), + ProtocolVersions: linodego.Pointer([]linodego.NFSProtocolVersion{linodego.NFSProtocolVersionV4}), } } @@ -106,9 +106,11 @@ func verifyNFSFilesystemDetails(t *testing.T, filesystem *linodego.NFSFilesystem t.Helper() assert.NotEmpty(t, filesystem.ProtocolVersions) assert.EqualValues(t, createOpts.MaxCapacityBytes, filesystem.MaxCapacityBytes) + assert.EqualValues(t, createOpts.MaxFileCount, linodego.Pointer(filesystem.MaxFileCount)) assert.NotEmpty(t, filesystem.MountTargetIPs) assert.NotNil(t, filesystem.MountTargetFQDN) assert.NotNil(t, filesystem.Stats) + // TODO: Specified in API docs, but not available in API itself yet // assert.NotNil(t, filesystem.SnapshotUsageBytes) // assert.NotNil(t, filesystem.LDAPConfigID) // assert.NotNil(t, filesystem.SourceSnapshotID) @@ -123,7 +125,7 @@ func TestNFSFilesystem_Get(t *testing.T) { ctx := waitContext(t, 180*time.Second) client, space, filesystem, createOpts := setupNFSFilesystem(t, "fixtures/TestNFSFilesystem_Get") - // Wait for NFS Filesystem status to be 'active' + // Wait for NFS Filesystem status to be 'active' to read the details _, err := client.WaitForNFSFilesystemStatus( ctx, space.ID, @@ -163,12 +165,13 @@ func TestNFSFilesystem_List(t *testing.T) { } func TestNFSFilesystem_Update(t *testing.T) { - client, space, filesystem, createOpts := setupNFSFilesystem(t, "fixtures/TestNFSFilesystem_List") + client, space, filesystem, createOpts := setupNFSFilesystem(t, "fixtures/TestNFSFilesystem_Update") updateOpts := filesystem.GetUpdateOptions() updateOpts.Label = linodego.Pointer(filesystem.Label + "-updated") updateOpts.Tags = linodego.Pointer([]string{"updated"}) // updateOpts.MaxCapacityBytes = linodego.Pointer(int64(1073741824)) // TODO: Currently API says it is not editable field + // updateOpts.MaxCountFile = linodego.Pointer(int64(2500)) // TODO: Currently API says it is not editable field filesystemUpdate, err := client.UpdateNFSFilesystem(context.Background(), space.ID, filesystem.ID, updateOpts) require.NoErrorf(t, err, "Error updating NFS Space: %v", err) @@ -178,6 +181,7 @@ func TestNFSFilesystem_Update(t *testing.T) { Region: createOpts.Region, Tags: updateOpts.Tags, // MaxCapacityBytes: *updateOpts.MaxCapacityBytes, // TODO: Currently API says it is not editable field + // MaxFileCount: *updateOpts.MaxCountFile, // TODO: Currently API says it is not editable field } verifyNFSFilesystemBasics(t, space, filesystemUpdate, verifyOpts) } From d74d0aac4fd7ef67a468b628380ffe6cc75d68c1 Mon Sep 17 00:00:00 2001 From: Maciej Wilk Date: Thu, 8 Oct 2026 12:56:21 +0200 Subject: [PATCH 10/18] Add wait and assert func for Space Access Policy tests --- test/integration/nfs_spaces_test.go | 45 +++++++++++++++++++---------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/test/integration/nfs_spaces_test.go b/test/integration/nfs_spaces_test.go index 923a38a3d..a26bd4c34 100644 --- a/test/integration/nfs_spaces_test.go +++ b/test/integration/nfs_spaces_test.go @@ -3,6 +3,7 @@ package integration import ( "context" "testing" + "time" "github.com/linode/linodego/v2" "github.com/stretchr/testify/assert" @@ -53,6 +54,17 @@ func verifyNFSSpace(t *testing.T, space *linodego.NFSSpace, createOpts linodego. assertDateSet(t, space.Updated) } +func verifyNFSSpaceAccessPolicyUpdate(t *testing.T, spaceAccPolicy *linodego.NFSSpaceAccessPolicy, opts linodego.NFSSpaceAccessPolicyUpdateOptions) { + // assert.Equal(t, "pending", spaceAccPolicy.Status) + // assert.Equal(t, updateOpts.Label, linodego.Pointer(spaceAccPolicy.Label)) // TODO: It is not updated - defect? + assert.True(t, spaceAccPolicy.Enabled) + assert.Len(t, spaceAccPolicy.VPCACL, 1) + assert.Equal(t, (*opts.VPCs)[0].ID, spaceAccPolicy.VPCACL[0].ID) + assert.Nil(t, spaceAccPolicy.MTLSCACert) + assert.Equal(t, linodego.NFSMTLSModeOptional, spaceAccPolicy.MTLSMode) + assertDateSet(t, spaceAccPolicy.Updated) +} + func TestNFSSpace_Create_smoke(t *testing.T) { _, space, createOpts := setupNFSSpace(t, "fixtures/TestNFSSpace_Create") verifyNFSSpace(t, space, createOpts) @@ -98,12 +110,11 @@ func TestNFSSpace_Update(t *testing.T) { } func TestNFSSpace_GetAccessPolicy_smoke(t *testing.T) { - //t.Skip("Access Policy is now fully developed yet") + t.Skip("Access Policy is now fully developed yet") client, space, _ := setupNFSSpace(t, "fixtures/TestNFSSpace_GetAccessPolicy") spaceAccPolicy, err := client.GetNFSSpaceAccessPolicy(context.Background(), space.ID) require.NoErrorf(t, err, "Error getting NFS Space Access Policy: %v", err) - assert.Equal(t, space.ID, spaceAccPolicy.SpaceID) assert.Equal(t, space.Label, spaceAccPolicy.Label) assert.Equal(t, linodego.NFSAccessPolicyStatusActive, spaceAccPolicy.Status) @@ -112,14 +123,14 @@ func TestNFSSpace_GetAccessPolicy_smoke(t *testing.T) { } func TestNFSSpace_UpdateAccessPolicy(t *testing.T) { - //t.Skip("Access Policy is now fully developed yet") + t.Skip("Access Policy is now fully developed yet") client, space, _ := setupNFSSpace(t, "fixtures/TestNFSSpace_UpdateAccessPolicy") vpc, _, vpcTeardown, err := createVPC(t, client, []vpcModifier{func(l *linodego.Client, opts *linodego.VPCCreateOptions) { opts.Region = getRegionsWithCaps(t, client, []linodego.RegionCapability{linodego.CapabilityVPCs, linodego.CapabilityNFSStorage})[0] }}...) - t.Cleanup(vpcTeardown) require.NoErrorf(t, err, "Error creating VPC for Access Policy: %v", err) + t.Cleanup(vpcTeardown) updateOpts := linodego.NFSSpaceAccessPolicyUpdateOptions{ Label: linodego.Pointer(space.Label + "-updated"), @@ -135,16 +146,18 @@ func TestNFSSpace_UpdateAccessPolicy(t *testing.T) { spaceAccPolicyUpdate, err := client.UpdateNFSSpaceAccessPolicy(context.Background(), space.ID, updateOpts) require.NoErrorf(t, err, "Error updating NFS Space Access Policy: %v", err) - assert.Equal(t, space.ID, spaceAccPolicyUpdate.SpaceID) - // assert.Equal(t, updateOpts.Label, linodego.Pointer(spaceAccPolicyUpdate.Label)) - assert.True(t, spaceAccPolicyUpdate.Enabled) - assert.Equal(t, vpc.ID, spaceAccPolicyUpdate.VPCACL[0].ID) - assert.Nil(t, spaceAccPolicyUpdate.MTLSCACert) - assert.Equal(t, linodego.NFSMTLSModeOptional, spaceAccPolicyUpdate.MTLSMode) - // assert.Equal(t, "pending", spaceAccPolicyUpdate.Status) - assertDateSet(t, spaceAccPolicyUpdate.Updated) - - //spaceAccPolicy, err := client.GetNFSSpaceAccessPolicy(context.Background(), space.ID) - //require.NoErrorf(t, err, "Error getting NFS Space Access Policy: %v", err) - //assert.Equal(t, linodego.NFSAccessPolicyStatusActive, spaceAccPolicy.Status) + verifyNFSSpaceAccessPolicyUpdate(t, spaceAccPolicyUpdate, updateOpts) + + // Wait for NFS Space Access Policy status to be 'active' to read the details + ctx := waitContext(t, 180*time.Second) + _, err = client.WaitForNFSSpaceAccessPolicyStatus( + ctx, + space.ID, + linodego.NFSAccessPolicyStatusActive, + ) + require.NoErrorf(t, err, "Failed to wait for Space Access Policy status: %s", err) + + spaceAccPolicyGet, err := client.GetNFSSpaceAccessPolicy(context.Background(), space.ID) + require.NoErrorf(t, err, "Error getting NFS Space Access Policy: %v", err) + verifyNFSSpaceAccessPolicyUpdate(t, spaceAccPolicyGet, updateOpts) } From 871a70c2d4d891dd12b6e308fa7c4cd2388d542c Mon Sep 17 00:00:00 2001 From: Maciej Wilk Date: Thu, 8 Oct 2026 12:58:06 +0200 Subject: [PATCH 11/18] Add Filesystem Access Policy tests --- test/integration/nfs_filesystems_test.go | 72 ++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/test/integration/nfs_filesystems_test.go b/test/integration/nfs_filesystems_test.go index 6fda1acf8..4ef4f1f1f 100644 --- a/test/integration/nfs_filesystems_test.go +++ b/test/integration/nfs_filesystems_test.go @@ -116,6 +116,18 @@ func verifyNFSFilesystemDetails(t *testing.T, filesystem *linodego.NFSFilesystem // assert.NotNil(t, filesystem.SourceSnapshotID) } +func verifyNFSFilesystemAccessPolicyUpdate( + t *testing.T, + filesystemAccPolicy *linodego.NFSFilesystemAccessPolicy, + opts linodego.NFSFilesystemAccessPolicyUpdateOptions, +) { + // assert.Equal(t, *updateOpts.Label, filesystemAccPolicy.Label) // TODO: It is not updated - defect? + assert.True(t, filesystemAccPolicy.Enabled) + assert.Len(t, filesystemAccPolicy.LinodeACL, 1) + assert.Equal(t, (*opts.LinodeIDs)[0], filesystemAccPolicy.LinodeACL[0].ID) + assertDateSet(t, filesystemAccPolicy.Updated) +} + func TestNFSFilesystem_Create_smoke(t *testing.T) { _, space, filesystem, createOpts := setupNFSFilesystem(t, "fixtures/TestNFSFilesystem_Create") verifyNFSFilesystemBasics(t, space, filesystem, createOpts) @@ -185,3 +197,63 @@ func TestNFSFilesystem_Update(t *testing.T) { } verifyNFSFilesystemBasics(t, space, filesystemUpdate, verifyOpts) } + +func TestNFSFilesystem_GetAccessPolicy_smoke(t *testing.T) { + client, space, filesystem, _ := setupNFSFilesystem(t, "fixtures/TestNFSFilesystem_GetAccessPolicy") + + filesystemAccPolicy, err := client.GetNFSFilesystemAccessPolicy(context.Background(), space.ID, filesystem.ID) + require.NoErrorf(t, err, "Error getting NFS Filesystem Access Policy: %v", err) + assert.Equal(t, filesystem.ID, filesystemAccPolicy.FilesystemID) + assert.Equal(t, filesystem.Label, filesystemAccPolicy.Label) + assert.False(t, filesystemAccPolicy.Enabled) + // assert.False(t, filesystemAccPolicy.Inherit) // TODO: No Inherit field in API spec, but returned by API response + assert.NotEmpty(t, filesystemAccPolicy.Protocols) + assert.Empty(t, filesystemAccPolicy.LinodeACL) + assert.NotNil(t, filesystemAccPolicy.SquashPolicy) + assert.Equal(t, linodego.NFSAccessPolicyStatusActive, filesystemAccPolicy.Status) + assertDateSet(t, filesystemAccPolicy.Created) + assert.Nil(t, filesystemAccPolicy.Updated) +} + +func TestNFSFilesystem_UpdateAccessPolicy(t *testing.T) { + client, space, filesystem, _ := setupNFSFilesystem(t, "fixtures/TestNFSFilesystem_UpdateAccessPolicy") + + linode, _, linodeTeardown, err := createInstanceWithoutDisks( + t, + client, + true, + func(client *linodego.Client, opts *linodego.InstanceCreateOptions) { + opts.Region = filesystem.Region + }) + require.NoErrorf(t, err, "Error creating Linode for NFS Filesystem Access Policy: %v", err) + t.Cleanup(linodeTeardown) + + updateOpts := linodego.NFSFilesystemAccessPolicyUpdateOptions{ + Label: linodego.Pointer(filesystem.Label + "-updated"), + Enabled: linodego.Pointer(true), + LinodeIDs: linodego.Pointer([]int{linode.ID}), + } + + filesystemAccPolicyUpdate, err := client.UpdateNFSFilesystemAccessPolicy( + context.Background(), + space.ID, + filesystem.ID, + updateOpts, + ) + require.NoErrorf(t, err, "Error updating NFS Filesystem Access Policy: %v", err) + verifyNFSFilesystemAccessPolicyUpdate(t, filesystemAccPolicyUpdate, updateOpts) + + // Wait for NFS Filesystem Access Policy status to be 'active' to read the details + ctx := waitContext(t, 180*time.Second) + _, err = client.WaitForNFSFilesystemAccessPolicyStatus( + ctx, + space.ID, + filesystem.ID, + linodego.NFSAccessPolicyStatusActive, + ) + require.NoErrorf(t, err, "Failed to wait for Filesystem Access Policy status: %s", err) + + filesystemAccPolicyGet, err := client.GetNFSFilesystemAccessPolicy(context.Background(), space.ID, filesystem.ID) + require.NoErrorf(t, err, "Error getting NFS Filesystem Access Policy: %v", err) + verifyNFSFilesystemAccessPolicyUpdate(t, filesystemAccPolicyGet, updateOpts) +} From f6a621f5be81b53f14ccbe0849d3e03fbd411496 Mon Sep 17 00:00:00 2001 From: Maciej Wilk Date: Thu, 8 Oct 2026 13:14:35 +0200 Subject: [PATCH 12/18] Add skip for Access Policy tests --- test/integration/nfs_filesystems_test.go | 2 ++ test/integration/nfs_spaces_test.go | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/test/integration/nfs_filesystems_test.go b/test/integration/nfs_filesystems_test.go index 4ef4f1f1f..0dcc3d64b 100644 --- a/test/integration/nfs_filesystems_test.go +++ b/test/integration/nfs_filesystems_test.go @@ -199,6 +199,7 @@ func TestNFSFilesystem_Update(t *testing.T) { } func TestNFSFilesystem_GetAccessPolicy_smoke(t *testing.T) { + t.Skip("Access Policy seems to not be fully developed yet") client, space, filesystem, _ := setupNFSFilesystem(t, "fixtures/TestNFSFilesystem_GetAccessPolicy") filesystemAccPolicy, err := client.GetNFSFilesystemAccessPolicy(context.Background(), space.ID, filesystem.ID) @@ -216,6 +217,7 @@ func TestNFSFilesystem_GetAccessPolicy_smoke(t *testing.T) { } func TestNFSFilesystem_UpdateAccessPolicy(t *testing.T) { + t.Skip("Access Policy seems to not be fully developed yet") client, space, filesystem, _ := setupNFSFilesystem(t, "fixtures/TestNFSFilesystem_UpdateAccessPolicy") linode, _, linodeTeardown, err := createInstanceWithoutDisks( diff --git a/test/integration/nfs_spaces_test.go b/test/integration/nfs_spaces_test.go index a26bd4c34..3d04dd7b3 100644 --- a/test/integration/nfs_spaces_test.go +++ b/test/integration/nfs_spaces_test.go @@ -110,7 +110,7 @@ func TestNFSSpace_Update(t *testing.T) { } func TestNFSSpace_GetAccessPolicy_smoke(t *testing.T) { - t.Skip("Access Policy is now fully developed yet") + t.Skip("Access Policy seems to not be fully developed yet") client, space, _ := setupNFSSpace(t, "fixtures/TestNFSSpace_GetAccessPolicy") spaceAccPolicy, err := client.GetNFSSpaceAccessPolicy(context.Background(), space.ID) @@ -123,7 +123,7 @@ func TestNFSSpace_GetAccessPolicy_smoke(t *testing.T) { } func TestNFSSpace_UpdateAccessPolicy(t *testing.T) { - t.Skip("Access Policy is now fully developed yet") + t.Skip("Access Policy seems to not be fully developed yet") client, space, _ := setupNFSSpace(t, "fixtures/TestNFSSpace_UpdateAccessPolicy") vpc, _, vpcTeardown, err := createVPC(t, client, []vpcModifier{func(l *linodego.Client, opts *linodego.VPCCreateOptions) { From 37a0b2a39ef58f319dec2e25924d4997c147b4e0 Mon Sep 17 00:00:00 2001 From: Maciej Wilk Date: Mon, 12 Oct 2026 12:40:32 +0200 Subject: [PATCH 13/18] Remove Label from Access Policy update options Labels are only able to be updated through the Space and Filesystem PUT requests --- nfs_access_policies.go | 2 -- test/integration/nfs_filesystems_test.go | 2 -- test/integration/nfs_spaces_test.go | 2 -- 3 files changed, 6 deletions(-) diff --git a/nfs_access_policies.go b/nfs_access_policies.go index 447304bef..9377c4890 100644 --- a/nfs_access_policies.go +++ b/nfs_access_policies.go @@ -94,7 +94,6 @@ type NFSSpaceAccessPolicy struct { // NFSSpaceAccessPolicyUpdateOptions contains fields accepted when updating an NFS Space access policy. type NFSSpaceAccessPolicyUpdateOptions struct { - Label *string `json:"label,omitzero"` Enabled *bool `json:"enabled,omitzero"` VPCs *[]NFSSpaceAccessPolicyVPCOptions `json:"vpcs,omitzero"` MTLSCACert *string `json:"mtls_ca_cert,omitzero"` @@ -116,7 +115,6 @@ type NFSFilesystemAccessPolicy struct { // NFSFilesystemAccessPolicyUpdateOptions contains fields accepted when updating an NFS Filesystem access policy. type NFSFilesystemAccessPolicyUpdateOptions struct { - Label *string `json:"label,omitzero"` Enabled *bool `json:"enabled,omitzero"` LinodeIDs *[]int `json:"linode_ids,omitzero"` SquashPolicy *NFSSquashPolicy `json:"squash_policy,omitzero"` diff --git a/test/integration/nfs_filesystems_test.go b/test/integration/nfs_filesystems_test.go index 0dcc3d64b..296bd7a39 100644 --- a/test/integration/nfs_filesystems_test.go +++ b/test/integration/nfs_filesystems_test.go @@ -121,7 +121,6 @@ func verifyNFSFilesystemAccessPolicyUpdate( filesystemAccPolicy *linodego.NFSFilesystemAccessPolicy, opts linodego.NFSFilesystemAccessPolicyUpdateOptions, ) { - // assert.Equal(t, *updateOpts.Label, filesystemAccPolicy.Label) // TODO: It is not updated - defect? assert.True(t, filesystemAccPolicy.Enabled) assert.Len(t, filesystemAccPolicy.LinodeACL, 1) assert.Equal(t, (*opts.LinodeIDs)[0], filesystemAccPolicy.LinodeACL[0].ID) @@ -231,7 +230,6 @@ func TestNFSFilesystem_UpdateAccessPolicy(t *testing.T) { t.Cleanup(linodeTeardown) updateOpts := linodego.NFSFilesystemAccessPolicyUpdateOptions{ - Label: linodego.Pointer(filesystem.Label + "-updated"), Enabled: linodego.Pointer(true), LinodeIDs: linodego.Pointer([]int{linode.ID}), } diff --git a/test/integration/nfs_spaces_test.go b/test/integration/nfs_spaces_test.go index 3d04dd7b3..99a8121ad 100644 --- a/test/integration/nfs_spaces_test.go +++ b/test/integration/nfs_spaces_test.go @@ -56,7 +56,6 @@ func verifyNFSSpace(t *testing.T, space *linodego.NFSSpace, createOpts linodego. func verifyNFSSpaceAccessPolicyUpdate(t *testing.T, spaceAccPolicy *linodego.NFSSpaceAccessPolicy, opts linodego.NFSSpaceAccessPolicyUpdateOptions) { // assert.Equal(t, "pending", spaceAccPolicy.Status) - // assert.Equal(t, updateOpts.Label, linodego.Pointer(spaceAccPolicy.Label)) // TODO: It is not updated - defect? assert.True(t, spaceAccPolicy.Enabled) assert.Len(t, spaceAccPolicy.VPCACL, 1) assert.Equal(t, (*opts.VPCs)[0].ID, spaceAccPolicy.VPCACL[0].ID) @@ -133,7 +132,6 @@ func TestNFSSpace_UpdateAccessPolicy(t *testing.T) { t.Cleanup(vpcTeardown) updateOpts := linodego.NFSSpaceAccessPolicyUpdateOptions{ - Label: linodego.Pointer(space.Label + "-updated"), Enabled: linodego.Pointer(true), VPCs: linodego.Pointer([]linodego.NFSSpaceAccessPolicyVPCOptions{ { From 4610214ee89ce3a229bc1eddf49d76f832eb0a61 Mon Sep 17 00:00:00 2001 From: Maciej Wilk Date: Mon, 12 Oct 2026 16:47:12 +0200 Subject: [PATCH 14/18] Add smoke int tests for Filesystem Quota --- test/integration/nfs_filesystems_test.go | 94 ++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/test/integration/nfs_filesystems_test.go b/test/integration/nfs_filesystems_test.go index 296bd7a39..9564a02ec 100644 --- a/test/integration/nfs_filesystems_test.go +++ b/test/integration/nfs_filesystems_test.go @@ -2,6 +2,7 @@ package integration import ( "context" + "strings" "testing" "time" @@ -91,6 +92,40 @@ func setupNFSFilesystem( return client, space, filesystem, createOpts } +func setupNFSFilesystemQuota( + t *testing.T, + client *linodego.Client, + space *linodego.NFSSpace, + filesystem *linodego.NFSFilesystem, + modifiers ...func(opts *linodego.NFSQuotaCreateOptions), +) (*linodego.NFSQuota, linodego.NFSQuotaCreateOptions) { + t.Helper() + + _, mountDir, isFound := strings.Cut(*filesystem.MountTargetFQDN, ":/") + require.True(t, isFound, "Mount Target FQDN does not contain ':/'") + + createOpts := linodego.NFSQuotaCreateOptions{ + Path: "/" + strings.Join([]string{mountDir, "testing-dx"}, "/"), + MaxFileCount: filesystem.MaxFileCount, + MaxCapacityBytes: filesystem.MaxCapacityBytes, + } + + for _, modifier := range modifiers { + modifier(&createOpts) + } + + quota, err := client.CreateNFSQuota(context.Background(), space.ID, filesystem.ID, createOpts) + require.NoErrorf(t, err, "Error creating Filesystem Quota: %v", err) + + t.Cleanup(func() { + if err = client.DeleteNFSQuota(context.Background(), space.ID, filesystem.ID, quota.ID); err != nil { + t.Errorf("Error deleting NFS Filesystem Quota: %v", err) + } + }) + + return quota, createOpts +} + func verifyNFSFilesystemBasics(t *testing.T, space *linodego.NFSSpace, filesystem *linodego.NFSFilesystem, createOpts linodego.NFSFilesystemCreateOptions) { t.Helper() assert.Equal(t, space.ID, filesystem.SpaceID) @@ -127,6 +162,22 @@ func verifyNFSFilesystemAccessPolicyUpdate( assertDateSet(t, filesystemAccPolicy.Updated) } +func verifyNFSFilesystemCustomQuota( + t *testing.T, + quota *linodego.NFSQuota, + filesystem *linodego.NFSFilesystem, + opts linodego.NFSQuotaCreateOptions, +) { + assert.Equal(t, filesystem.ID, quota.FilesystemID) + assert.Equal(t, opts.Path, quota.Path) + assert.Equal(t, opts.MaxFileCount, *quota.MaxFileCount) + assert.Equal(t, opts.MaxCapacityBytes, *quota.MaxCapacityBytes) + assert.Equal(t, linodego.NFSQuotaStatusActive, quota.Status) + assert.False(t, quota.IsRoot) + assertDateSet(t, quota.Created) + assertDateSet(t, quota.Updated) +} + func TestNFSFilesystem_Create_smoke(t *testing.T) { _, space, filesystem, createOpts := setupNFSFilesystem(t, "fixtures/TestNFSFilesystem_Create") verifyNFSFilesystemBasics(t, space, filesystem, createOpts) @@ -257,3 +308,46 @@ func TestNFSFilesystem_UpdateAccessPolicy(t *testing.T) { require.NoErrorf(t, err, "Error getting NFS Filesystem Access Policy: %v", err) verifyNFSFilesystemAccessPolicyUpdate(t, filesystemAccPolicyGet, updateOpts) } + +func TestNFSFilesystem_CreateCustomQuota_smoke(t *testing.T) { + ctx := waitContext(t, 180*time.Second) + client, space, filesystem, _ := setupNFSFilesystem(t, "fixtures/TestNFSFilesystem_CreateCustomQuota") + + // Wait for NFS Filesystem status to be 'active' to read the details + _, err := client.WaitForNFSFilesystemStatus( + ctx, + space.ID, + filesystem.ID, + linodego.NFSFilesystemStatusActive, + ) + require.NoErrorf(t, err, "Failed to wait for Filesystem status to be active: %s", err) + + filesystem, err = client.GetNFSFilesystemInSpace(context.Background(), space.ID, filesystem.ID) + require.NoErrorf(t, err, "Error retrieving NFS Filesystem in Space: %v", err) + + quota, createOpts := setupNFSFilesystemQuota(t, client, space, filesystem) + verifyNFSFilesystemCustomQuota(t, quota, filesystem, createOpts) +} + +func TestNFSFilesystem_GetCustomQuota(t *testing.T) { + ctx := waitContext(t, 180*time.Second) + client, space, filesystem, _ := setupNFSFilesystem(t, "fixtures/TestNFSFilesystem_GetCustomQuota") + + // Wait for NFS Filesystem status to be 'active' to read the details + _, err := client.WaitForNFSFilesystemStatus( + ctx, + space.ID, + filesystem.ID, + linodego.NFSFilesystemStatusActive, + ) + require.NoErrorf(t, err, "Failed to wait for Filesystem status to be active: %s", err) + + filesystem, err = client.GetNFSFilesystemInSpace(context.Background(), space.ID, filesystem.ID) + require.NoErrorf(t, err, "Error retrieving NFS Filesystem in Space: %v", err) + + quota, createOpts := setupNFSFilesystemQuota(t, client, space, filesystem) + + quota, err = client.GetNFSQuota(context.Background(), space.ID, filesystem.ID, quota.ID) + require.NoErrorf(t, err, "Error retrieving Filesystem Quota: %v", err) + verifyNFSFilesystemCustomQuota(t, quota, filesystem, createOpts) +} From b1f6db40a657a906da8272ac9781c3ff99152de7 Mon Sep 17 00:00:00 2001 From: Maciej Wilk Date: Tue, 13 Oct 2026 12:53:45 +0200 Subject: [PATCH 15/18] Move WaitForNFSFilesystemStatus to setupNFSFilesystem --- test/integration/nfs_filesystems_test.go | 65 +++++++++--------------- 1 file changed, 24 insertions(+), 41 deletions(-) diff --git a/test/integration/nfs_filesystems_test.go b/test/integration/nfs_filesystems_test.go index 9564a02ec..f950121cb 100644 --- a/test/integration/nfs_filesystems_test.go +++ b/test/integration/nfs_filesystems_test.go @@ -54,6 +54,7 @@ func waitForNFSFilesystemDeleted( func setupNFSFilesystem( t *testing.T, fixtureYaml string, + requireActive bool, modifiers ...func(opts *linodego.NFSFilesystemCreateOptions), ) (*linodego.Client, *linodego.NFSSpace, *linodego.NFSFilesystem, linodego.NFSFilesystemCreateOptions) { t.Helper() @@ -71,6 +72,18 @@ func setupNFSFilesystem( filesystem, err := client.CreateNFSFilesystem(context.Background(), space.ID, createOpts) require.NoErrorf(t, err, "Error creating NFS Filesystem: %v", err) + // Wait for NFS Filesystem status to be 'active' to read the details (if needed) + if requireActive { + ctx := waitContext(t, 240*time.Second) + _, err = client.WaitForNFSFilesystemStatus( + ctx, + space.ID, + filesystem.ID, + linodego.NFSFilesystemStatusActive, + ) + require.NoErrorf(t, err, "Failed to wait for Filesystem status to be active: %s", err) + } + t.Cleanup(func() { ctx, cancel := context.WithTimeout(context.Background(), 90*time.Second) defer cancel() @@ -179,22 +192,12 @@ func verifyNFSFilesystemCustomQuota( } func TestNFSFilesystem_Create_smoke(t *testing.T) { - _, space, filesystem, createOpts := setupNFSFilesystem(t, "fixtures/TestNFSFilesystem_Create") + _, space, filesystem, createOpts := setupNFSFilesystem(t, "fixtures/TestNFSFilesystem_Create", false) verifyNFSFilesystemBasics(t, space, filesystem, createOpts) } func TestNFSFilesystem_Get(t *testing.T) { - ctx := waitContext(t, 180*time.Second) - client, space, filesystem, createOpts := setupNFSFilesystem(t, "fixtures/TestNFSFilesystem_Get") - - // Wait for NFS Filesystem status to be 'active' to read the details - _, err := client.WaitForNFSFilesystemStatus( - ctx, - space.ID, - filesystem.ID, - linodego.NFSFilesystemStatusActive, - ) - require.NoErrorf(t, err, "Failed to wait for Filesystem status to be active: %s", err) + client, space, filesystem, createOpts := setupNFSFilesystem(t, "fixtures/TestNFSFilesystem_Get", true) filesystemGet, err := client.GetNFSFilesystemInSpace(context.Background(), space.ID, filesystem.ID) require.NoErrorf(t, err, "Error retrieving NFS Filesystem in Space: %v", err) @@ -203,7 +206,7 @@ func TestNFSFilesystem_Get(t *testing.T) { } func TestNFSFilesystem_GetWithoutNFSSpace(t *testing.T) { - client, space, filesystem, createOpts := setupNFSFilesystem(t, "fixtures/TestNFSFilesystem_GetWithoutNFSSpace") + client, space, filesystem, createOpts := setupNFSFilesystem(t, "fixtures/TestNFSFilesystem_GetWithoutNFSSpace", false) filesystemGet, err := client.GetNFSFilesystem(context.Background(), filesystem.ID) require.NoErrorf(t, err, "Error retrieving NFS Filesystem with no Space: %v", err) @@ -211,7 +214,7 @@ func TestNFSFilesystem_GetWithoutNFSSpace(t *testing.T) { } func TestNFSFilesystem_List(t *testing.T) { - client, space, filesystem, createOpts := setupNFSFilesystem(t, "fixtures/TestNFSFilesystem_List") + client, space, filesystem, createOpts := setupNFSFilesystem(t, "fixtures/TestNFSFilesystem_List", false) f := linodego.Filter{} f.AddField(linodego.Eq, "label", filesystem.Label) @@ -227,7 +230,7 @@ func TestNFSFilesystem_List(t *testing.T) { } func TestNFSFilesystem_Update(t *testing.T) { - client, space, filesystem, createOpts := setupNFSFilesystem(t, "fixtures/TestNFSFilesystem_Update") + client, space, filesystem, createOpts := setupNFSFilesystem(t, "fixtures/TestNFSFilesystem_Update", false) updateOpts := filesystem.GetUpdateOptions() updateOpts.Label = linodego.Pointer(filesystem.Label + "-updated") @@ -250,7 +253,7 @@ func TestNFSFilesystem_Update(t *testing.T) { func TestNFSFilesystem_GetAccessPolicy_smoke(t *testing.T) { t.Skip("Access Policy seems to not be fully developed yet") - client, space, filesystem, _ := setupNFSFilesystem(t, "fixtures/TestNFSFilesystem_GetAccessPolicy") + client, space, filesystem, _ := setupNFSFilesystem(t, "fixtures/TestNFSFilesystem_GetAccessPolicy", false) filesystemAccPolicy, err := client.GetNFSFilesystemAccessPolicy(context.Background(), space.ID, filesystem.ID) require.NoErrorf(t, err, "Error getting NFS Filesystem Access Policy: %v", err) @@ -268,7 +271,7 @@ func TestNFSFilesystem_GetAccessPolicy_smoke(t *testing.T) { func TestNFSFilesystem_UpdateAccessPolicy(t *testing.T) { t.Skip("Access Policy seems to not be fully developed yet") - client, space, filesystem, _ := setupNFSFilesystem(t, "fixtures/TestNFSFilesystem_UpdateAccessPolicy") + client, space, filesystem, _ := setupNFSFilesystem(t, "fixtures/TestNFSFilesystem_UpdateAccessPolicy", false) linode, _, linodeTeardown, err := createInstanceWithoutDisks( t, @@ -310,19 +313,9 @@ func TestNFSFilesystem_UpdateAccessPolicy(t *testing.T) { } func TestNFSFilesystem_CreateCustomQuota_smoke(t *testing.T) { - ctx := waitContext(t, 180*time.Second) - client, space, filesystem, _ := setupNFSFilesystem(t, "fixtures/TestNFSFilesystem_CreateCustomQuota") - - // Wait for NFS Filesystem status to be 'active' to read the details - _, err := client.WaitForNFSFilesystemStatus( - ctx, - space.ID, - filesystem.ID, - linodego.NFSFilesystemStatusActive, - ) - require.NoErrorf(t, err, "Failed to wait for Filesystem status to be active: %s", err) + client, space, filesystem, _ := setupNFSFilesystem(t, "fixtures/TestNFSFilesystem_CreateCustomQuota", true) - filesystem, err = client.GetNFSFilesystemInSpace(context.Background(), space.ID, filesystem.ID) + filesystem, err := client.GetNFSFilesystemInSpace(context.Background(), space.ID, filesystem.ID) require.NoErrorf(t, err, "Error retrieving NFS Filesystem in Space: %v", err) quota, createOpts := setupNFSFilesystemQuota(t, client, space, filesystem) @@ -330,19 +323,9 @@ func TestNFSFilesystem_CreateCustomQuota_smoke(t *testing.T) { } func TestNFSFilesystem_GetCustomQuota(t *testing.T) { - ctx := waitContext(t, 180*time.Second) - client, space, filesystem, _ := setupNFSFilesystem(t, "fixtures/TestNFSFilesystem_GetCustomQuota") - - // Wait for NFS Filesystem status to be 'active' to read the details - _, err := client.WaitForNFSFilesystemStatus( - ctx, - space.ID, - filesystem.ID, - linodego.NFSFilesystemStatusActive, - ) - require.NoErrorf(t, err, "Failed to wait for Filesystem status to be active: %s", err) + client, space, filesystem, _ := setupNFSFilesystem(t, "fixtures/TestNFSFilesystem_GetCustomQuota", true) - filesystem, err = client.GetNFSFilesystemInSpace(context.Background(), space.ID, filesystem.ID) + filesystem, err := client.GetNFSFilesystemInSpace(context.Background(), space.ID, filesystem.ID) require.NoErrorf(t, err, "Error retrieving NFS Filesystem in Space: %v", err) quota, createOpts := setupNFSFilesystemQuota(t, client, space, filesystem) From 6cda9ab321f1a8af6737796b50a4c08f3c11a402 Mon Sep 17 00:00:00 2001 From: Maciej Wilk Date: Wed, 14 Oct 2026 13:15:39 +0200 Subject: [PATCH 16/18] Separate tests for Root and Custom Quotas --- test/integration/nfs_filesystems_test.go | 69 ++++++++++++++++-------- 1 file changed, 46 insertions(+), 23 deletions(-) diff --git a/test/integration/nfs_filesystems_test.go b/test/integration/nfs_filesystems_test.go index f950121cb..2ebfd5c0f 100644 --- a/test/integration/nfs_filesystems_test.go +++ b/test/integration/nfs_filesystems_test.go @@ -105,7 +105,7 @@ func setupNFSFilesystem( return client, space, filesystem, createOpts } -func setupNFSFilesystemQuota( +func setupNFSFilesystemCustomQuota( t *testing.T, client *linodego.Client, space *linodego.NFSSpace, @@ -172,21 +172,19 @@ func verifyNFSFilesystemAccessPolicyUpdate( assert.True(t, filesystemAccPolicy.Enabled) assert.Len(t, filesystemAccPolicy.LinodeACL, 1) assert.Equal(t, (*opts.LinodeIDs)[0], filesystemAccPolicy.LinodeACL[0].ID) + assert.Equal(t, opts.SquashPolicy, linodego.Pointer(filesystemAccPolicy.SquashPolicy)) assertDateSet(t, filesystemAccPolicy.Updated) } -func verifyNFSFilesystemCustomQuota( +func verifyNFSFilesystemQuota( t *testing.T, quota *linodego.NFSQuota, filesystem *linodego.NFSFilesystem, - opts linodego.NFSQuotaCreateOptions, ) { assert.Equal(t, filesystem.ID, quota.FilesystemID) - assert.Equal(t, opts.Path, quota.Path) - assert.Equal(t, opts.MaxFileCount, *quota.MaxFileCount) - assert.Equal(t, opts.MaxCapacityBytes, *quota.MaxCapacityBytes) + assert.Equal(t, filesystem.MaxFileCount, *quota.MaxFileCount) + assert.Equal(t, filesystem.MaxCapacityBytes, *quota.MaxCapacityBytes) assert.Equal(t, linodego.NFSQuotaStatusActive, quota.Status) - assert.False(t, quota.IsRoot) assertDateSet(t, quota.Created) assertDateSet(t, quota.Updated) } @@ -252,11 +250,10 @@ func TestNFSFilesystem_Update(t *testing.T) { } func TestNFSFilesystem_GetAccessPolicy_smoke(t *testing.T) { - t.Skip("Access Policy seems to not be fully developed yet") client, space, filesystem, _ := setupNFSFilesystem(t, "fixtures/TestNFSFilesystem_GetAccessPolicy", false) filesystemAccPolicy, err := client.GetNFSFilesystemAccessPolicy(context.Background(), space.ID, filesystem.ID) - require.NoErrorf(t, err, "Error getting NFS Filesystem Access Policy: %v", err) + require.NoErrorf(t, err, "Error retrieving NFS Filesystem Access Policy: %v", err) assert.Equal(t, filesystem.ID, filesystemAccPolicy.FilesystemID) assert.Equal(t, filesystem.Label, filesystemAccPolicy.Label) assert.False(t, filesystemAccPolicy.Enabled) @@ -270,22 +267,31 @@ func TestNFSFilesystem_GetAccessPolicy_smoke(t *testing.T) { } func TestNFSFilesystem_UpdateAccessPolicy(t *testing.T) { - t.Skip("Access Policy seems to not be fully developed yet") client, space, filesystem, _ := setupNFSFilesystem(t, "fixtures/TestNFSFilesystem_UpdateAccessPolicy", false) - linode, _, linodeTeardown, err := createInstanceWithoutDisks( + linode, err := createInstance( t, client, true, func(client *linodego.Client, opts *linodego.InstanceCreateOptions) { opts.Region = filesystem.Region - }) + opts.Booted = linodego.Pointer(true) + }, + ) require.NoErrorf(t, err, "Error creating Linode for NFS Filesystem Access Policy: %v", err) - t.Cleanup(linodeTeardown) + + t.Cleanup(func() { + if err := client.DeleteInstance(context.Background(), linode.ID); err != nil { + if t != nil { + t.Errorf("Error deleting Linode instance: %s", err) + } + } + }) updateOpts := linodego.NFSFilesystemAccessPolicyUpdateOptions{ - Enabled: linodego.Pointer(true), - LinodeIDs: linodego.Pointer([]int{linode.ID}), + Enabled: linodego.Pointer(true), + LinodeIDs: linodego.Pointer([]int{linode.ID}), + SquashPolicy: linodego.Pointer(linodego.NFSSquashPolicyAllSquash), } filesystemAccPolicyUpdate, err := client.UpdateNFSFilesystemAccessPolicy( @@ -312,25 +318,42 @@ func TestNFSFilesystem_UpdateAccessPolicy(t *testing.T) { verifyNFSFilesystemAccessPolicyUpdate(t, filesystemAccPolicyGet, updateOpts) } -func TestNFSFilesystem_CreateCustomQuota_smoke(t *testing.T) { - client, space, filesystem, _ := setupNFSFilesystem(t, "fixtures/TestNFSFilesystem_CreateCustomQuota", true) +func TestNFSFilesystem_GetRootQuota_smoke(t *testing.T) { + client, space, filesystem, _ := setupNFSFilesystem(t, "fixtures/TestNFSFilesystem_GetRootQuota_smoke", true) filesystem, err := client.GetNFSFilesystemInSpace(context.Background(), space.ID, filesystem.ID) require.NoErrorf(t, err, "Error retrieving NFS Filesystem in Space: %v", err) - quota, createOpts := setupNFSFilesystemQuota(t, client, space, filesystem) - verifyNFSFilesystemCustomQuota(t, quota, filesystem, createOpts) + _, mountDir, isFound := strings.Cut(*filesystem.MountTargetFQDN, ":/") + require.True(t, isFound, "Mount Target FQDN does not contain ':/'") + + quotas, err := client.ListNFSQuotas(context.Background(), space.ID, filesystem.ID, nil) + require.NoErrorf(t, err, "Error listing Filesystem Quotas: %v", err) + assert.Len(t, quotas, 1) + assert.Contains(t, quotas[0].Path, mountDir) + assert.True(t, quotas[0].IsRoot) + verifyNFSFilesystemQuota(t, linodego.Pointer(quotas[0]), filesystem) } -func TestNFSFilesystem_GetCustomQuota(t *testing.T) { - client, space, filesystem, _ := setupNFSFilesystem(t, "fixtures/TestNFSFilesystem_GetCustomQuota", true) +func TestNFSFilesystem_ManageCustomQuota(t *testing.T) { + t.Skip("Removal of Filesystem with custom Quota requires manual action on mounted Linode instance") + client, space, filesystem, _ := setupNFSFilesystem(t, "fixtures/TestNFSFilesystem_ManageCustomQuota", true) filesystem, err := client.GetNFSFilesystemInSpace(context.Background(), space.ID, filesystem.ID) require.NoErrorf(t, err, "Error retrieving NFS Filesystem in Space: %v", err) - quota, createOpts := setupNFSFilesystemQuota(t, client, space, filesystem) + quota, createOpts := setupNFSFilesystemCustomQuota(t, client, space, filesystem) + assert.Equal(t, createOpts.Path, quota.Path) + assert.False(t, quota.IsRoot) + verifyNFSFilesystemQuota(t, quota, filesystem) quota, err = client.GetNFSQuota(context.Background(), space.ID, filesystem.ID, quota.ID) require.NoErrorf(t, err, "Error retrieving Filesystem Quota: %v", err) - verifyNFSFilesystemCustomQuota(t, quota, filesystem, createOpts) + assert.Equal(t, createOpts.Path, quota.Path) + assert.False(t, quota.IsRoot) + verifyNFSFilesystemQuota(t, quota, filesystem) + + quotas, err := client.ListNFSQuotas(context.Background(), space.ID, filesystem.ID, nil) + require.NoErrorf(t, err, "Error listing Filesystem Quotas: %v", err) + assert.Len(t, quotas, 2) } From 7b0f4c595ff9f7156f066b540c05eb1187a6477e Mon Sep 17 00:00:00 2001 From: Maciej Wilk Date: Fri, 30 Oct 2026 13:44:32 +0100 Subject: [PATCH 17/18] Refactor FS and tests after NFS fixes --- nfs_filesystems.go | 14 ++++++------- test/integration/nfs_filesystems_test.go | 19 +++++++++-------- test/integration/nfs_spaces_test.go | 26 ++++++++++++++++-------- 3 files changed, 34 insertions(+), 25 deletions(-) diff --git a/nfs_filesystems.go b/nfs_filesystems.go index 77606d5f5..eb68cc929 100644 --- a/nfs_filesystems.go +++ b/nfs_filesystems.go @@ -65,10 +65,10 @@ type NFSFilesystemCreateOptions struct { // NFSFilesystemUpdateOptions contains fields accepted when updating an NFS Filesystem. type NFSFilesystemUpdateOptions struct { - Label *string `json:"label,omitzero"` - // MaxCapacityBytes *int64 `json:"max_capacity_bytes,omitzero"` // TODO: Currently API says it is not editable field - // MaxFileCount *int64 `json:"max_file_count,omitzero"` // TODO: Currently API says it is not editable field - Tags *[]string `json:"tags,omitzero"` + Label *string `json:"label,omitzero"` + MaxCapacityBytes *int64 `json:"max_capacity_bytes,omitzero"` + MaxFileCount *int64 `json:"max_file_count,omitzero"` + Tags *[]string `json:"tags,omitzero"` } // NFSFilesystemStats represents collected NFS Filesystem usage statistics. @@ -145,9 +145,9 @@ func (n NFSFilesystem) GetCreateOptions() NFSFilesystemCreateOptions { // GetUpdateOptions returns the NFS Filesystem fields accepted by UpdateNFSFilesystem. func (n NFSFilesystem) GetUpdateOptions() NFSFilesystemUpdateOptions { result := NFSFilesystemUpdateOptions{ - Label: Pointer(n.Label), - // MaxCapacityBytes: Pointer(n.MaxCapacityBytes), // TODO: Currently API says it is not editable field - // MaxFileCount: Pointer(n.MaxFileCount), // TODO: Currently API says it is not editable field + Label: Pointer(n.Label), + MaxCapacityBytes: Pointer(n.MaxCapacityBytes), + MaxFileCount: Pointer(n.MaxFileCount), } if n.Tags != nil { diff --git a/test/integration/nfs_filesystems_test.go b/test/integration/nfs_filesystems_test.go index 2ebfd5c0f..e23938385 100644 --- a/test/integration/nfs_filesystems_test.go +++ b/test/integration/nfs_filesystems_test.go @@ -228,25 +228,26 @@ func TestNFSFilesystem_List(t *testing.T) { } func TestNFSFilesystem_Update(t *testing.T) { - client, space, filesystem, createOpts := setupNFSFilesystem(t, "fixtures/TestNFSFilesystem_Update", false) + client, space, filesystem, createOpts := setupNFSFilesystem(t, "fixtures/TestNFSFilesystem_Update", true) updateOpts := filesystem.GetUpdateOptions() updateOpts.Label = linodego.Pointer(filesystem.Label + "-updated") updateOpts.Tags = linodego.Pointer([]string{"updated"}) - // updateOpts.MaxCapacityBytes = linodego.Pointer(int64(1073741824)) // TODO: Currently API says it is not editable field - // updateOpts.MaxCountFile = linodego.Pointer(int64(2500)) // TODO: Currently API says it is not editable field + updateOpts.MaxCapacityBytes = linodego.Pointer(int64(1099511628000)) + updateOpts.MaxFileCount = linodego.Pointer(int64(3210)) filesystemUpdate, err := client.UpdateNFSFilesystem(context.Background(), space.ID, filesystem.ID, updateOpts) require.NoErrorf(t, err, "Error updating NFS Space: %v", err) verifyOpts := linodego.NFSFilesystemCreateOptions{ - Label: *updateOpts.Label, - Region: createOpts.Region, - Tags: updateOpts.Tags, - // MaxCapacityBytes: *updateOpts.MaxCapacityBytes, // TODO: Currently API says it is not editable field - // MaxFileCount: *updateOpts.MaxCountFile, // TODO: Currently API says it is not editable field + Label: *updateOpts.Label, + Region: createOpts.Region, + Tags: updateOpts.Tags, + MaxCapacityBytes: *updateOpts.MaxCapacityBytes, + MaxFileCount: updateOpts.MaxFileCount, } verifyNFSFilesystemBasics(t, space, filesystemUpdate, verifyOpts) + verifyNFSFilesystemDetails(t, filesystemUpdate, verifyOpts) } func TestNFSFilesystem_GetAccessPolicy_smoke(t *testing.T) { @@ -263,7 +264,7 @@ func TestNFSFilesystem_GetAccessPolicy_smoke(t *testing.T) { assert.NotNil(t, filesystemAccPolicy.SquashPolicy) assert.Equal(t, linodego.NFSAccessPolicyStatusActive, filesystemAccPolicy.Status) assertDateSet(t, filesystemAccPolicy.Created) - assert.Nil(t, filesystemAccPolicy.Updated) + assertDateSet(t, filesystemAccPolicy.Updated) } func TestNFSFilesystem_UpdateAccessPolicy(t *testing.T) { diff --git a/test/integration/nfs_spaces_test.go b/test/integration/nfs_spaces_test.go index 99a8121ad..fa1e22eac 100644 --- a/test/integration/nfs_spaces_test.go +++ b/test/integration/nfs_spaces_test.go @@ -55,7 +55,6 @@ func verifyNFSSpace(t *testing.T, space *linodego.NFSSpace, createOpts linodego. } func verifyNFSSpaceAccessPolicyUpdate(t *testing.T, spaceAccPolicy *linodego.NFSSpaceAccessPolicy, opts linodego.NFSSpaceAccessPolicyUpdateOptions) { - // assert.Equal(t, "pending", spaceAccPolicy.Status) assert.True(t, spaceAccPolicy.Enabled) assert.Len(t, spaceAccPolicy.VPCACL, 1) assert.Equal(t, (*opts.VPCs)[0].ID, spaceAccPolicy.VPCACL[0].ID) @@ -109,7 +108,6 @@ func TestNFSSpace_Update(t *testing.T) { } func TestNFSSpace_GetAccessPolicy_smoke(t *testing.T) { - t.Skip("Access Policy seems to not be fully developed yet") client, space, _ := setupNFSSpace(t, "fixtures/TestNFSSpace_GetAccessPolicy") spaceAccPolicy, err := client.GetNFSSpaceAccessPolicy(context.Background(), space.ID) @@ -118,18 +116,26 @@ func TestNFSSpace_GetAccessPolicy_smoke(t *testing.T) { assert.Equal(t, space.Label, spaceAccPolicy.Label) assert.Equal(t, linodego.NFSAccessPolicyStatusActive, spaceAccPolicy.Status) assertDateSet(t, spaceAccPolicy.Created) - assert.Nil(t, spaceAccPolicy.Updated) + assertDateSet(t, spaceAccPolicy.Created) } func TestNFSSpace_UpdateAccessPolicy(t *testing.T) { - t.Skip("Access Policy seems to not be fully developed yet") + t.Skip("Access Policy update is stuck with 'updating'/'pending' status") client, space, _ := setupNFSSpace(t, "fixtures/TestNFSSpace_UpdateAccessPolicy") - vpc, _, vpcTeardown, err := createVPC(t, client, []vpcModifier{func(l *linodego.Client, opts *linodego.VPCCreateOptions) { - opts.Region = getRegionsWithCaps(t, client, []linodego.RegionCapability{linodego.CapabilityVPCs, linodego.CapabilityNFSStorage})[0] - }}...) - require.NoErrorf(t, err, "Error creating VPC for Access Policy: %v", err) - t.Cleanup(vpcTeardown) + vpc, _, vpcWithSubnetTeardown, err := createVPCWithDualStackSubnet( + t, + client, + func(client *linodego.Client, opts *linodego.VPCCreateOptions) { + opts.Region = getRegionsWithCaps(t, client, []linodego.RegionCapability{ + linodego.CapabilityVPCs, + linodego.CapabilityVPCDualStack, + linodego.CapabilityNFSStorage, + })[0] + }, + ) + require.NoErrorf(t, err, "Error creating Dual Stack VPC for Access Policy: %v", err) + t.Cleanup(vpcWithSubnetTeardown) updateOpts := linodego.NFSSpaceAccessPolicyUpdateOptions{ Enabled: linodego.Pointer(true), @@ -144,6 +150,7 @@ func TestNFSSpace_UpdateAccessPolicy(t *testing.T) { spaceAccPolicyUpdate, err := client.UpdateNFSSpaceAccessPolicy(context.Background(), space.ID, updateOpts) require.NoErrorf(t, err, "Error updating NFS Space Access Policy: %v", err) + assert.Equal(t, "pending", string(spaceAccPolicyUpdate.Status)) verifyNFSSpaceAccessPolicyUpdate(t, spaceAccPolicyUpdate, updateOpts) // Wait for NFS Space Access Policy status to be 'active' to read the details @@ -157,5 +164,6 @@ func TestNFSSpace_UpdateAccessPolicy(t *testing.T) { spaceAccPolicyGet, err := client.GetNFSSpaceAccessPolicy(context.Background(), space.ID) require.NoErrorf(t, err, "Error getting NFS Space Access Policy: %v", err) + assert.Equal(t, "active", string(spaceAccPolicyGet.Status)) verifyNFSSpaceAccessPolicyUpdate(t, spaceAccPolicyGet, updateOpts) } From a9a91e39c94e685409d1ea899c4948a78194c160 Mon Sep 17 00:00:00 2001 From: Maciej Wilk Date: Fri, 30 Oct 2026 14:02:03 +0100 Subject: [PATCH 18/18] Change MaxCapacityBytes type to pointer as it is optional field --- nfs_filesystems.go | 4 ++-- test/integration/nfs_filesystems_test.go | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/nfs_filesystems.go b/nfs_filesystems.go index eb68cc929..fb5cfe9bc 100644 --- a/nfs_filesystems.go +++ b/nfs_filesystems.go @@ -57,7 +57,7 @@ type NFSFilesystem struct { type NFSFilesystemCreateOptions struct { Label string `json:"label"` Region string `json:"region"` - MaxCapacityBytes int64 `json:"max_capacity_bytes"` + MaxCapacityBytes *int64 `json:"max_capacity_bytes,omitzero"` MaxFileCount *int64 `json:"max_file_count,omitzero"` ProtocolVersions *[]NFSProtocolVersion `json:"protocol_versions,omitzero"` Tags *[]string `json:"tags,omitzero"` @@ -127,7 +127,7 @@ func (n NFSFilesystem) GetCreateOptions() NFSFilesystemCreateOptions { result := NFSFilesystemCreateOptions{ Label: n.Label, Region: n.Region, - MaxCapacityBytes: n.MaxCapacityBytes, + MaxCapacityBytes: Pointer(n.MaxCapacityBytes), MaxFileCount: Pointer(n.MaxFileCount), } diff --git a/test/integration/nfs_filesystems_test.go b/test/integration/nfs_filesystems_test.go index e23938385..cd1c6130d 100644 --- a/test/integration/nfs_filesystems_test.go +++ b/test/integration/nfs_filesystems_test.go @@ -11,14 +11,14 @@ import ( "github.com/stretchr/testify/require" ) -func getNFSFilesystemCreateOptions(t *testing.T, client *linodego.Client) linodego.NFSFilesystemCreateOptions { +func setNFSFilesystemCreateOptions(t *testing.T, client *linodego.Client) linodego.NFSFilesystemCreateOptions { return linodego.NFSFilesystemCreateOptions{ Label: "go-test-nfs-filesystem-" + randLabel(), Region: getRegionsWithCaps(t, client, []linodego.RegionCapability{linodego.CapabilityNFSStorage})[0], - MaxCapacityBytes: 1099511627776, - Tags: linodego.Pointer([]string{"testing"}), + MaxCapacityBytes: linodego.Pointer(int64(1099511627776)), MaxFileCount: linodego.Pointer(int64(1500)), ProtocolVersions: linodego.Pointer([]linodego.NFSProtocolVersion{linodego.NFSProtocolVersionV4}), + Tags: linodego.Pointer([]string{"testing"}), } } @@ -59,7 +59,7 @@ func setupNFSFilesystem( ) (*linodego.Client, *linodego.NFSSpace, *linodego.NFSFilesystem, linodego.NFSFilesystemCreateOptions) { t.Helper() client, fixtureTeardown := createTestClient(t, fixtureYaml) - createOpts := getNFSFilesystemCreateOptions(t, client) + createOpts := setNFSFilesystemCreateOptions(t, client) for _, modifier := range modifiers { modifier(&createOpts) @@ -153,7 +153,7 @@ func verifyNFSFilesystemBasics(t *testing.T, space *linodego.NFSSpace, filesyste func verifyNFSFilesystemDetails(t *testing.T, filesystem *linodego.NFSFilesystem, createOpts linodego.NFSFilesystemCreateOptions) { t.Helper() assert.NotEmpty(t, filesystem.ProtocolVersions) - assert.EqualValues(t, createOpts.MaxCapacityBytes, filesystem.MaxCapacityBytes) + assert.EqualValues(t, createOpts.MaxCapacityBytes, linodego.Pointer(filesystem.MaxCapacityBytes)) assert.EqualValues(t, createOpts.MaxFileCount, linodego.Pointer(filesystem.MaxFileCount)) assert.NotEmpty(t, filesystem.MountTargetIPs) assert.NotNil(t, filesystem.MountTargetFQDN) @@ -243,7 +243,7 @@ func TestNFSFilesystem_Update(t *testing.T) { Label: *updateOpts.Label, Region: createOpts.Region, Tags: updateOpts.Tags, - MaxCapacityBytes: *updateOpts.MaxCapacityBytes, + MaxCapacityBytes: updateOpts.MaxCapacityBytes, MaxFileCount: updateOpts.MaxFileCount, } verifyNFSFilesystemBasics(t, space, filesystemUpdate, verifyOpts)