1
0
mirror of https://gitee.com/willfree/mlsr.git synced 2026-06-06 20:29:28 +08:00

add: SyncLogicHandler 以及 SyncProtocolAdapter单元测试

This commit is contained in:
wzhq
2022-08-11 21:44:45 +08:00
parent eecb522c2e
commit 2550fcf695
6 changed files with 498 additions and 15 deletions
+15 -13
View File
@@ -50,7 +50,7 @@ type SyncLogicHandler struct {
// confParam MLSR配置参数
confParam *common.MlsrConfigParameters
// nlsrComponent NLSR字符串
nlsrComponent string
mlsrComponent string
// lsaComponent LSA字符串
lsaComponent string
/////////////// 公有属性 /////////////
@@ -80,17 +80,17 @@ func (s *SyncLogicHandler) ProcessUpdate(updateName *component.Identifier, highS
common2.LogInfo("Update Name: ", updateName.ToUri(), " Seq no: ", highSeq)
// nlsrPosition 从同步数据的标识中获取子字符串'nlsr'的位置
nlsrPosition := utils.GetNameComponentPosition(updateName, s.nlsrComponent)
mlsrPosition := utils.GetNameComponentPosition(updateName, s.mlsrComponent)
// lsaPosition 从同步数据的标识中获取子字符串'lsa'的位置
lsaPosition := utils.GetNameComponentPosition(updateName, s.lsaComponent)
if nlsrPosition < 0 || lsaPosition < 0 {
if mlsrPosition < 0 || lsaPosition < 0 {
common2.LogWarn("收到了不合法的同步更新数据")
return
}
// networkName 用于表示源MLSR节点网络标识
networkName, err := updateName.GetSubIdentifier(1, nlsrPosition-1)
networkName, err := updateName.GetSubIdentifier(1, mlsrPosition-1)
if err != nil {
common2.LogError("解析源MLSR节点网络标识出错", err.Error())
return
@@ -128,6 +128,7 @@ func (s *SyncLogicHandler) ProcessUpdate(updateName *component.Identifier, highS
originRouterName.Append(comp)
}
s.ProcessUpdateFromSync(originRouterName, updateName, highSeq, incomingFaceId)
}
// ProcessUpdateFromSync 处理更新的回调函数
@@ -213,36 +214,37 @@ func NewSyncLogicHandler(face *logicface.DummyClientLogicFace, isLsaNew IsLsaNew
syncLogicHandler.confParam = conf
// 标识组件构造
syncLogicHandler.nlsrComponent = "nlsr"
syncLogicHandler.lsaComponent = "lsa"
syncLogicHandler.mlsrComponent = "mlsr"
syncLogicHandler.lsaComponent = "LSA"
// NLSR的源码中使用了字符串类型的标识组件, 而不是非负数类型
nameComponent := component.CreateIdentifierComponentByString(strconv.Itoa(int(lsa.LsaNAMEType)))
adjComponent := component.CreateIdentifierComponentByString(strconv.Itoa(int(lsa.LsaADJACENCYType)))
coorComponent := component.CreateIdentifierComponentByString(strconv.Itoa(int(lsa.LsaCOORDINATEType)))
// 复制标识SyncUserPrefix
syncPrefix := conf.GetSyncPrefix()
if syncPrefix == nil {
// Bug: 复制标识SyncPrefix
// Fix: 复制标识SyncUserPrefix
syncUserPrefix := conf.GetSyncUserPrefix()
if syncUserPrefix == nil {
return nil, errors.New("无效同步标识")
}
syncPrefixBlock, err := syncPrefix.SelfWireEncode(syncPrefix)
syncUserPrefixBlock, err := syncUserPrefix.SelfWireEncode(syncUserPrefix)
if err != nil {
return nil, err
}
// NameLsaUserPrefix 构建
syncLogicHandler.NameLsaUserPrefix, err = component.NewIdentifierByBlock(syncPrefixBlock)
syncLogicHandler.NameLsaUserPrefix, err = component.NewIdentifierByBlock(syncUserPrefixBlock)
if err != nil {
return nil, err
}
syncLogicHandler.NameLsaUserPrefix.Append(nameComponent)
// AdjLsaUserPrefix 构建
syncLogicHandler.AdjLsaUserPrefix, err = component.NewIdentifierByBlock(syncPrefixBlock)
syncLogicHandler.AdjLsaUserPrefix, err = component.NewIdentifierByBlock(syncUserPrefixBlock)
if err != nil {
return nil, err
}
syncLogicHandler.AdjLsaUserPrefix.Append(adjComponent)
// CoorLsaUserPrefix 构建
syncLogicHandler.CoorLsaUserPrefix, err = component.NewIdentifierByBlock(syncPrefixBlock)
syncLogicHandler.CoorLsaUserPrefix, err = component.NewIdentifierByBlock(syncUserPrefixBlock)
if err != nil {
return nil, err
}
+337
View File
@@ -0,0 +1,337 @@
// Package communication
// @Author: zhengqi Wu
// @Description:
// @Version: 0.1.0
// @Date: 2022/8/10 16:07
// @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
//
package communication
import (
"MINSync"
"fmt"
"github.com/stretchr/testify/assert"
common2 "minlib/common"
"minlib/component"
"minlib/logicface"
"minlib/utils"
"mlsr/common"
"mlsr/lsa"
"strconv"
"testing"
"time"
)
// SyncLogicFixture SyncLogic测试中固定不变的部分
type SyncLogicFixture struct {
// 变量
face *logicface.DummyClientLogicFace
conf *common.MlsrConfigParameters
testIsLsaNew IsLsaNew
// 同步逻辑实例
sync *SyncLogicHandler
// 常量
updateNamePrefix string
lsaTypes [3]lsa.LsaType
}
// receiveUpdate 模拟接收到更新后的处理流程
//
func (this *SyncLogicFixture) receiveUpdate(prefix string, seqNo uint64) {
time.Sleep(10 * time.Millisecond)
this.face.SentInterests.Clear()
// 模拟更新数据
updates := make([]*MINSync.MissingDataInfo, 0)
prefixInIdentifier, _ := component.NewIdentifierByString(prefix)
updates = append(updates, MINSync.NewMissingDataInfo(prefixInIdentifier, 0, seqNo, 0))
// 通知SyncLogic处理更新数据
this.sync.SyncLogic.OnMINSyncUpdate(updates)
}
// NewSyncLogicFixture SyncLogicFixture的工厂方法
func NewSyncLogicFixture() *SyncLogicFixture {
syncLogicFixture := new(SyncLogicFixture)
syncLogicFixture.face = logicface.NewDummyClientLogicFaceByOptions("face0", "", logicface.NewDummyClientOptionsByParams(true, true))
syncLogicFixture.testIsLsaNew = func(identifier *component.Identifier, lsaType lsa.LsaType, seq uint64, incomingLogicFaceId uint64) bool {
return true
}
// 初始化MLSR配置
// TODO: 这里写死是为了测试,真实使用不能这么写
mlsrConfig, _ := common.ParseConfig("E:/mir-dir/mlsr/mlsrConf.ini")
syncLogicFixture.conf = new(common.MlsrConfigParameters)
syncLogicFixture.conf.Init(mlsrConfig)
syncLogicFixture.sync, _ = NewSyncLogicHandler(syncLogicFixture.face, syncLogicFixture.testIsLsaNew, syncLogicFixture.conf)
syncLogicFixture.updateNamePrefix =
syncLogicFixture.conf.GetLsaPrefix().ToUri() +
syncLogicFixture.conf.GetSiteName().ToUri() +
"/C1.Router/other-router/"
// 初始化lsaTypes,按顺序填充
syncLogicFixture.lsaTypes = *(new([3]lsa.LsaType))
syncLogicFixture.lsaTypes[0] = lsa.LsaNAMEType
syncLogicFixture.lsaTypes[1] = lsa.LsaADJACENCYType
syncLogicFixture.lsaTypes[2] = lsa.LsaCOORDINATEType
return syncLogicFixture
}
// TestUpdateForOtherLS
//
// 该测试用例主要用于测试当SyncLogicHandler收到更新的NameLSA或ADJLSA时,
// 是否会将该LSA及其细节通过信号通知MLSR
//
func TestUpdateForOtherLS(t *testing.T) {
fixture := NewSyncLogicFixture()
// nCallBacks 用于统计回调函数的调用次数
nCallBacks := 0
// syncSeqNo 手工指定的同步数据的序列号
var syncSeqNo uint64 = 1
lsaTypes := []lsa.LsaType{lsa.LsaNAMEType, lsa.LsaADJACENCYType}
var conn *utils.Connection
for _, lsaType := range lsaTypes {
// Fix: 模拟ScopedConnection 手动释放信号
if conn != nil {
conn.Disconnect()
}
updateName := fmt.Sprintf("%s%d", fixture.updateNamePrefix, lsaType)
// Bug: 在NLSR中使用的是ScopedConnection,意味着每当一次循环结束后,该连接就自动解除
conn = fixture.sync.OnNewLsa.Connect(func(i ...interface{}) {
routerName := i[0].(*component.Identifier)
sequenceNumber := i[1].(uint64)
// originRouter := i[2].(*component.Identifier)
// incomingFaceId := i[3].(uint64)
// 检查更新的同步数据前缀是否相等
assert.Equal(t, updateName, routerName.ToUri())
// 检查更新的同步数据序列号是否相等
assert.Equal(t, sequenceNumber, syncSeqNo)
nCallBacks += 1
})
fixture.receiveUpdate(updateName, syncSeqNo)
}
assert.Equal(t, nCallBacks, 2)
}
// TestUpdateForOtherHR
//
// 该测试用例主要用于测试当SyncLogicHandler收到更新的NameLSA或CoordinateLSA时,
// 是否会将该LSA及其细节通过信号通知MLSR
//
func TestUpdateForOtherHR(t *testing.T) {
fixture := NewSyncLogicFixture()
// nCallBacks 用于统计回调函数的调用次数
nCallBacks := 0
// syncSeqNo 手工指定的同步数据的序列号
var syncSeqNo uint64 = 1
lsaTypes := []lsa.LsaType{lsa.LsaNAMEType, lsa.LsaCOORDINATEType}
var conn *utils.Connection
for _, lsaType := range lsaTypes {
// Fix: 模拟ScopedConnection 手动释放信号
if conn != nil {
conn.Disconnect()
}
updateName := fmt.Sprintf("%s%d", fixture.updateNamePrefix, lsaType)
// Bug: 在NLSR中使用的是ScopedConnection,意味着每当一次循环结束后,该连接就自动解除
conn = fixture.sync.OnNewLsa.Connect(func(i ...interface{}) {
routerName := i[0].(*component.Identifier)
sequenceNumber := i[1].(uint64)
// originRouter := i[2].(*component.Identifier)
// incomingFaceId := i[3].(uint64)
// 检查更新的同步数据前缀是否相等
assert.Equal(t, updateName, routerName.ToUri())
// 检查更新的同步数据序列号是否相等
assert.Equal(t, sequenceNumber, syncSeqNo)
nCallBacks += 1
})
fixture.receiveUpdate(updateName, syncSeqNo)
}
assert.Equal(t, nCallBacks, 2)
}
// TestUpdateForOtherHRDry
//
// 该测试用例主要用于测试当SyncLogicHandler收到更新的任意类型的LSA时,
// 是否会将该LSA及其细节通过信号通知MLSR
//
func TestUpdateForOtherHRDry(t *testing.T) {
fixture := NewSyncLogicFixture()
// nCallBacks 用于统计回调函数的调用次数
nCallBacks := 0
// syncSeqNo 手工指定的同步数据的序列号
var syncSeqNo uint64 = 1
var conn *utils.Connection
for _, lsaType := range fixture.lsaTypes {
// Fix: 模拟ScopedConnection 手动释放信号
if conn != nil {
conn.Disconnect()
}
updateName := fmt.Sprintf("%s%d", fixture.updateNamePrefix, lsaType)
// Bug: 在NLSR中使用的是ScopedConnection,意味着每当一次循环结束后,该连接就自动解除
conn = fixture.sync.OnNewLsa.Connect(func(i ...interface{}) {
routerName := i[0].(*component.Identifier)
sequenceNumber := i[1].(uint64)
// originRouter := i[2].(*component.Identifier)
// incomingFaceId := i[3].(uint64)
// 检查更新的同步数据前缀是否相等
assert.Equal(t, updateName, routerName.ToUri())
// 检查更新的同步数据序列号是否相等
assert.Equal(t, sequenceNumber, syncSeqNo)
nCallBacks += 1
})
fixture.receiveUpdate(updateName, syncSeqNo)
}
assert.Equal(t, nCallBacks, 3)
}
// TestNoUpdateForSelf
//
// 该测试用例主要用于测试当SyncLogicHandler收到自身发布的任意更新数据时,
// 是否不会触发信号调用回调函数
//
func TestNoUpdateForSelf(t *testing.T) {
fixture := NewSyncLogicFixture()
var sequenceNumber uint64 = 1
var conn *utils.Connection
for _, lsaType := range fixture.lsaTypes {
// Fix: 模拟ScopedConnection 手动释放信号
if conn != nil {
conn.Disconnect()
}
// 为拷贝标识准备TLV Block
lsaPrefixBlockForCopy, _ := fixture.conf.GetLsaPrefix().SelfWireEncode(fixture.conf.GetLsaPrefix())
siteNameBlockForCopy, _ := fixture.conf.GetSiteName().SelfWireEncode(fixture.conf.GetSiteName())
routerNameBlockForCopy, _ := fixture.conf.GetRouterName().SelfWireEncode(fixture.conf.GetRouterName())
updateName, _ := component.NewIdentifierByBlock(lsaPrefixBlockForCopy)
// 拷贝siteName标识,并将副本的标识组件加入到updateName中
siteNameCopy, _ := component.NewIdentifierByBlock(siteNameBlockForCopy)
for _, comp := range siteNameCopy.GetComponents() {
updateName.Append(comp)
}
// 拷贝routeName标识,并将副本的标识组件加入到updateName中
routerNameCopy, _ := component.NewIdentifierByBlock(routerNameBlockForCopy)
for _, comp := range routerNameCopy.GetComponents() {
updateName.Append(comp)
}
// 添加LSAType字符串标识组件
updateName.AppendString(strconv.Itoa(int(lsaType)))
conn = fixture.sync.OnNewLsa.Connect(func(i ...interface{}) {
// 自身发布的更新不应该触发信号,因此这里Fatal掉
common2.LogFatal("Updates for self should not be emitted!")
})
fixture.receiveUpdate(updateName.ToUri(), sequenceNumber)
}
// 正常运行结束即算单元测试通过
}
// TestMalformedUpdate
//
// 该测试用例主要用于测试当SyncHandler收到不符合格式的异常更新数据时,
// 是否不会去触发信号通知MLSR
//
func TestMalformedUpdate(t *testing.T) {
fixture := NewSyncLogicFixture()
var sequenceNumber uint64 = 1
var conn *utils.Connection
for _, lsaType := range fixture.lsaTypes {
// Fix: 模拟ScopedConnection 手动释放信号
if conn != nil {
conn.Disconnect()
}
// 为拷贝标识准备TLV Block
siteNameBlockForCopy, _ := fixture.conf.GetSiteName().SelfWireEncode(fixture.conf.GetSiteName())
routerNameBlockForCopy, _ := fixture.conf.GetRouterName().SelfWireEncode(fixture.conf.GetRouterName())
updateName, _ := component.NewIdentifierByBlock(siteNameBlockForCopy)
// 拷贝routeName标识,并将副本的标识组件加入到updateName中
routerNameCopy, _ := component.NewIdentifierByBlock(routerNameBlockForCopy)
for _, comp := range routerNameCopy.GetComponents() {
updateName.Append(comp)
}
// 添加LSAType字符串标识组件
updateName.AppendString(strconv.Itoa(int(lsaType)))
conn = fixture.sync.OnNewLsa.Connect(func(i ...interface{}) {
// 自身发布的更新不应该触发信号,因此这里Fatal掉
common2.LogFatal("Updates for self should not be emitted!")
})
fixture.receiveUpdate(updateName.ToUri(), sequenceNumber)
}
// 正常运行结束即算单元测试通过
}
// TestLsaNotNew
//
// 该测试用例主要用于测试当SyncHandler收到老版本的同步数据时,
// 是否不会去触发信号通知MLSR
//
func TestLsaNotNew(t *testing.T) {
fixture := NewSyncLogicFixture()
// IsNewLSA 总返回false
testLsaAlwaysFalse := func(routerName *component.Identifier,
lsaType lsa.LsaType,
sequenceNumber uint64,
incomingFaceId uint64) bool {
return false
}
var sequenceNumber uint64 = 1
// 新建一个使用testLsaAlwaysFalse作为IsNewLSA的SyncLogicHandler
sync, _ := NewSyncLogicHandler(fixture.face, testLsaAlwaysFalse, fixture.conf)
sync.OnNewLsa.Connect(func(i ...interface{}) {
// 由于没有收到新的LSA,因此该信号不会被触发
common2.LogFatal("An update for an LSA with non-new sequence number should not emit!")
})
updateName := fixture.updateNamePrefix + strconv.Itoa(int(lsa.LsaNAMEType))
fixture.receiveUpdate(updateName, sequenceNumber)
// 正常运行结束即算单元测试通过
}
// TestUpdatePrefix
//
// 本测试用例主要用于测试SyncLogicHandler是否将LsaPrefix SiteName RouterName成功组合在一起
//
func TestUpdatePrefix(t *testing.T) {
fixture := NewSyncLogicFixture()
expectedPrefix := fixture.conf.GetLsaPrefix()
for _, comp := range fixture.conf.GetSiteName().GetComponents() {
expectedPrefix.Append(comp)
}
for _, comp := range fixture.conf.GetRouterName().GetComponents() {
expectedPrefix.Append(comp)
}
assert.Equal(t, fixture.sync.NameLsaUserPrefix.ToUri(), expectedPrefix.ToUri()+"/"+strconv.Itoa(int(lsa.LsaNAMEType)))
assert.Equal(t, fixture.sync.AdjLsaUserPrefix.ToUri(), expectedPrefix.ToUri()+"/"+strconv.Itoa(int(lsa.LsaADJACENCYType)))
assert.Equal(t, fixture.sync.CoorLsaUserPrefix.ToUri(), expectedPrefix.ToUri()+"/"+strconv.Itoa(int(lsa.LsaCOORDINATEType)))
}
+138
View File
@@ -0,0 +1,138 @@
// Package communication
// @Author: zhengqi Wu
// @Description:
// @Version: 0.1.0
// @Date: 2022/8/10 16:07
// @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
//
package communication
import (
"fmt"
"github.com/stretchr/testify/assert"
"minlib/common"
"minlib/component"
"minlib/logicface"
"testing"
"time"
)
// SyncProtocolAdapterFixture SyncProtocolAdapter单元测试中不变的部分
type SyncProtocolAdapterFixture struct {
// syncPrefix 同步公共前缀
syncPrefix *component.Identifier
// nameLsaUserPrefix
nameLsaUserPrefix *component.Identifier
// userPrefixes
userPrefixes [2]*component.Identifier
// syncInterestLifetime 同步兴趣包的生命周期
syncInterestLifetime time.Duration
faces [2]*logicface.DummyClientLogicFace
nodes [2]*SyncProtocolAdapter
// prefixToSeq 前缀与序列号的映射表
// NLSR中使用Identifier的地址作为map的key
// 然而在本测试中无法保证两个内容一致的标识它们的指针地址也相同,所以使用标识的字符串作为map的key
prefixToSeq [2]map[string]uint64
}
// addNodes 准备路由同步节点
//
func (f *SyncProtocolAdapterFixture) addNodes() {
nameLsaUserPrefixBlockForCopy, _ := f.nameLsaUserPrefix.SelfWireEncode(f.nameLsaUserPrefix)
for i := 0; i < 2; i++ {
// fix: 为循环的每一次闭包创建一个局部变量用来逃逸
index := i
f.faces[i] = logicface.NewDummyClientLogicFaceByOptions(fmt.Sprintf("face%d", i), "", logicface.NewDummyClientOptionsByParams(true, true))
f.userPrefixes[i], _ = component.NewIdentifierByBlock(nameLsaUserPrefixBlockForCopy)
f.userPrefixes[i].Append(component.CreateIdentifierComponentByNonNegativeInteger(uint64(i)))
f.nodes[i], _ = NewSyncProtocolAdapter(f.faces[i], f.syncPrefix,
f.userPrefixes[i],
f.syncInterestLifetime,
func(updateName *component.Identifier, seqNo uint64, incomingFaceId uint64) {
// bug: 闭包 变量i逃逸 导致数组访问越界
// f.prefixToSeq[i][updateName.ToUri()] = seqNo
// common.LogInfo("逃逸的变量i赋值给本地局部变量index: ", index)
f.prefixToSeq[index][updateName.ToUri()] = seqNo
})
}
f.faces[0].LinkTo(f.faces[1])
time.Sleep(100 * time.Millisecond)
}
// NewSyncProtocolAdapterFixture SyncProtocolAdapterFixture的工厂方法
//
func NewSyncProtocolAdapterFixture() *SyncProtocolAdapterFixture {
// 基本数据类型
fixture := new(SyncProtocolAdapterFixture)
fixture.syncPrefix, _ = component.NewIdentifierByString("/localhop/min/mlsr/sync")
fixture.nameLsaUserPrefix, _ = component.NewIdentifierByString("/localhop/min/mlsr/LSA/NAME")
// fixture.syncInterestLifetime = 60 * time.Second
// 由于MINSync实现的原因,为了实现正确的数据同步,将请求兴趣包的生命周期设为0.5s
fixture.syncInterestLifetime = 500 * time.Millisecond
fixture.syncPrefix.AppendVersionNumber(4)
// 引用数据类型
fixture.userPrefixes = *new([2]*component.Identifier)
fixture.nodes = *new([2]*SyncProtocolAdapter)
fixture.faces = *new([2]*logicface.DummyClientLogicFace)
fixture.prefixToSeq = *new([2]map[string]uint64)
fixture.prefixToSeq[0] = make(map[string]uint64)
fixture.prefixToSeq[1] = make(map[string]uint64)
return fixture
}
// TestBasicSyncProtocolAdapter SyncProtocolAdapter 基本用法 测试用例
func TestBasicSyncProtocolAdapter(t *testing.T) {
// 设置日志输出参数
common.InitLogger(&common.LoggerParameters{
// ReportCaller 输出日志所处文件位置
ReportCaller: true,
LogLevel: "",
LogFormat: "",
LogFilePath: "",
})
// 准备路由同步节点
fixture := NewSyncProtocolAdapterFixture()
fixture.addNodes()
// 节点 0 发布更新
fixture.nodes[0].PublishUpdate(fixture.userPrefixes[0], 10)
time.Sleep(1000 * time.Millisecond)
// 检查节点 1 的 prefixToSeq
seq, exist := fixture.prefixToSeq[1][fixture.userPrefixes[0].ToUri()]
assert.Equal(t, exist, true)
assert.Equal(t, seq, uint64(10))
// 节点 1 发布更新
fixture.nodes[1].PublishUpdate(fixture.userPrefixes[1], 100)
time.Sleep(1000 * time.Millisecond)
// 检查节点 0 的 prefixToSeq
seq, exist = fixture.prefixToSeq[0][fixture.userPrefixes[1].ToUri()]
assert.Equal(t, exist, true)
assert.Equal(t, seq, uint64(100))
// 为 节点0 新增数据前缀
adjLsaUserPrefix, _ := component.NewIdentifierByString("/localhop/min/mlsr/LSA/ADJACENCY")
fixture.nodes[0].AddUserNode(adjLsaUserPrefix)
time.Sleep(10 * time.Millisecond)
// 为新增的数据前缀发布更新
fixture.nodes[0].PublishUpdate(adjLsaUserPrefix, 10)
// 等待1到2个时间窗口,节点数据完成同步
time.Sleep(1000 * time.Millisecond)
// 检查节点1的prefixToSeq
seq, exist = fixture.prefixToSeq[1][adjLsaUserPrefix.ToUri()]
assert.Equal(t, exist, true)
assert.Equal(t, seq, uint64(10))
}
func TestBasicSyncProtocolAdapter_100times(t *testing.T) {
for i := 0; i < 100; i++ {
TestBasicSyncProtocolAdapter(t)
}
}
+3 -1
View File
@@ -3,6 +3,7 @@ module mlsr
go 1.17
require (
MINSync v0.0.0
//github.com/rakanalh/scheduler v0.1
github.com/go-co-op/gocron v1.13.0
github.com/liyue201/gostl v1.0.1
@@ -10,7 +11,6 @@ require (
github.com/tidwall/buntdb v1.2.9
gopkg.in/ini.v1 v1.62.0
minlib v0.0.0
MINSync v0.0.0
)
require (
@@ -39,6 +39,7 @@ require (
github.com/tidwall/rtred v0.1.2 // indirect
github.com/tidwall/tinyqueue v0.1.1 // indirect
github.com/tylertreat/BoomFilters v0.0.0-20210315201527-1a82519a3e43 // indirect
github.com/vishalkuo/bimap v0.0.0-20180703190407-09cff2814645 // indirect
github.com/zeebo/xxh3 v1.0.1 // indirect
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
@@ -51,4 +52,5 @@ require (
)
replace minlib v0.0.0 => ../minlib
replace MINSync v0.0.0 => ../MINSync
+2
View File
@@ -88,6 +88,8 @@ github.com/tidwall/tinyqueue v0.1.1/go.mod h1:O/QNHwrnjqr6IHItYrzoHAKYhBkLI67Q09
github.com/tylertreat/BoomFilters v0.0.0-20210315201527-1a82519a3e43 h1:QEePdg0ty2r0t1+qwfZmQ4OOl/MB2UXIeJSpIZv56lg=
github.com/tylertreat/BoomFilters v0.0.0-20210315201527-1a82519a3e43/go.mod h1:OYRfF6eb5wY9VRFkXJH8FFBi3plw2v+giaIu7P054pM=
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
github.com/vishalkuo/bimap v0.0.0-20180703190407-09cff2814645 h1:GUsWoxLgZ75MvazbQ0AWSvtjyvhmFryQD7BwWN6+5+0=
github.com/vishalkuo/bimap v0.0.0-20180703190407-09cff2814645/go.mod h1:SLUZBTfsmfFJDSKTVyh/ifAE50/GMATIYGTgr29/2Ms=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/zeebo/xxh3 v1.0.1 h1:FMSRIbkrLikb/0hZxmltpg84VkqDAT5M8ufXynuhXsI=
github.com/zeebo/xxh3 v1.0.1/go.mod h1:8VHV24/3AZLn3b6Mlp/KuC33LWH687Wq6EnziEB+rsA=
+3 -1
View File
@@ -20,7 +20,9 @@ import "minlib/component"
func GetNameComponentPosition(name *component.Identifier, searchString string) int {
components := name.GetComponents()
for i := 0; i < len(components); i++ {
if components[i].ToUri() == "/"+searchString {
// bug: IdentifierComponent.ToUri() 默认不带斜杠
// if components[i].ToUri() == "/"+searchString {
if components[i].ToUri() == searchString {
return i
}
}