go-micro icon indicating copy to clipboard operation
go-micro copied to clipboard

[BUG] metadata returns old results when key is not title case

Open xhd2015 opened this issue 1 year ago • 2 comments

Describe the bug

In our unit test we have a test that checks update of a metadata context yields expected result when Get. But it fails randomly.

After investigation, we think the bug is related to metadata package, and possibly due to go's random map traversing behavior.

But I am not sure if this is considered a bug or not, so raise an issue here to discuss.

How to reproduce the bug

  • Description: The following test sets metadata with the same key twice,
    • first "A", then "a",
    • and then get the key from the metadata back,
    • The result is always expected to be "a", but it sometimes returns "A".
  • Observation: this test usually fails within 10 loops
package demo

import (
	"context"
	"testing"

	"go-micro.dev/v5/metadata"
)

// go.mod: require go-micro.dev/v5 v5.3.0

const LOWER_TEST_KEY = "lower-test-key"

func TestMetadataBug(t *testing.T) {
	n := 0
	for {
		ctx := context.TODO()
		ctx1 := metadata.Set(ctx, LOWER_TEST_KEY, "A")

		ctx2 := metadata.Set(ctx1, LOWER_TEST_KEY, "a")

		v, _ := metadata.Get(ctx2, LOWER_TEST_KEY)
		if v != "a" {
			t.Fatalf("fail: %d, found unexpected result: %v", n, v)
		}
		t.Logf("pass: %d", n)
		n++
	}
}

Output:

=== RUN   TestMetadataBug
    v2_test.go:24: pass: 0
    v2_test.go:24: pass: 1
    v2_test.go:24: pass: 2
    v2_test.go:24: pass: 3
    v2_test.go:24: pass: 4
    v2_test.go:24: pass: 5
    v2_test.go:24: pass: 6
    v2_test.go:24: pass: 7
    v2_test.go:24: pass: 8
    v2_test.go:24: pass: 9
    v2_test.go:24: pass: 10
    v2_test.go:24: pass: 11
    v2_test.go:22: fail: 12, found unexpected result: A
--- FAIL: TestMetadataBug (0.00s)

Here is the runnable snippet: https://go.dev/play/p/h_55BgcL6wY (need to place require go-micro.dev/v5 v5.3.0 in your go.mod first)

Environment

Go Version: go version go1.19.6 darwin/amd64

xhd2015 avatar Nov 03 '24 07:11 xhd2015

Possible reason:

The Set function does not convert lower case to title case, so at a point the metadata map may hold both the lower case and the title case key:

https://github.com/micro/go-micro/blob/14a17910115a5a1c3723dc8f213524e726afc2f1/metadata/metadata.go#L61-L63

And in FromContext, there is a map copying via traversing, which is randomized, the actual value depends on which key comes at last: https://github.com/micro/go-micro/blob/14a17910115a5a1c3723dc8f213524e726afc2f1/metadata/metadata.go#L94-L96

xhd2015 avatar Nov 03 '24 07:11 xhd2015

Sequence: image

xhd2015 avatar Nov 03 '24 09:11 xhd2015

I think you're right. We shouldn't alter the key on retrieval. IN the case anyone needs it there's a Get method on Metadata that checks lower or uppercase keys.

asim avatar Oct 22 '25 06:10 asim

Thanks a lot.

xhd2015 avatar Oct 23 '25 01:10 xhd2015