项目文件夹

文件
Asim Aslam c7657f73f4
goreleaser / goreleaser (push) Has been cancelled
Refactor agent plan storage, update docs, and release v6 (#2977)
* test(harness): read agent plan from the scoped store

The store-scoping change moved an agent's plan from the default table
key agent/{name}/plan to its own table (database "agent", table {name},
key "plan"). The plan-delegate harness tests still read the old key and
failed with 'not found'; read through store.Scope(mem, "agent", name)
like the agent does.

* docs: orient agents-first across README, landing, and docs overview

Lead with agents (then services and flows), surface MCP + A2A as the
interop story, and frame agents as services. Landing hero and feature
grid reordered agents-first with an A2A gateway card.

* v6: module path go-micro.dev/v6, TLS secure by default, NewService

Cut v6. Three breaking changes, bundled so the major bump is paid once:

- Module path go-micro.dev/v5 -> go-micro.dev/v6 across all imports + go.mod.
- TLS verification on by default (was off). MICRO_TLS_SECURE removed;
  MICRO_TLS_INSECURE=true opts out for self-signed/dev.
- micro.NewService(name, opts...) is the canonical service constructor,
  symmetric with NewAgent/NewFlow; micro.New kept as a deprecated alias;
  the old name-less NewService(opts...) removed. Generators emit NewService.

Also ports the JWT auth token provider in-module (go-micro.dev/v6/auth/jwt/token
on golang-jwt/jwt/v5), dropping the v5-pinned github.com/micro/plugins/v5/auth/jwt
and the deprecated dgrijalva/jwt-go.

Docs/README/landing updated to v6 and @latest; v5->v6 migration guide added;
CHANGELOG cut as [6.0.0]. Blog posts left at their historical versions.

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-06-18 11:55:35 +01:00

454 行
9.0 KiB
Go

package util
import (
"context"
"reflect"
"strings"
"testing"
"github.com/davecgh/go-spew/spew"
"go-micro.dev/v6/metadata"
goregistry "go-micro.dev/v6/registry"
)
type parseCase struct {
args []string
values *goregistry.Value
expected map[string]interface{}
}
func TestDynamicFlagParsing(t *testing.T) {
cases := []parseCase{
{
args: []string{"--ss=a,b"},
values: &goregistry.Value{
Values: []*goregistry.Value{
{
Name: "ss",
Type: "[]string",
},
},
},
expected: map[string]interface{}{
"ss": []interface{}{"a", "b"},
},
},
{
args: []string{"--ss", "a,b"},
values: &goregistry.Value{
Values: []*goregistry.Value{
{
Name: "ss",
Type: "[]string",
},
},
},
expected: map[string]interface{}{
"ss": []interface{}{"a", "b"},
},
},
{
args: []string{"--ss=a", "--ss=b"},
values: &goregistry.Value{
Values: []*goregistry.Value{
{
Name: "ss",
Type: "[]string",
},
},
},
expected: map[string]interface{}{
"ss": []interface{}{"a", "b"},
},
},
{
args: []string{"--ss", "a", "--ss", "b"},
values: &goregistry.Value{
Values: []*goregistry.Value{
{
Name: "ss",
Type: "[]string",
},
},
},
expected: map[string]interface{}{
"ss": []interface{}{"a", "b"},
},
},
{
args: []string{"--bs=true,false"},
values: &goregistry.Value{
Values: []*goregistry.Value{
{
Name: "bs",
Type: "[]bool",
},
},
},
expected: map[string]interface{}{
"bs": []interface{}{true, false},
},
},
{
args: []string{"--bs", "true,false"},
values: &goregistry.Value{
Values: []*goregistry.Value{
{
Name: "bs",
Type: "[]bool",
},
},
},
expected: map[string]interface{}{
"bs": []interface{}{true, false},
},
},
{
args: []string{"--bs=true", "--bs=false"},
values: &goregistry.Value{
Values: []*goregistry.Value{
{
Name: "bs",
Type: "[]bool",
},
},
},
expected: map[string]interface{}{
"bs": []interface{}{true, false},
},
},
{
args: []string{"--bs", "true", "--bs", "false"},
values: &goregistry.Value{
Values: []*goregistry.Value{
{
Name: "bs",
Type: "[]bool",
},
},
},
expected: map[string]interface{}{
"bs": []interface{}{true, false},
},
},
{
args: []string{"--is=10,20"},
values: &goregistry.Value{
Values: []*goregistry.Value{
{
Name: "is",
Type: "[]int32",
},
},
},
expected: map[string]interface{}{
"is": []interface{}{int32(10), int32(20)},
},
},
{
args: []string{"--is", "10,20"},
values: &goregistry.Value{
Values: []*goregistry.Value{
{
Name: "is",
Type: "[]int32",
},
},
},
expected: map[string]interface{}{
"is": []interface{}{int32(10), int32(20)},
},
},
{
args: []string{"--is=10", "--is=20"},
values: &goregistry.Value{
Values: []*goregistry.Value{
{
Name: "is",
Type: "[]int32",
},
},
},
expected: map[string]interface{}{
"is": []interface{}{int32(10), int32(20)},
},
},
{
args: []string{"--is", "10", "--is", "20"},
values: &goregistry.Value{
Values: []*goregistry.Value{
{
Name: "is",
Type: "[]int32",
},
},
},
expected: map[string]interface{}{
"is": []interface{}{int32(10), int32(20)},
},
},
{
args: []string{"--is=10,20"},
values: &goregistry.Value{
Values: []*goregistry.Value{
{
Name: "is",
Type: "[]int64",
},
},
},
expected: map[string]interface{}{
"is": []interface{}{int64(10), int64(20)},
},
},
{
args: []string{"--is", "10,20"},
values: &goregistry.Value{
Values: []*goregistry.Value{
{
Name: "is",
Type: "[]int64",
},
},
},
expected: map[string]interface{}{
"is": []interface{}{int64(10), int64(20)},
},
},
{
args: []string{"--is=10", "--is=20"},
values: &goregistry.Value{
Values: []*goregistry.Value{
{
Name: "is",
Type: "[]int64",
},
},
},
expected: map[string]interface{}{
"is": []interface{}{int64(10), int64(20)},
},
},
{
args: []string{"--is", "10", "--is", "20"},
values: &goregistry.Value{
Values: []*goregistry.Value{
{
Name: "is",
Type: "[]int64",
},
},
},
expected: map[string]interface{}{
"is": []interface{}{int64(10), int64(20)},
},
},
{
args: []string{"--fs=10.1,20.2"},
values: &goregistry.Value{
Values: []*goregistry.Value{
{
Name: "fs",
Type: "[]float64",
},
},
},
expected: map[string]interface{}{
"fs": []interface{}{float64(10.1), float64(20.2)},
},
},
{
args: []string{"--fs", "10.1,20.2"},
values: &goregistry.Value{
Values: []*goregistry.Value{
{
Name: "fs",
Type: "[]float64",
},
},
},
expected: map[string]interface{}{
"fs": []interface{}{float64(10.1), float64(20.2)},
},
},
{
args: []string{"--fs=10.1", "--fs=20.2"},
values: &goregistry.Value{
Values: []*goregistry.Value{
{
Name: "fs",
Type: "[]float64",
},
},
},
expected: map[string]interface{}{
"fs": []interface{}{float64(10.1), float64(20.2)},
},
},
{
args: []string{"--fs", "10.1", "--fs", "20.2"},
values: &goregistry.Value{
Values: []*goregistry.Value{
{
Name: "fs",
Type: "[]float64",
},
},
},
expected: map[string]interface{}{
"fs": []interface{}{float64(10.1), float64(20.2)},
},
},
{
args: []string{"--user_email=someemail"},
values: &goregistry.Value{
Values: []*goregistry.Value{
{
Name: "user_email",
Type: "string",
},
},
},
expected: map[string]interface{}{
"user_email": "someemail",
},
},
{
args: []string{"--user_email=someemail", "--user_name=somename"},
values: &goregistry.Value{
Values: []*goregistry.Value{
{
Name: "user_email",
Type: "string",
},
{
Name: "user_name",
Type: "string",
},
},
},
expected: map[string]interface{}{
"user_email": "someemail",
"user_name": "somename",
},
},
{
args: []string{"--b"},
values: &goregistry.Value{
Values: []*goregistry.Value{
{
Name: "b",
Type: "bool",
},
},
},
expected: map[string]interface{}{
"b": true,
},
},
{
args: []string{"--user_friend_email=hi"},
values: &goregistry.Value{
Values: []*goregistry.Value{
{
Name: "user_friend_email",
Type: "string",
},
},
},
expected: map[string]interface{}{
"user_friend_email": "hi",
},
},
}
for _, c := range cases {
t.Run(strings.Join(c.args, " "), func(t *testing.T) {
_, flags, err := splitCmdArgs(c.args)
if err != nil {
t.Fatal(err)
}
req, err := FlagsToRequest(flags, c.values)
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(c.expected, req) {
spew.Dump("Expected:", c.expected, "got: ", req)
t.Fatalf("Expected %v, got %v", c.expected, req)
}
})
}
}
func TestAddMetadataToContext(t *testing.T) {
tests := []struct {
name string
metadataStrs []string
expectedKeys []string
expectedValues []string
}{
{
name: "Single metadata",
metadataStrs: []string{"Key1:Value1"},
expectedKeys: []string{"Key1"},
expectedValues: []string{"Value1"},
},
{
name: "Multiple metadata",
metadataStrs: []string{"Key1:Value1", "Key2:Value2"},
expectedKeys: []string{"Key1", "Key2"},
expectedValues: []string{"Value1", "Value2"},
},
{
name: "Metadata with spaces",
metadataStrs: []string{"Key1: Value1 ", " Key2 : Value2"},
expectedKeys: []string{"Key1", "Key2"},
expectedValues: []string{"Value1", "Value2"},
},
{
name: "Metadata with colon in value",
metadataStrs: []string{"Authorization:Bearer token:123"},
expectedKeys: []string{"Authorization"},
expectedValues: []string{"Bearer token:123"},
},
{
name: "Empty metadata",
metadataStrs: []string{},
expectedKeys: []string{},
expectedValues: []string{},
},
{
name: "Invalid metadata format",
metadataStrs: []string{"InvalidFormat"},
expectedKeys: []string{},
expectedValues: []string{},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctx := context.Background()
ctx = AddMetadataToContext(ctx, tt.metadataStrs)
md, ok := metadata.FromContext(ctx)
if len(tt.expectedKeys) == 0 && !ok {
return // Expected no metadata
}
if !ok && len(tt.expectedKeys) > 0 {
t.Fatal("Expected metadata in context but got none")
}
for i, key := range tt.expectedKeys {
value, found := md.Get(key)
if !found {
t.Fatalf("Expected key %s not found in metadata", key)
}
if value != tt.expectedValues[i] {
t.Fatalf("Expected value %s for key %s, got %s", tt.expectedValues[i], key, value)
}
}
})
}
}