|
1 | 1 | package commands |
2 | 2 |
|
3 | 3 | import ( |
| 4 | + "fmt" |
| 5 | + "math" |
4 | 6 | "testing" |
5 | 7 |
|
6 | 8 | "github.com/docker/model-runner/pkg/inference" |
7 | 9 | "github.com/stretchr/testify/assert" |
8 | 10 | "github.com/stretchr/testify/require" |
9 | 11 | ) |
10 | 12 |
|
| 13 | +// TestUpCommandContextSizeFlagBehavior verifies that the --context-size flag on |
| 14 | +// the compose up command is not "changed" by default (i.e. nil ContextSize |
| 15 | +// should be sent when the flag is absent) and is marked as changed after an |
| 16 | +// explicit value is provided. |
| 17 | +func TestUpCommandContextSizeFlagBehavior(t *testing.T) { |
| 18 | + t.Run("context-size flag not changed by default", func(t *testing.T) { |
| 19 | + cmd := newUpCommand() |
| 20 | + // Parse with just the required --model flag — no --context-size. |
| 21 | + err := cmd.ParseFlags([]string{"--model", "mymodel"}) |
| 22 | + require.NoError(t, err) |
| 23 | + // The flag must NOT be marked as changed so that ContextSize is omitted |
| 24 | + // from the configure request (i.e. remains nil). |
| 25 | + assert.False(t, cmd.Flags().Changed("context-size"), |
| 26 | + "context-size must not be Changed when the flag is absent") |
| 27 | + }) |
| 28 | + |
| 29 | + t.Run("context-size flag changed after explicit value", func(t *testing.T) { |
| 30 | + cmd := newUpCommand() |
| 31 | + err := cmd.ParseFlags([]string{"--model", "mymodel", "--context-size", "4096"}) |
| 32 | + require.NoError(t, err) |
| 33 | + assert.True(t, cmd.Flags().Changed("context-size"), |
| 34 | + "context-size must be Changed when explicitly provided") |
| 35 | + }) |
| 36 | + |
| 37 | + t.Run("context-size flag changed with unlimited value -1", func(t *testing.T) { |
| 38 | + cmd := newUpCommand() |
| 39 | + err := cmd.ParseFlags([]string{"--model", "mymodel", "--context-size", "-1"}) |
| 40 | + require.NoError(t, err) |
| 41 | + assert.True(t, cmd.Flags().Changed("context-size"), |
| 42 | + "context-size must be Changed when explicitly set to -1 (unlimited)") |
| 43 | + }) |
| 44 | + |
| 45 | + t.Run("ContextSize is nil in BackendConfiguration when flag not set", func(t *testing.T) { |
| 46 | + cmd := newUpCommand() |
| 47 | + require.NoError(t, cmd.ParseFlags([]string{"--model", "mymodel"})) |
| 48 | + // Simulate the logic in compose.go RunE: only add ContextSize when Changed. |
| 49 | + backendConfig := inference.BackendConfiguration{} |
| 50 | + if cmd.Flags().Changed("context-size") { |
| 51 | + size := int32(-1) // default value |
| 52 | + backendConfig.ContextSize = &size |
| 53 | + } |
| 54 | + assert.Nil(t, backendConfig.ContextSize, |
| 55 | + "ContextSize must be nil in BackendConfiguration when --context-size is not provided") |
| 56 | + }) |
| 57 | + |
| 58 | + t.Run("ContextSize is non-nil in BackendConfiguration when flag is set", func(t *testing.T) { |
| 59 | + cmd := newUpCommand() |
| 60 | + require.NoError(t, cmd.ParseFlags([]string{"--model", "mymodel", "--context-size", "64000"})) |
| 61 | + ctxSize, err := cmd.Flags().GetInt64("context-size") |
| 62 | + require.NoError(t, err) |
| 63 | + backendConfig := inference.BackendConfiguration{} |
| 64 | + if cmd.Flags().Changed("context-size") { |
| 65 | + size := int32(ctxSize) |
| 66 | + backendConfig.ContextSize = &size |
| 67 | + } |
| 68 | + require.NotNil(t, backendConfig.ContextSize, |
| 69 | + "ContextSize must be non-nil when --context-size is provided") |
| 70 | + assert.Equal(t, int32(64000), *backendConfig.ContextSize) |
| 71 | + }) |
| 72 | + |
| 73 | + t.Run("context-size above int32 max is out of range", func(t *testing.T) { |
| 74 | + tooBig := int64(math.MaxInt32) + 1 |
| 75 | + cmd := newUpCommand() |
| 76 | + require.NoError(t, cmd.ParseFlags([]string{"--model", "mymodel", "--context-size", fmt.Sprintf("%d", tooBig)})) |
| 77 | + ctxSize, err := cmd.Flags().GetInt64("context-size") |
| 78 | + require.NoError(t, err) |
| 79 | + require.True(t, cmd.Flags().Changed("context-size")) |
| 80 | + // Simulate the range check from compose.go RunE. |
| 81 | + if ctxSize > math.MaxInt32 || ctxSize < math.MinInt32 { |
| 82 | + // Expected: would return an error in RunE. |
| 83 | + return |
| 84 | + } |
| 85 | + t.Fatal("expected out-of-range check to trigger for value above MaxInt32") |
| 86 | + }) |
| 87 | + |
| 88 | + t.Run("context-size below int32 min is out of range", func(t *testing.T) { |
| 89 | + tooSmall := int64(math.MinInt32) - 1 |
| 90 | + cmd := newUpCommand() |
| 91 | + require.NoError(t, cmd.ParseFlags([]string{"--model", "mymodel", "--context-size", fmt.Sprintf("%d", tooSmall)})) |
| 92 | + ctxSize, err := cmd.Flags().GetInt64("context-size") |
| 93 | + require.NoError(t, err) |
| 94 | + require.True(t, cmd.Flags().Changed("context-size")) |
| 95 | + if ctxSize > math.MaxInt32 || ctxSize < math.MinInt32 { |
| 96 | + return |
| 97 | + } |
| 98 | + t.Fatal("expected out-of-range check to trigger for value below MinInt32") |
| 99 | + }) |
| 100 | +} |
| 101 | + |
11 | 102 | func TestParseBackendMode(t *testing.T) { |
12 | 103 | tests := []struct { |
13 | 104 | name string |
|
0 commit comments