Skip to content

Commit 61d7a95

Browse files
authored
fix(pulsaradmin): preserve explicit zero receiver queue size (#1529)
Signed-off-by: Rui Fu <rfu@apache.org>
1 parent fd604fa commit 61d7a95

2 files changed

Lines changed: 167 additions & 8 deletions

File tree

pulsaradmin/pkg/utils/consumer_config.go

Lines changed: 61 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,66 @@
1717

1818
package utils
1919

20+
import "encoding/json"
21+
2022
type ConsumerConfig struct {
21-
SchemaType string `json:"schemaType,omitempty" yaml:"schemaType"`
22-
SerdeClassName string `json:"serdeClassName,omitempty" yaml:"serdeClassName"`
23-
RegexPattern bool `json:"regexPattern,omitempty" yaml:"regexPattern"`
24-
ReceiverQueueSize int `json:"receiverQueueSize,omitempty" yaml:"receiverQueueSize"`
25-
SchemaProperties map[string]string `json:"schemaProperties,omitempty" yaml:"schemaProperties"`
26-
ConsumerProperties map[string]string `json:"consumerProperties,omitempty" yaml:"consumerProperties"`
27-
CryptoConfig *CryptoConfig `json:"cryptoConfig,omitempty" yaml:"cryptoConfig"`
28-
PoolMessages bool `json:"poolMessages,omitempty" yaml:"poolMessages"`
23+
SchemaType string `json:"schemaType,omitempty" yaml:"schemaType"`
24+
SerdeClassName string `json:"serdeClassName,omitempty" yaml:"serdeClassName"`
25+
RegexPattern bool `json:"regexPattern,omitempty" yaml:"regexPattern"`
26+
ReceiverQueueSize int `json:"-" yaml:"receiverQueueSize"`
27+
receiverQueueSizeSet bool
28+
SchemaProperties map[string]string `json:"schemaProperties,omitempty" yaml:"schemaProperties"`
29+
ConsumerProperties map[string]string `json:"consumerProperties,omitempty" yaml:"consumerProperties"`
30+
CryptoConfig *CryptoConfig `json:"cryptoConfig,omitempty" yaml:"cryptoConfig"`
31+
PoolMessages bool `json:"poolMessages,omitempty" yaml:"poolMessages"`
32+
}
33+
34+
// SetReceiverQueueSize records an explicitly configured receiver queue size. It is required when
35+
// the value is zero so JSON marshaling can distinguish zero from an unset value.
36+
func (c *ConsumerConfig) SetReceiverQueueSize(value int) {
37+
c.ReceiverQueueSize = value
38+
c.receiverQueueSizeSet = true
39+
}
40+
41+
// HasReceiverQueueSize reports whether receiverQueueSize was explicitly configured or returned by
42+
// the server. Non-zero values assigned directly remain supported for backward compatibility.
43+
func (c ConsumerConfig) HasReceiverQueueSize() bool {
44+
return c.receiverQueueSizeSet || c.ReceiverQueueSize != 0
45+
}
46+
47+
type consumerConfigJSON ConsumerConfig
48+
49+
func (c ConsumerConfig) MarshalJSON() ([]byte, error) {
50+
var receiverQueueSize *int
51+
if c.HasReceiverQueueSize() {
52+
value := c.ReceiverQueueSize
53+
receiverQueueSize = &value
54+
}
55+
56+
return json.Marshal(struct {
57+
consumerConfigJSON
58+
ReceiverQueueSize *int `json:"receiverQueueSize,omitempty"`
59+
}{
60+
consumerConfigJSON: consumerConfigJSON(c),
61+
ReceiverQueueSize: receiverQueueSize,
62+
})
63+
}
64+
65+
func (c *ConsumerConfig) UnmarshalJSON(data []byte) error {
66+
var value struct {
67+
consumerConfigJSON
68+
ReceiverQueueSize *int `json:"receiverQueueSize,omitempty"`
69+
}
70+
if err := json.Unmarshal(data, &value); err != nil {
71+
return err
72+
}
73+
74+
*c = ConsumerConfig(value.consumerConfigJSON)
75+
c.ReceiverQueueSize = 0
76+
c.receiverQueueSizeSet = false
77+
if value.ReceiverQueueSize != nil {
78+
c.SetReceiverQueueSize(*value.ReceiverQueueSize)
79+
}
80+
81+
return nil
2982
}
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package utils
19+
20+
import (
21+
"encoding/json"
22+
"testing"
23+
24+
"github.com/stretchr/testify/assert"
25+
"github.com/stretchr/testify/require"
26+
)
27+
28+
func TestConsumerConfigReceiverQueueSizeJSON(t *testing.T) {
29+
tests := []struct {
30+
name string
31+
config ConsumerConfig
32+
want string
33+
}{
34+
{
35+
name: "unset is omitted",
36+
config: ConsumerConfig{},
37+
want: `{}`,
38+
},
39+
{
40+
name: "direct non-zero assignment and other fields remain supported",
41+
config: ConsumerConfig{
42+
SchemaType: "STRING",
43+
RegexPattern: true,
44+
ReceiverQueueSize: 100,
45+
SchemaProperties: map[string]string{"schema": "value"},
46+
ConsumerProperties: map[string]string{"consumer": "value"},
47+
PoolMessages: true,
48+
},
49+
want: `{
50+
"schemaType":"STRING",
51+
"regexPattern":true,
52+
"receiverQueueSize":100,
53+
"schemaProperties":{"schema":"value"},
54+
"consumerProperties":{"consumer":"value"},
55+
"poolMessages":true
56+
}`,
57+
},
58+
{
59+
name: "explicit zero is included",
60+
config: func() ConsumerConfig {
61+
config := ConsumerConfig{}
62+
config.SetReceiverQueueSize(0)
63+
return config
64+
}(),
65+
want: `{"receiverQueueSize":0}`,
66+
},
67+
}
68+
69+
for _, test := range tests {
70+
t.Run(test.name, func(t *testing.T) {
71+
data, err := json.Marshal(test.config)
72+
require.NoError(t, err)
73+
assert.JSONEq(t, test.want, string(data))
74+
})
75+
}
76+
}
77+
78+
func TestConsumerConfigReceiverQueueSizeUnmarshalJSON(t *testing.T) {
79+
tests := []struct {
80+
name string
81+
payload string
82+
want int
83+
isSet bool
84+
schema string
85+
}{
86+
{name: "unset", payload: `{}`, want: 0, isSet: false},
87+
{name: "explicit zero", payload: `{"receiverQueueSize":0}`, want: 0, isSet: true},
88+
{
89+
name: "non-zero with other fields",
90+
payload: `{"receiverQueueSize":100,"schemaType":"STRING"}`,
91+
want: 100,
92+
isSet: true,
93+
schema: "STRING",
94+
},
95+
}
96+
97+
for _, test := range tests {
98+
t.Run(test.name, func(t *testing.T) {
99+
var config ConsumerConfig
100+
require.NoError(t, json.Unmarshal([]byte(test.payload), &config))
101+
assert.Equal(t, test.want, config.ReceiverQueueSize)
102+
assert.Equal(t, test.isSet, config.HasReceiverQueueSize())
103+
assert.Equal(t, test.schema, config.SchemaType)
104+
})
105+
}
106+
}

0 commit comments

Comments
 (0)