From 18957773f2b112fafcc2fd0638b537a8058cefd2 Mon Sep 17 00:00:00 2001 From: Kevin Klues Date: Mon, 27 Mar 2023 09:48:34 +0000 Subject: [PATCH] Add function for AssertValidMigProfileFormat This does not verify that the profile is a valid profile for the current platform, but rather that it simply adheres to the proper formatting of a MIG profile string. Signed-off-by: Kevin Klues --- pkg/nvlib/device/api.go | 1 + pkg/nvlib/device/mig_profile.go | 58 +++++++++++++++++----------- pkg/nvlib/device/mig_profile_test.go | 58 ++++++++++++++++++++++++++-- 3 files changed, 92 insertions(+), 25 deletions(-) diff --git a/pkg/nvlib/device/api.go b/pkg/nvlib/device/api.go index 9886d7b..777789b 100644 --- a/pkg/nvlib/device/api.go +++ b/pkg/nvlib/device/api.go @@ -22,6 +22,7 @@ import ( // Interface provides the API to the 'device' package type Interface interface { + AssertValidMigProfileFormat(profile string) error GetDevices() ([]Device, error) GetMigDevices() ([]MigDevice, error) GetMigProfiles() ([]MigProfile, error) diff --git a/pkg/nvlib/device/mig_profile.go b/pkg/nvlib/device/mig_profile.go index 7581db5..a5c455e 100644 --- a/pkg/nvlib/device/mig_profile.go +++ b/pkg/nvlib/device/mig_profile.go @@ -119,6 +119,12 @@ func (d *devicelib) NewMigProfile(giProfileID, ciProfileID, ciEngProfileID int, return p, nil } +// AssertValidMigProfileFormat checks if the string is in the proper format to represent a MIG profile +func (d *devicelib) AssertValidMigProfileFormat(profile string) error { + _, _, _, _, err := parseMigProfile(profile) + return err +} + // ParseMigProfile converts a string representation of a MigProfile into an object func (d *devicelib) ParseMigProfile(profile string) (MigProfile, error) { profiles, err := d.GetMigProfiles() @@ -181,16 +187,7 @@ func (p *MigProfileInfo) Equals(other MigProfile) bool { // Matches checks if a MigProfile matches the string passed in func (p *MigProfileInfo) Matches(profile string) bool { - // If we are handed the empty string, there is nothing to check - if profile == "" { - return false - } - - // Split by + to separate out attributes - split := strings.SplitN(profile, "+", 2) - - // Check to make sure the c, g, and gb values match - c, g, gb, err := parseMigProfileFields(split[0]) + c, g, gb, attrs, err := parseMigProfile(profile) if err != nil { return false } @@ -203,17 +200,6 @@ func (p *MigProfileInfo) Matches(profile string) bool { if gb != p.GB { return false } - - // If we have no attributes we are done - if len(split) == 1 { - return true - } - - // Make sure we have the same set of attributes - attrs, err := parseMigProfileAttributes(split[1]) - if err != nil { - return false - } if len(attrs) != len(p.Attributes) { return false } @@ -224,10 +210,38 @@ func (p *MigProfileInfo) Matches(profile string) bool { return false } } - return true } +func parseMigProfile(profile string) (int, int, int, []string, error) { + // If we are handed the empty string, we cannot parse it + if profile == "" { + return -1, -1, -1, nil, fmt.Errorf("profile is the empty string") + } + + // Split by + to separate out attributes + split := strings.SplitN(profile, "+", 2) + + // Check to make sure the c, g, and gb values match + c, g, gb, err := parseMigProfileFields(split[0]) + if err != nil { + return -1, -1, -1, nil, fmt.Errorf("cannot parse fields of '%v': %v", profile, err) + } + + // If we have no attributes we are done + if len(split) == 1 { + return c, g, gb, nil, nil + } + + // Make sure we have the same set of attributes + attrs, err := parseMigProfileAttributes(split[1]) + if err != nil { + return -1, -1, -1, nil, fmt.Errorf("cannot parse attributes of '%v': %v", profile, err) + } + + return c, g, gb, attrs, nil +} + func parseMigProfileField(s string, field string) (int, error) { if strings.TrimSpace(s) != s { return -1, fmt.Errorf("leading or trailing spaces on '%%d%s'", field) diff --git a/pkg/nvlib/device/mig_profile_test.go b/pkg/nvlib/device/mig_profile_test.go index d22550a..8287455 100644 --- a/pkg/nvlib/device/mig_profile_test.go +++ b/pkg/nvlib/device/mig_profile_test.go @@ -28,232 +28,278 @@ func TestParseMigProfile(t *testing.T) { testCases := []struct { description string device string - valid bool + validFormat bool + validDevice bool }{ { "Empty device type", "", false, + false, }, { "Valid 1g.5gb", "1g.5gb", true, + true, }, { "Valid 1c.1g.5gb", "1c.1g.5gb", true, + true, }, { "Valid 1g.5gb+me", "1g.5gb+me", true, + true, }, { "Valid 1c.1g.5gb+me", "1c.1g.5gb+me", true, + true, }, { "Invalid 0g.0gb", "0g.0gb", + true, false, }, { "Invalid 0c.0g.0gb", "0c.0g.0gb", + true, false, }, { "Invalid 10000g.500000gb", "10000g.500000gb", + true, false, }, { "Invalid 10000c.10000g.500000gb", "10000c.10000g.500000gb", + true, false, }, { "Invalid ' 1c.1g.5gb'", " 1c.1g.5gb", false, + false, }, { "Invalid '1 c.1g.5gb'", "1 c.1g.5gb", false, + false, }, { "Invalid '1c .1g.5gb'", "1c .1g.5gb", false, + false, }, { "Invalid '1c. 1g.5gb'", "1c. 1g.5gb", false, + false, }, { "Invalid '1c.1 g.5gb'", "1c.1 g.5gb", false, + false, }, { "Invalid '1c.1g .5gb'", "1c.1g .5gb", false, + false, }, { "Invalid '1c.1g. 5gb'", "1c.1g. 5gb", false, + false, }, { "Invalid '1c.1g.5 gb'", "1c.1g.5 gb", false, + false, }, { "Invalid '1c.1g.5g b'", "1c.1g.5g b", false, + false, }, { "Invalid '1c.1g.5gb '", "1c.1g.5gb ", false, + false, }, { "Invalid '1c . 1g . 5gb'", "1c . 1g . 5gb", false, + false, }, { "Invalid 1c.f1g.5gb", "1c.f1g.5gb", false, + false, }, { "Invalid 1r.1g.5gb", "1r.1g.5gb", false, + false, }, { "Invalid 1g.5gbk", "1g.5gbk", false, + false, }, { "Invalid 1g.5", "1g.5", false, + false, }, { "Invalid g.5gb", "1g.5", false, + false, }, { "Invalid g.5gb", "g.5gb", false, + false, }, { "Invalid 1g.gb", "1g.gb", false, + false, }, { "Invalid 1g.5gb+me,me", "1g.5gb+me,me", false, + false, }, { "Invalid 1g.5gb+me,you,them", "1g.5gb+me,you,them", + true, false, }, { "Invalid 1c.1g.5gb+me,you,them", "1c.1g.5gb+me,you,them", + true, false, }, { "Invalid 1g.5gb+", "1g.5gb+", false, + false, }, { "Invalid 1g.5gb +", "1g.5gb+", false, + false, }, { "Invalid 1g.5gb+ ", "1g.5gb+", false, + false, }, { "Invalid 1g.5gb+ ,", "1g.5gb+", false, + false, }, { "Invalid 1g.5gb+,", "1g.5gb+", false, + false, }, { "Invalid 1g.5gb+,,", "1g.5gb+", false, + false, }, { "Invalid 1g.5gb+me,", "1g.5gb+", false, + false, }, { "Invalid 1g.5gb+me,,", "1g.5gb+", false, + false, }, { "Invalid 1g.5gb+me, ", "1g.5gb+", false, + false, }, { "Invalid 1g.5gb+2me", "1g.5gb+2me", false, + false, }, { "Inavlid 1g.5gb*me", "1g.5gb*me", false, + false, }, { "Invalid 1c.1g.5gb*me", "1c.1g.5gb*me", false, + false, }, { "Invalid 1g.5gb*me,you,them", "1g.5gb*me,you,them", false, + false, }, { "Invalid 1c.1g.5gb*me,you,them", "1c.1g.5gb*me,you,them", false, + false, }, { "Invalid bogus", "bogus", false, + false, }, } @@ -308,8 +354,14 @@ func TestParseMigProfile(t *testing.T) { d := New(WithNvml(mockNvml), WithVerifySymbols(false)) for _, tc := range testCases { t.Run(tc.description, func(t *testing.T) { - _, err := d.ParseMigProfile(tc.device) - if tc.valid { + err := d.AssertValidMigProfileFormat(tc.device) + if tc.validFormat { + require.Nil(t, err) + } else { + require.Error(t, err) + } + _, err = d.ParseMigProfile(tc.device) + if tc.validDevice { require.Nil(t, err) } else { require.Error(t, err)