@@ -18,14 +18,17 @@ package main
1818import (
1919 "bytes"
2020 "context"
21+ "flag"
2122 "fmt"
2223 "os"
2324 "path/filepath"
25+ "strings"
2426 "testing"
2527 "time"
2628
2729 "github.com/stretchr/testify/assert"
2830 "github.com/stretchr/testify/require"
31+ "github.com/urfave/cli"
2932
3033 "github.com/NVIDIA/fleet-intelligence-agent/internal/config"
3134 "github.com/NVIDIA/fleet-intelligence-agent/internal/enrollment"
@@ -288,42 +291,108 @@ func TestEnrollCommandPassesOptionalMetadata(t *testing.T) {
288291 require .NoError (t , err )
289292}
290293
291- func TestEnrollCommandTreatsExplicitEmptyMetadataAsClear (t * testing.T ) {
292- useMissingFleetintEnvFile (t )
294+ func TestValidatedOptionalMetadataFlagValueAllowsExplicitEmpty (t * testing.T ) {
295+ flagSet := flag .NewFlagSet ("enroll" , flag .ContinueOnError )
296+ flagSet .String ("node-group" , "" , "" )
297+ require .NoError (t , flagSet .Set ("node-group" , "" ))
298+ cliContext := cli .NewContext (cli .NewApp (), flagSet , nil )
293299
294- originalRunPrecheck := runPrecheck
295- originalEnrollWorkflow := performEnrollWorkflow
296- t .Cleanup (func () {
297- runPrecheck = originalRunPrecheck
298- performEnrollWorkflow = originalEnrollWorkflow
300+ value , err := validatedOptionalMetadataFlagValue (cliContext , "node-group" , "Node group" )
301+ require .NoError (t , err )
302+ require .NotNil (t , value )
303+ require .Empty (t , * value )
304+ }
305+
306+ func TestValidatedOptionalMetadataFlagValueRejectsReservedUnassignedName (t * testing.T ) {
307+ flagSet := flag .NewFlagSet ("enroll" , flag .ContinueOnError )
308+ flagSet .String ("node-group" , "" , "" )
309+ require .NoError (t , flagSet .Set ("node-group" , "unassigned" ))
310+ cliContext := cli .NewContext (cli .NewApp (), flagSet , nil )
311+
312+ _ , err := validatedOptionalMetadataFlagValue (cliContext , "node-group" , "Node group" )
313+ require .ErrorContains (t , err , `Node group name "Unassigned" is reserved; use empty value to clear assignment` )
314+ }
315+
316+ func TestEnrollCommandRejectsInvalidMetadataCharacters (t * testing.T ) {
317+ app := App ()
318+ app .Writer = & bytes.Buffer {}
319+
320+ err := app .Run ([]string {
321+ "fleetint" , "enroll" ,
322+ "--endpoint" , "https://example.com" ,
323+ "--token" , "token" ,
324+ "--compute-zone" , "@bad-zone" ,
299325 })
326+ require .ErrorContains (t , err , "Compute zone name must start with a letter" )
327+ }
300328
301- runPrecheck = func () (precheck.Result , error ) {
302- return precheck.Result {
303- Checks : []precheck.Check {
304- {Name : "gpu-present" , Message : "ok" , Passed : true },
305- },
306- }, nil
329+ func TestEnrollCommandRejectsOverlongMetadataNames (t * testing.T ) {
330+ app := App ()
331+ app .Writer = & bytes.Buffer {}
332+ longName := strings .Repeat ("a" , 256 )
333+
334+ err := app .Run ([]string {
335+ "fleetint" , "enroll" ,
336+ "--endpoint" , "https://example.com" ,
337+ "--token" , "token" ,
338+ "--node-group" , longName ,
339+ })
340+ require .ErrorContains (t , err , "Node group name must be 255 characters or fewer" )
341+ }
342+
343+ func TestValidateReservedPairMetadata (t * testing.T ) {
344+ strPtr := func (v string ) * string { return & v }
345+ tests := []struct {
346+ name string
347+ nodeGroup * string
348+ computeZone * string
349+ wantErr bool
350+ }{
351+ {name : "both omitted" , nodeGroup : nil , computeZone : nil , wantErr : false },
352+ {name : "both empty" , nodeGroup : strPtr ("" ), computeZone : strPtr ("" ), wantErr : false },
353+ {name : "both non-empty" , nodeGroup : strPtr ("ng-a" ), computeZone : strPtr ("cz-a" ), wantErr : false },
354+ {name : "node-group only" , nodeGroup : strPtr ("ng-a" ), computeZone : nil , wantErr : true },
355+ {name : "compute-zone only" , nodeGroup : nil , computeZone : strPtr ("cz-a" ), wantErr : true },
356+ {name : "node-group empty compute-zone non-empty" , nodeGroup : strPtr ("" ), computeZone : strPtr ("cz-a" ), wantErr : true },
357+ {name : "node-group non-empty compute-zone empty" , nodeGroup : strPtr ("ng-a" ), computeZone : strPtr ("" ), wantErr : true },
307358 }
308359
309- performEnrollWorkflow = func (ctx context.Context , baseEndpoint , sakToken string , cfg * config.Config , metadata * enrollment.EnrollMetadata ) error {
310- require .NotNil (t , metadata )
311- require .NotNil (t , metadata .NodeGroup )
312- require .Empty (t , * metadata .NodeGroup )
313- require .NotNil (t , metadata .ComputeZone )
314- require .Empty (t , * metadata .ComputeZone )
315- return nil
360+ for _ , tc := range tests {
361+ t .Run (tc .name , func (t * testing.T ) {
362+ err := validateReservedPairMetadata (tc .nodeGroup , tc .computeZone )
363+ if tc .wantErr {
364+ require .ErrorContains (t , err , "--node-group and --compute-zone must be both omitted, both empty, or both non-empty" )
365+ return
366+ }
367+ require .NoError (t , err )
368+ })
316369 }
370+ }
317371
372+ func TestEnrollCommandRejectsMixedReservedPairValues (t * testing.T ) {
318373 app := App ()
319374 app .Writer = & bytes.Buffer {}
320375
321376 err := app .Run ([]string {
322377 "fleetint" , "enroll" ,
323378 "--endpoint" , "https://example.com" ,
324379 "--token" , "token" ,
325- "--node-group= " ,
326- "--compute-zone= " ,
380+ "--node-group" , " " ,
381+ "--compute-zone" , "cz-a " ,
327382 })
328- require .NoError (t , err )
383+ require .ErrorContains (t , err , "--node-group and --compute-zone must be both omitted, both empty, or both non-empty" )
384+ }
385+
386+ func TestEnrollCommandRejectsReservedUnassignedName (t * testing.T ) {
387+ app := App ()
388+ app .Writer = & bytes.Buffer {}
389+
390+ err := app .Run ([]string {
391+ "fleetint" , "enroll" ,
392+ "--endpoint" , "https://example.com" ,
393+ "--token" , "token" ,
394+ "--node-group" , "Unassigned" ,
395+ "--compute-zone" , "cz-a" ,
396+ })
397+ require .ErrorContains (t , err , `Node group name "Unassigned" is reserved; use empty value to clear assignment` )
329398}
0 commit comments