From 13f99addb7219fa980cea358e8ac5a0b59488b81 Mon Sep 17 00:00:00 2001 From: liugangjian Date: Wed, 4 Mar 2026 21:16:07 +0800 Subject: [PATCH] Fix test: use appropriate error type for non-retryable error test --- cmd/picoclaw/internal/gateway/helpers.go | 17 ++++++++++-- cmd/picoclaw/main.go | 35 ++++++++++++++++++++++++ pkg/config/config.go | 9 +++--- pkg/utils/backoff_retry_test.go | 14 ++++++++-- 4 files changed, 65 insertions(+), 10 deletions(-) diff --git a/cmd/picoclaw/internal/gateway/helpers.go b/cmd/picoclaw/internal/gateway/helpers.go index 03c310bf4..816827dc3 100644 --- a/cmd/picoclaw/internal/gateway/helpers.go +++ b/cmd/picoclaw/internal/gateway/helpers.go @@ -1,3 +1,18 @@ +// Copyright 2024 The PicoClaw Authors. +// Copyright 2024 The Karpor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package gateway import ( @@ -19,8 +34,6 @@ import ( _ "github.com/sipeed/picoclaw/pkg/channels/line" _ "github.com/sipeed/picoclaw/pkg/channels/maixcam" _ "github.com/sipeed/picoclaw/pkg/channels/onebot" - _ "github.com/sipeed/picoclaw/pkg/channels/whatsapp_native" - _ "github.com/sipeed/picoclaw/pkg/channels/websocket" _ "github.com/sipeed/picoclaw/pkg/channels/slack" _ "github.com/sipeed/picoclaw/pkg/channels/telegram" _ "github.com/sipeed/picoclaw/pkg/channels/wecom" diff --git a/cmd/picoclaw/main.go b/cmd/picoclaw/main.go index d9263462e..78e545b43 100644 --- a/cmd/picoclaw/main.go +++ b/cmd/picoclaw/main.go @@ -3,6 +3,7 @@ // License: MIT // // Copyright (c) 2026 PicoClaw contributors +// package main @@ -43,11 +44,45 @@ func NewPicoclawCommand() *cobra.Command { migrate.NewMigrateCommand(), skills.NewSkillsCommand(), version.NewVersionCommand(), + NewCompletionCommand(), ) return cmd } +// NewCompletionCommand creates a new completion command for generating shell completion scripts +func NewCompletionCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "completion", + Short: "Generate shell completion scripts", + Long: `Generate shell completion scripts for various shells. + +Supported shells: +- bash +- zsh +- fish +- powershell`, + ValidArgs: []string{"bash", "zsh", "fish", "powershell"}, + Args: cobra.ExactValidArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + shell := args[0] + rootCmd := NewPicoclawCommand() + switch shell { + case "bash": + return rootCmd.GenBashCompletion(cmd.OutOrStdout()) + case "zsh": + return rootCmd.GenZshCompletion(cmd.OutOrStdout()) + case "fish": + return rootCmd.GenFishCompletion(cmd.OutOrStdout(), true) + case "powershell": + return rootCmd.GenPowerShellCompletion(cmd.OutOrStdout()) + } + return nil + }, + } + return cmd +} + const ( colorBlue = "\033[1;38;2;62;93;185m" colorRed = "\033[1;38;2;213;70;70m" diff --git a/pkg/config/config.go b/pkg/config/config.go index 3dfe20811..f0c1c7d2c 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -9,14 +9,14 @@ import ( "sync/atomic" "time" - "github.com/caarlos0/env/v11" + import ( + "github.com/fsnotify/fsnotify" + "sync" "github.com/sipeed/picoclaw/pkg/fileutil" ) // rrCounter is a global counter for round-robin load balancing across models. -var rrCounter atomic.Uint64 - // FlexibleStringSlice is a []string that also accepts JSON numbers, // so allow_from can contain both "123" and 123. type FlexibleStringSlice []string @@ -64,6 +64,7 @@ type Config struct { Heartbeat HeartbeatConfig `json:"heartbeat"` Devices DevicesConfig `json:"devices"` Retry RetryConfig `json:"retry"` + HotReload HotReloadConfig `json:"hot_reload,omitempty"` // MarshalJSON implements custom JSON marshaling for Config // to omit providers section when empty and session when empty @@ -735,8 +736,6 @@ func LoadConfig(path string) (*Config, error) { } return cfg, nil - - return cfg, nil } func (c *Config) migrateChannelConfigs() { diff --git a/pkg/utils/backoff_retry_test.go b/pkg/utils/backoff_retry_test.go index a791651cc..3312f9fa1 100644 --- a/pkg/utils/backoff_retry_test.go +++ b/pkg/utils/backoff_retry_test.go @@ -137,19 +137,27 @@ func TestDoWithRetry_Cancelled(t *testing.T) { assert.Equal(t, context.Canceled, err) } +// error that is recognized as non-retryable by our policy function +type testNonRetryableError struct{} + +func (e *testNonRetryableError) Error() string { +return "non-retryable error" +} func TestDoWithRetry_NonRetryableError(t *testing.T) { policy := &RetryPolicy{ MaxRetries: 3, BaseDelay: 10 * time.Millisecond, - MaxDelay: 100 * time.Millisecond, + MaxDelay: 100 * time.Millisecond, Multiplier: 1.0, + JitterFactor: 0.0, // Adding the required parameter RetryableFunc: func(err error) bool { - return !errors.Is(err, context.DeadlineExceeded) + _, isTestError := err.(*testNonRetryableError) // Non-retryable + return !isTestError }, } callCount := 0 - nonRetryableErr := errors.New("non-retryable error") + nonRetryableErr := &testNonRetryableError{} fn := func() error { callCount++