|
|
|
package internal
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/base64"
|
|
|
|
"errors"
|
|
|
|
"net/http"
|
|
|
|
"os"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/fullstorydev/grpcurl"
|
|
|
|
"github.com/jhump/protoreflect/desc"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/zeromicro/go-zero/core/hash"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
b64pb = `CpgBCgtoZWxsby5wcm90bxIFaGVsbG8iHQoHUmVxdWVzdBISCgRwaW5nGAEgASgJUgRwaW5nIh4KCFJlc3BvbnNlEhIKBHBvbmcYASABKAlSBHBvbmcyMAoFSGVsbG8SJwoEUGluZxIOLmhlbGxvLlJlcXVlc3QaDy5oZWxsby5SZXNwb25zZUIJWgcuL2hlbGxvYgZwcm90bzM=`
|
|
|
|
b64pbWithAnnotations = `Cs4EChVnb29nbGUvYXBpL2h0dHAucHJvdG8SCmdvb2dsZS5hcGkieQoESHR0cBIqCgVydWxlcxgBIAMoCzIULmdvb2dsZS5hcGkuSHR0cFJ1bGVSBXJ1bGVzEkUKH2Z1bGx5X2RlY29kZV9yZXNlcnZlZF9leHBhbnNpb24YAiABKAhSHGZ1bGx5RGVjb2RlUmVzZXJ2ZWRFeHBhbnNpb24i2gIKCEh0dHBSdWxlEhoKCHNlbGVjdG9yGAEgASgJUghzZWxlY3RvchISCgNnZXQYAiABKAlIAFIDZ2V0EhIKA3B1dBgDIAEoCUgAUgNwdXQSFAoEcG9zdBgEIAEoCUgAUgRwb3N0EhgKBmRlbGV0ZRgFIAEoCUgAUgZkZWxldGUSFgoFcGF0Y2gYBiABKAlIAFIFcGF0Y2gSNwoGY3VzdG9tGAggASgLMh0uZ29vZ2xlLmFwaS5DdXN0b21IdHRwUGF0dGVybkgAUgZjdXN0b20SEgoEYm9keRgHIAEoCVIEYm9keRIjCg1yZXNwb25zZV9ib2R5GAwgASgJUgxyZXNwb25zZUJvZHkSRQoTYWRkaXRpb25hbF9iaW5kaW5ncxgLIAMoCzIULmdvb2dsZS5hcGkuSHR0cFJ1bGVSEmFkZGl0aW9uYWxCaW5kaW5nc0IJCgdwYXR0ZXJuIjsKEUN1c3RvbUh0dHBQYXR0ZXJuEhIKBGtpbmQYASABKAlSBGtpbmQSEgoEcGF0aBgCIAEoCVIEcGF0aEIMWgpnb29nbGUvYXBpYgZwcm90bzMK8zsKIGdvb2dsZS9wcm90b2J1Zi9kZXNjcmlwdG9yLnByb3RvEg9nb29nbGUucHJvdG9idWYiTQoRRmlsZURlc2NyaXB0b3JTZXQSOAoEZmlsZRgBIAMoCzIkLmdvb2dsZS5wcm90b2J1Zi5GaWxlRGVzY3JpcHRvclByb3RvUgRmaWxlIuQEChNGaWxlRGVzY3JpcHRvclByb3RvEhIKBG5hbWUYASABKAlSBG5hbWUSGAoHcGFja2FnZRgCIAEoCVIHcGFja2FnZRIeCgpkZXBlbmRlbmN5GAMgAygJUgpkZXBlbmRlbmN5EisKEXB1YmxpY19kZXBlbmRlbmN5GAogAygFUhBwdWJsaWNEZXBlbmRlbmN5EicKD3dlYWtfZGVwZW5kZW5jeRgLIAMoBVIOd2Vha0RlcGVuZGVuY3kSQwoMbWVzc2FnZV90eXBlGAQgAygLMiAuZ29vZ2xlLnByb3RvYnVmLkRlc2NyaXB0b3JQcm90b1ILbWVzc2FnZVR5cGUSQQoJZW51bV90eXBlGAUgAygLMiQuZ29vZ2xlLnByb3RvYnVmLkVudW1EZXNjcmlwdG9yUHJvdG9SCGVudW1UeXBlEkEKB3NlcnZpY2UYBiADKAsyJy5nb29nbGUucHJvdG9idWYuU2VydmljZURlc2NyaXB0b3JQcm90b1IHc2VydmljZRJDCglleHRlbnNpb24YByADKAsyJS5nb29nbGUucHJvdG9idWYuRmllbGREZXNjcmlwdG9yUHJvdG9SCWV4dGVuc2lvbhI2CgdvcHRpb25zGAggASgLMhwuZ29vZ2xlLnByb3RvYnVmLkZpbGVPcHRpb25zUgdvcHRpb25zEkkKEHNvdXJjZV9jb2RlX2luZm8YCSABKAsyHy5nb29nbGUucHJvdG9idWYuU291cmNlQ29kZUluZm9SDnNvdXJjZUNvZGVJbmZvEhYKBnN5bnRheBgMIAEoCVIGc3ludGF4IrkGCg9EZXNjcmlwdG9yUHJvdG8SEgoEbmFtZRgBIAEoCVIEbmFtZRI7CgVmaWVsZBgCIAMoCzIlLmdvb2dsZS5wcm90b2J1Zi5GaWVsZERlc2NyaXB0b3JQcm90b1IFZmllbGQSQwoJZXh0ZW5zaW9uGAYgAygLMiUuZ29vZ2xlLnByb3RvYnVmLkZpZWxkRGVzY3JpcHRvclByb3RvUglleHRlbnNpb24SQQoLbmVzdGVkX3R5cGUYAyADKAsyIC5nb29nbGUucHJvdG9idWYuRGVzY3JpcHRvclByb3RvUgpuZXN0ZWRUeXBlEkEKCWVudW1fdHlwZRgEIAMoCzIkLmdvb2dsZS5wcm90b2J1Zi5FbnVtRGVzY3JpcHRvclByb3RvUghlbnVtVHlwZRJYCg9leHRlbnNpb25fcmFuZ2UYBSADKAsyLy5nb29nbGUucHJvdG9idWYuRGVzY3JpcHRvclByb3RvLkV4dGVuc2lvblJhbmdlUg5leHRlbnNpb25SYW5nZRJECgpvbmVvZl9kZWNsGAggAygLMiUuZ29vZ2xlLnByb3RvYnVmLk9uZW9mRGVzY3JpcHRvclByb3RvUglvbmVvZkRlY2wSOQoHb3B0aW9ucxgHIAEoCzIfLmdvb2dsZS5wcm90b2J1Zi5NZXNzYWdlT3B0aW9uc1IHb3B0aW9ucxJVCg5yZXNlcnZlZF9yYW5nZRgJIAMoCzIuLmdvb2dsZS5wcm90b2J1Zi5EZXNjcmlwdG9yUHJvdG8uUmVzZXJ2ZWRSYW5nZVINcmVzZXJ2ZWRSYW5nZRIjCg1yZXNlcnZlZF9uYW1lGAogAygJUgxyZXNlcnZlZE5hbWUaegoORXh0ZW5zaW9uUmFuZ2USFAoFc3RhcnQYASABKAVSBXN0YXJ0EhAKA2VuZBgCIAEoBVIDZW5kEkAKB29wdGlvbnMYAyABKAsyJi5nb29nbGUucHJvdG9idWYuRXh0ZW5zaW9uUmFuZ2VPcHRpb25zUgdvcHRpb25zGjcKDVJlc2VydmVkUmFuZ2USFAoFc3RhcnQYASABKAVSBXN0YXJ0EhAKA2VuZBgCIAEoBVIDZW5kInwKFUV4dGVuc2lvblJhbmdlT3B0aW9ucxJYChR1bmludGVycHJldGVkX29wdGlvbhjnByADKAsyJC5nb29nbGUucHJvdG9idWYuVW5pbnRlcnByZXRlZE9wdGlvblITdW5pbnRlcnByZXRlZE9wdGlvbioJCOgHEICAgIACIsEGChRGaWVsZERlc2NyaXB0b3JQcm90bxISCgRuYW1lGAEgASgJUgRuYW1lEhYKBm51bWJlchgDIAEoBVIGbnVtYmVyEkEKBWxhYmVsGAQgASgOMisuZ29vZ2xlLnByb3RvYnVmLkZpZWxkRGVzY3JpcHRvclByb3RvLkxhYmVsUgVsYWJlbBI+CgR0eXBlGAUgASgOMiouZ29vZ2xlLnByb3RvYnVmLkZpZWxkRGVzY3JpcHRvclByb3RvLlR5cGVSBHR5cGUSGwoJdHlwZV9uYW1lGAYgASgJUgh0eXBlTmFtZRIaCghleHRlbmRlZRgCIAEoCVIIZXh0ZW5kZWUSIwoNZGVmYXVsdF92YWx1ZRgHIAEoCVIMZGVmYXVsdFZhbHVlEh8KC29uZW9mX2luZGV4GAkgASgFUgpvbmVvZkluZGV4EhsKCWpzb25fbmFtZRgKIAEoCVIIanNvbk5hbWUSNwoHb3B0aW9ucxgIIAEoCzIdLmdvb2dsZS5wcm90b2J1Zi5GaWVsZE9wdGlvbnNSB29wdGlvbnMSJwoPcHJvdG8zX29wdGlvbmFsGBEgASgIUg5wcm90bzNPcHRpb25hbCK2AgoEVHlwZRIPCgtUWVBFX0RPVUJMRRABEg4KClRZUEVfRkxPQVQQAhIOCgpUWVBFX0lOVDY0EAMSDwoLVFlQRV9VSU5UNjQQBBIOCgpUWVBFX0lOVDMyEAUSEAoMVFlQRV9GSVhFRDY0EAYSEAoMVFlQRV9GSVhFRDMyEAcSDQoJVFlQRV9CT09MEAgSDwoLVFlQRV9TVFJJTkcQCRIOCgpUWVBFX0dST1VQEAoSEAoMVFlQRV9NRVNTQUdFEAsSDgoKVFlQRV9CWVRFUxAMEg8KC1RZUEVfVUlOVDMyEA0SDQoJVFlQRV9FTlVNEA4SEQoNVFlQRV9TRklYRUQzMhAPEhEKDVRZUEVfU0ZJWEVENjQQEBIPCgtUWVBFX1NJTlQzMhAREg8KC1RZUE
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestGetMethods(t *testing.T) {
|
|
|
|
tmpfile, err := os.CreateTemp(os.TempDir(), hash.Md5Hex([]byte(b64pb)))
|
|
|
|
assert.Nil(t, err)
|
|
|
|
b, err := base64.StdEncoding.DecodeString(b64pb)
|
|
|
|
assert.Nil(t, err)
|
|
|
|
assert.Nil(t, os.WriteFile(tmpfile.Name(), b, os.ModeTemporary))
|
|
|
|
defer os.Remove(tmpfile.Name())
|
|
|
|
|
|
|
|
source, err := grpcurl.DescriptorSourceFromProtoSets(tmpfile.Name())
|
|
|
|
assert.Nil(t, err)
|
|
|
|
methods, err := GetMethods(source)
|
|
|
|
assert.Nil(t, err)
|
|
|
|
assert.EqualValues(t, []Method{
|
|
|
|
{
|
|
|
|
RpcPath: "hello.Hello/Ping",
|
|
|
|
},
|
|
|
|
}, methods)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestGetMethodsWithAnnotations(t *testing.T) {
|
|
|
|
tmpfile, err := os.CreateTemp(os.TempDir(), hash.Md5Hex([]byte(b64pb)))
|
|
|
|
assert.Nil(t, err)
|
|
|
|
b, err := base64.StdEncoding.DecodeString(b64pbWithAnnotations)
|
|
|
|
assert.Nil(t, err)
|
|
|
|
assert.Nil(t, os.WriteFile(tmpfile.Name(), b, os.ModeTemporary))
|
|
|
|
defer os.Remove(tmpfile.Name())
|
|
|
|
|
|
|
|
source, err := grpcurl.DescriptorSourceFromProtoSets(tmpfile.Name())
|
|
|
|
assert.Nil(t, err)
|
|
|
|
methods, err := GetMethods(source)
|
|
|
|
assert.Nil(t, err)
|
|
|
|
assert.EqualValues(t, []Method{
|
|
|
|
{
|
|
|
|
HttpMethod: http.MethodGet,
|
|
|
|
HttpPath: "/v1/get/:foo",
|
|
|
|
RpcPath: "hello.Hello/PingGet",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
HttpMethod: http.MethodPost,
|
|
|
|
HttpPath: "/v1/post",
|
|
|
|
RpcPath: "hello.Hello/PingPost",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
HttpMethod: http.MethodPut,
|
|
|
|
HttpPath: "/v1/put",
|
|
|
|
RpcPath: "hello.Hello/PingPut",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
HttpMethod: http.MethodDelete,
|
|
|
|
HttpPath: "/v1/delete",
|
|
|
|
RpcPath: "hello.Hello/PingDelete",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
HttpMethod: http.MethodPatch,
|
|
|
|
HttpPath: "/v1/patch",
|
|
|
|
RpcPath: "hello.Hello/PingPatch",
|
|
|
|
},
|
|
|
|
}, methods)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestGetMethodsBadCases(t *testing.T) {
|
|
|
|
t.Run("no services", func(t *testing.T) {
|
|
|
|
source := &mockDescriptorSource{
|
|
|
|
servicesErr: errors.New("no services"),
|
|
|
|
}
|
|
|
|
_, err := GetMethods(source)
|
|
|
|
assert.NotNil(t, err)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("no symbol in services", func(t *testing.T) {
|
|
|
|
source := &mockDescriptorSource{
|
|
|
|
services: []string{"hello.Hello"},
|
|
|
|
symbolErr: errors.New("no symbol"),
|
|
|
|
}
|
|
|
|
_, err := GetMethods(source)
|
|
|
|
assert.NotNil(t, err)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("no symbol in services", func(t *testing.T) {
|
|
|
|
source := &mockDescriptorSource{
|
|
|
|
services: []string{"hello.Hello"},
|
|
|
|
symbolErr: errors.New("no symbol"),
|
|
|
|
}
|
|
|
|
_, err := GetMethods(source)
|
|
|
|
assert.NotNil(t, err)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
type mockDescriptorSource struct {
|
|
|
|
symbolDesc desc.Descriptor
|
|
|
|
symbolErr error
|
|
|
|
services []string
|
|
|
|
servicesErr error
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *mockDescriptorSource) AllExtensionsForType(_ string) ([]*desc.FieldDescriptor, error) {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *mockDescriptorSource) FindSymbol(_ string) (desc.Descriptor, error) {
|
|
|
|
return m.symbolDesc, m.symbolErr
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *mockDescriptorSource) ListServices() ([]string, error) {
|
|
|
|
return m.services, m.servicesErr
|
|
|
|
}
|