Resolve Client.Go-002, -003 code-review findings
Client.Go-002: the Events/EventsAfter compatibility path silently dropped events when the 16-slot results channel filled — it cancelled the stream and closed the channel with no error delivered. sendEventResult now evicts an old buffered event and delivers a terminal EventResult carrying the new exported ErrEventBufferOverflow before close, so the overflow is observable. Client.Go-003: parseInt32List panicked on a malformed -item-handles token, crashing the CLI with a stack trace. It now returns an error that runUnsubscribeBulk propagates, exiting 2 with a clean message. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -331,6 +331,11 @@ func runUnsubscribeBulk(ctx context.Context, args []string, stdout, stderr io.Wr
|
||||
return errors.New("session-id and item-handles are required")
|
||||
}
|
||||
|
||||
handles, err := parseInt32List(*itemHandles)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
client, options, err := dialForCommand(ctx, common)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -338,7 +343,7 @@ func runUnsubscribeBulk(ctx context.Context, args []string, stdout, stderr io.Wr
|
||||
defer client.Close()
|
||||
|
||||
session := mxgateway.NewSessionForID(client, *sessionID)
|
||||
results, err := session.UnsubscribeBulk(ctx, int32(*serverHandle), parseInt32List(*itemHandles))
|
||||
results, err := session.UnsubscribeBulk(ctx, int32(*serverHandle), handles)
|
||||
return writeBulkOutput(stdout, *jsonOutput, "unsubscribe-bulk", options, results, err)
|
||||
}
|
||||
|
||||
@@ -514,7 +519,7 @@ func parseStringList(value string) []string {
|
||||
return items
|
||||
}
|
||||
|
||||
func parseInt32List(value string) []int32 {
|
||||
func parseInt32List(value string) ([]int32, error) {
|
||||
parts := strings.Split(value, ",")
|
||||
items := make([]int32, 0, len(parts))
|
||||
for _, part := range parts {
|
||||
@@ -524,11 +529,11 @@ func parseInt32List(value string) []int32 {
|
||||
}
|
||||
parsed, err := strconv.ParseInt(item, 10, 32)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return nil, fmt.Errorf("invalid item handle %q: %w", item, err)
|
||||
}
|
||||
items = append(items, int32(parsed))
|
||||
}
|
||||
return items
|
||||
return items, nil
|
||||
}
|
||||
|
||||
func bindCommonFlags(flags *flag.FlagSet) *commonOptions {
|
||||
|
||||
@@ -56,3 +56,32 @@ func TestParseValueBuildsTypedValue(t *testing.T) {
|
||||
t.Fatalf("int32 value = %d, want 123", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseInt32ListParsesValidTokens(t *testing.T) {
|
||||
items, err := parseInt32List("1, 2 ,3")
|
||||
if err != nil {
|
||||
t.Fatalf("parseInt32List() error = %v", err)
|
||||
}
|
||||
want := []int32{1, 2, 3}
|
||||
if len(items) != len(want) {
|
||||
t.Fatalf("parseInt32List() = %v, want %v", items, want)
|
||||
}
|
||||
for i := range want {
|
||||
if items[i] != want[i] {
|
||||
t.Fatalf("parseInt32List()[%d] = %d, want %d", i, items[i], want[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseInt32ListReturnsErrorOnMalformedToken(t *testing.T) {
|
||||
items, err := parseInt32List("1,foo")
|
||||
if err == nil {
|
||||
t.Fatalf("parseInt32List() error = nil, want a parse error; items = %v", items)
|
||||
}
|
||||
if items != nil {
|
||||
t.Fatalf("parseInt32List() items = %v, want nil on error", items)
|
||||
}
|
||||
if !strings.Contains(err.Error(), "foo") {
|
||||
t.Fatalf("parseInt32List() error = %q, want it to name the bad token", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user