Merge pull request #1356 from Gustav-Simonsson/debug_develop
Debug develop
This commit is contained in:
commit
9d8b512b27
@ -2,7 +2,6 @@ language: go
|
|||||||
go:
|
go:
|
||||||
- 1.4.2
|
- 1.4.2
|
||||||
before_install:
|
before_install:
|
||||||
- sudo add-apt-repository ppa:beineri/opt-qt541 -y
|
|
||||||
- sudo apt-get update -qq
|
- sudo apt-get update -qq
|
||||||
- sudo apt-get install -yqq libgmp3-dev
|
- sudo apt-get install -yqq libgmp3-dev
|
||||||
install:
|
install:
|
||||||
@ -22,14 +21,12 @@ after_success:
|
|||||||
- if [ "$COVERALLS_TOKEN" ]; then goveralls -coverprofile=profile.cov -service=travis-ci -repotoken $COVERALLS_TOKEN; fi
|
- if [ "$COVERALLS_TOKEN" ]; then goveralls -coverprofile=profile.cov -service=travis-ci -repotoken $COVERALLS_TOKEN; fi
|
||||||
env:
|
env:
|
||||||
global:
|
global:
|
||||||
- PKG_CONFIG_PATH=/opt/qt54/lib/pkgconfig
|
|
||||||
- LD_LIBRARY_PATH=/opt/qt54/lib
|
|
||||||
- secure: "U2U1AmkU4NJBgKR/uUAebQY87cNL0+1JHjnLOmmXwxYYyj5ralWb1aSuSH3qSXiT93qLBmtaUkuv9fberHVqrbAeVlztVdUsKAq7JMQH+M99iFkC9UiRMqHmtjWJ0ok4COD1sRYixxi21wb/JrMe3M1iL4QJVS61iltjHhVdM64="
|
- secure: "U2U1AmkU4NJBgKR/uUAebQY87cNL0+1JHjnLOmmXwxYYyj5ralWb1aSuSH3qSXiT93qLBmtaUkuv9fberHVqrbAeVlztVdUsKAq7JMQH+M99iFkC9UiRMqHmtjWJ0ok4COD1sRYixxi21wb/JrMe3M1iL4QJVS61iltjHhVdM64="
|
||||||
|
|
||||||
notifications:
|
notifications:
|
||||||
webhooks:
|
webhooks:
|
||||||
urls:
|
urls:
|
||||||
- https://webhooks.gitter.im/e/e09ccdce1048c5e03445
|
- https://webhooks.gitter.im/e/e09ccdce1048c5e03445
|
||||||
on_success: change # options: [always|never|change] default: always
|
on_success: change
|
||||||
on_failure: always # options: [always|never|change] default: always
|
on_failure: always
|
||||||
on_start: false # default: false
|
on_start: false
|
||||||
|
@ -44,11 +44,10 @@ Executables
|
|||||||
Go Ethereum comes with several wrappers/executables found in
|
Go Ethereum comes with several wrappers/executables found in
|
||||||
[the `cmd` directory](https://github.com/ethereum/go-ethereum/tree/develop/cmd):
|
[the `cmd` directory](https://github.com/ethereum/go-ethereum/tree/develop/cmd):
|
||||||
|
|
||||||
* `mist` Official Ethereum Browser (ethereum GUI client)
|
|
||||||
* `geth` Ethereum CLI (ethereum command line interface client)
|
* `geth` Ethereum CLI (ethereum command line interface client)
|
||||||
* `bootnode` runs a bootstrap node for the Discovery Protocol
|
* `bootnode` runs a bootstrap node for the Discovery Protocol
|
||||||
* `ethtest` test tool which runs with the [tests](https://github.com/ethereum/testes) suite:
|
* `ethtest` test tool which runs with the [tests](https://github.com/ethereum/tests) suite:
|
||||||
`cat file | ethtest`.
|
`/path/to/test.json > ethtest --test BlockTests --stdin`.
|
||||||
* `evm` is a generic Ethereum Virtual Machine: `evm -code 60ff60ff -gas
|
* `evm` is a generic Ethereum Virtual Machine: `evm -code 60ff60ff -gas
|
||||||
10000 -price 0 -dump`. See `-h` for a detailed description.
|
10000 -price 0 -dump`. See `-h` for a detailed description.
|
||||||
* `disasm` disassembles EVM code: `echo "6001" | disasm`
|
* `disasm` disassembles EVM code: `echo "6001" | disasm`
|
||||||
@ -57,7 +56,7 @@ Go Ethereum comes with several wrappers/executables found in
|
|||||||
Command line options
|
Command line options
|
||||||
====================
|
====================
|
||||||
|
|
||||||
Both `mist` and `geth` can be configured via command line options, environment variables and config files.
|
`geth` can be configured via command line options, environment variables and config files.
|
||||||
|
|
||||||
To get the options available:
|
To get the options available:
|
||||||
|
|
||||||
|
@ -103,33 +103,17 @@ func monitor(ctx *cli.Context) {
|
|||||||
footer.Height = 3
|
footer.Height = 3
|
||||||
|
|
||||||
charts := make([]*termui.LineChart, len(monitored))
|
charts := make([]*termui.LineChart, len(monitored))
|
||||||
|
units := make([]int, len(monitored))
|
||||||
data := make([][]float64, len(monitored))
|
data := make([][]float64, len(monitored))
|
||||||
for i := 0; i < len(data); i++ {
|
for i := 0; i < len(monitored); i++ {
|
||||||
data[i] = make([]float64, 512)
|
charts[i] = createChart((termui.TermHeight() - footer.Height) / rows)
|
||||||
}
|
|
||||||
for i, metric := range monitored {
|
|
||||||
charts[i] = termui.NewLineChart()
|
|
||||||
if runtime.GOOS == "windows" {
|
|
||||||
charts[i].Mode = "dot"
|
|
||||||
}
|
|
||||||
charts[i].Data = make([]float64, 512)
|
|
||||||
charts[i].DataLabels = []string{""}
|
|
||||||
charts[i].Height = (termui.TermHeight() - footer.Height) / rows
|
|
||||||
charts[i].AxesColor = termui.ColorWhite
|
|
||||||
charts[i].PaddingBottom = -2
|
|
||||||
|
|
||||||
charts[i].Border.Label = metric
|
|
||||||
charts[i].Border.LabelFgColor = charts[i].Border.FgColor | termui.AttrBold
|
|
||||||
charts[i].Border.FgColor = charts[i].Border.BgColor
|
|
||||||
|
|
||||||
row := termui.Body.Rows[i%rows]
|
row := termui.Body.Rows[i%rows]
|
||||||
row.Cols = append(row.Cols, termui.NewCol(12/cols, 0, charts[i]))
|
row.Cols = append(row.Cols, termui.NewCol(12/cols, 0, charts[i]))
|
||||||
}
|
}
|
||||||
termui.Body.AddRows(termui.NewRow(termui.NewCol(12, 0, footer)))
|
termui.Body.AddRows(termui.NewRow(termui.NewCol(12, 0, footer)))
|
||||||
termui.Body.Align()
|
|
||||||
termui.Render(termui.Body)
|
|
||||||
|
|
||||||
refreshCharts(xeth, monitored, data, charts, ctx, footer)
|
refreshCharts(xeth, monitored, data, units, charts, ctx, footer)
|
||||||
|
termui.Body.Align()
|
||||||
termui.Render(termui.Body)
|
termui.Render(termui.Body)
|
||||||
|
|
||||||
// Watch for various system events, and periodically refresh the charts
|
// Watch for various system events, and periodically refresh the charts
|
||||||
@ -149,7 +133,9 @@ func monitor(ctx *cli.Context) {
|
|||||||
termui.Render(termui.Body)
|
termui.Render(termui.Body)
|
||||||
}
|
}
|
||||||
case <-refresh:
|
case <-refresh:
|
||||||
refreshCharts(xeth, monitored, data, charts, ctx, footer)
|
if refreshCharts(xeth, monitored, data, units, charts, ctx, footer) {
|
||||||
|
termui.Body.Align()
|
||||||
|
}
|
||||||
termui.Render(termui.Body)
|
termui.Render(termui.Body)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -246,45 +232,63 @@ func fetchMetric(metrics map[string]interface{}, metric string) float64 {
|
|||||||
|
|
||||||
// refreshCharts retrieves a next batch of metrics, and inserts all the new
|
// refreshCharts retrieves a next batch of metrics, and inserts all the new
|
||||||
// values into the active datasets and charts
|
// values into the active datasets and charts
|
||||||
func refreshCharts(xeth *rpc.Xeth, metrics []string, data [][]float64, charts []*termui.LineChart, ctx *cli.Context, footer *termui.Par) {
|
func refreshCharts(xeth *rpc.Xeth, metrics []string, data [][]float64, units []int, charts []*termui.LineChart, ctx *cli.Context, footer *termui.Par) (realign bool) {
|
||||||
values, err := retrieveMetrics(xeth)
|
values, err := retrieveMetrics(xeth)
|
||||||
for i, metric := range metrics {
|
for i, metric := range metrics {
|
||||||
data[i] = append([]float64{fetchMetric(values, metric)}, data[i][:len(data[i])-1]...)
|
if len(data) < 512 {
|
||||||
updateChart(metric, data[i], charts[i], err)
|
data[i] = append([]float64{fetchMetric(values, metric)}, data[i]...)
|
||||||
|
} else {
|
||||||
|
data[i] = append([]float64{fetchMetric(values, metric)}, data[i][:len(data[i])-1]...)
|
||||||
|
}
|
||||||
|
if updateChart(metric, data[i], &units[i], charts[i], err) {
|
||||||
|
realign = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
updateFooter(ctx, err, footer)
|
updateFooter(ctx, err, footer)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// updateChart inserts a dataset into a line chart, scaling appropriately as to
|
// updateChart inserts a dataset into a line chart, scaling appropriately as to
|
||||||
// not display weird labels, also updating the chart label accordingly.
|
// not display weird labels, also updating the chart label accordingly.
|
||||||
func updateChart(metric string, data []float64, chart *termui.LineChart, err error) {
|
func updateChart(metric string, data []float64, base *int, chart *termui.LineChart, err error) (realign bool) {
|
||||||
dataUnits := []string{"", "K", "M", "G", "T", "E"}
|
dataUnits := []string{"", "K", "M", "G", "T", "E"}
|
||||||
timeUnits := []string{"ns", "µs", "ms", "s", "ks", "ms"}
|
timeUnits := []string{"ns", "µs", "ms", "s", "ks", "ms"}
|
||||||
colors := []termui.Attribute{termui.ColorBlue, termui.ColorCyan, termui.ColorGreen, termui.ColorYellow, termui.ColorRed, termui.ColorRed}
|
colors := []termui.Attribute{termui.ColorBlue, termui.ColorCyan, termui.ColorGreen, termui.ColorYellow, termui.ColorRed, termui.ColorRed}
|
||||||
|
|
||||||
// Extract only part of the data that's actually visible
|
// Extract only part of the data that's actually visible
|
||||||
data = data[:chart.Width*2]
|
if chart.Width*2 < len(data) {
|
||||||
|
data = data[:chart.Width*2]
|
||||||
|
}
|
||||||
// Find the maximum value and scale under 1K
|
// Find the maximum value and scale under 1K
|
||||||
high := data[0]
|
high := 0.0
|
||||||
for _, value := range data[1:] {
|
if len(data) > 0 {
|
||||||
high = math.Max(high, value)
|
high = data[0]
|
||||||
|
for _, value := range data[1:] {
|
||||||
|
high = math.Max(high, value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
unit, scale := 0, 1.0
|
unit, scale := 0, 1.0
|
||||||
for high >= 1000 {
|
for high >= 1000 {
|
||||||
high, unit, scale = high/1000, unit+1, scale*1000
|
high, unit, scale = high/1000, unit+1, scale*1000
|
||||||
}
|
}
|
||||||
|
// If the unit changes, re-create the chart (hack to set max height...)
|
||||||
|
if unit != *base {
|
||||||
|
realign, *base, *chart = true, unit, *createChart(chart.Height)
|
||||||
|
}
|
||||||
// Update the chart's data points with the scaled values
|
// Update the chart's data points with the scaled values
|
||||||
|
if cap(chart.Data) < len(data) {
|
||||||
|
chart.Data = make([]float64, len(data))
|
||||||
|
}
|
||||||
|
chart.Data = chart.Data[:len(data)]
|
||||||
for i, value := range data {
|
for i, value := range data {
|
||||||
chart.Data[i] = value / scale
|
chart.Data[i] = value / scale
|
||||||
}
|
}
|
||||||
// Update the chart's label with the scale units
|
// Update the chart's label with the scale units
|
||||||
chart.Border.Label = metric
|
|
||||||
|
|
||||||
units := dataUnits
|
units := dataUnits
|
||||||
if strings.Contains(metric, "/Percentiles/") || strings.Contains(metric, "/pauses/") {
|
if strings.Contains(metric, "/Percentiles/") || strings.Contains(metric, "/pauses/") {
|
||||||
units = timeUnits
|
units = timeUnits
|
||||||
}
|
}
|
||||||
|
chart.Border.Label = metric
|
||||||
if len(units[unit]) > 0 {
|
if len(units[unit]) > 0 {
|
||||||
chart.Border.Label += " [" + units[unit] + "]"
|
chart.Border.Label += " [" + units[unit] + "]"
|
||||||
}
|
}
|
||||||
@ -292,6 +296,24 @@ func updateChart(metric string, data []float64, chart *termui.LineChart, err err
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
chart.LineColor = termui.ColorRed | termui.AttrBold
|
chart.LineColor = termui.ColorRed | termui.AttrBold
|
||||||
}
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// createChart creates an empty line chart with the default configs.
|
||||||
|
func createChart(height int) *termui.LineChart {
|
||||||
|
chart := termui.NewLineChart()
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
chart.Mode = "dot"
|
||||||
|
}
|
||||||
|
chart.DataLabels = []string{""}
|
||||||
|
chart.Height = height
|
||||||
|
chart.AxesColor = termui.ColorWhite
|
||||||
|
chart.PaddingBottom = -2
|
||||||
|
|
||||||
|
chart.Border.LabelFgColor = chart.Border.FgColor | termui.AttrBold
|
||||||
|
chart.Border.FgColor = chart.Border.BgColor
|
||||||
|
|
||||||
|
return chart
|
||||||
}
|
}
|
||||||
|
|
||||||
// updateFooter updates the footer contents based on any encountered errors.
|
// updateFooter updates the footer contents based on any encountered errors.
|
||||||
|
@ -7,6 +7,8 @@ import (
|
|||||||
"math/rand"
|
"math/rand"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
@ -104,6 +106,7 @@ type Fetcher struct {
|
|||||||
broadcastMeter metrics.Meter // Counter for metering the inbound propagations
|
broadcastMeter metrics.Meter // Counter for metering the inbound propagations
|
||||||
broadcastTimer metrics.Timer // Counter and timer for metering the block forwarding
|
broadcastTimer metrics.Timer // Counter and timer for metering the block forwarding
|
||||||
discardMeter metrics.Meter // Counter for metering the discarded blocks
|
discardMeter metrics.Meter // Counter for metering the discarded blocks
|
||||||
|
futureMeter metrics.Meter // Counter for metering future blocks
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a block fetcher to retrieve blocks based on hash announcements.
|
// New creates a block fetcher to retrieve blocks based on hash announcements.
|
||||||
@ -131,6 +134,7 @@ func New(getBlock blockRetrievalFn, validateBlock blockValidatorFn, broadcastBlo
|
|||||||
broadcastMeter: metrics.GetOrRegisterMeter("eth/sync/RemoteBroadcasts", metrics.DefaultRegistry),
|
broadcastMeter: metrics.GetOrRegisterMeter("eth/sync/RemoteBroadcasts", metrics.DefaultRegistry),
|
||||||
broadcastTimer: metrics.GetOrRegisterTimer("eth/sync/LocalBroadcasts", metrics.DefaultRegistry),
|
broadcastTimer: metrics.GetOrRegisterTimer("eth/sync/LocalBroadcasts", metrics.DefaultRegistry),
|
||||||
discardMeter: metrics.GetOrRegisterMeter("eth/sync/DiscardedBlocks", metrics.DefaultRegistry),
|
discardMeter: metrics.GetOrRegisterMeter("eth/sync/DiscardedBlocks", metrics.DefaultRegistry),
|
||||||
|
futureMeter: metrics.GetOrRegisterMeter("eth/sync/FutureBlocks", metrics.DefaultRegistry),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -323,7 +327,7 @@ func (f *Fetcher) loop() {
|
|||||||
hash := block.Hash()
|
hash := block.Hash()
|
||||||
|
|
||||||
// Filter explicitly requested blocks from hash announcements
|
// Filter explicitly requested blocks from hash announcements
|
||||||
if _, ok := f.fetching[hash]; ok {
|
if f.fetching[hash] != nil && f.queued[hash] == nil {
|
||||||
// Discard if already imported by other means
|
// Discard if already imported by other means
|
||||||
if f.getBlock(hash) == nil {
|
if f.getBlock(hash) == nil {
|
||||||
explicit = append(explicit, block)
|
explicit = append(explicit, block)
|
||||||
@ -416,14 +420,22 @@ func (f *Fetcher) insert(peer string, block *types.Block) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Quickly validate the header and propagate the block if it passes
|
// Quickly validate the header and propagate the block if it passes
|
||||||
if err := f.validateBlock(block, parent); err != nil {
|
switch err := f.validateBlock(block, parent); err {
|
||||||
|
case nil:
|
||||||
|
// All ok, quickly propagate to our peers
|
||||||
|
f.broadcastTimer.UpdateSince(block.ReceivedAt)
|
||||||
|
go f.broadcastBlock(block, true)
|
||||||
|
|
||||||
|
case core.BlockFutureErr:
|
||||||
|
f.futureMeter.Mark(1)
|
||||||
|
// Weird future block, don't fail, but neither propagate
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Something went very wrong, drop the peer
|
||||||
glog.V(logger.Debug).Infof("Peer %s: block #%d [%x] verification failed: %v", peer, block.NumberU64(), hash[:4], err)
|
glog.V(logger.Debug).Infof("Peer %s: block #%d [%x] verification failed: %v", peer, block.NumberU64(), hash[:4], err)
|
||||||
f.dropPeer(peer)
|
f.dropPeer(peer)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
f.broadcastTimer.UpdateSince(block.ReceivedAt)
|
|
||||||
go f.broadcastBlock(block, true)
|
|
||||||
|
|
||||||
// Run the actual import and log any issues
|
// Run the actual import and log any issues
|
||||||
if _, err := f.insertChain(types.Blocks{block}); err != nil {
|
if _, err := f.insertChain(types.Blocks{block}); err != nil {
|
||||||
glog.V(logger.Warn).Infof("Peer %s: block #%d [%x] import failed: %v", peer, block.NumberU64(), hash[:4], err)
|
glog.V(logger.Warn).Infof("Peer %s: block #%d [%x] import failed: %v", peer, block.NumberU64(), hash[:4], err)
|
||||||
|
11
p2p/peer.go
11
p2p/peer.go
@ -249,15 +249,22 @@ func countMatchingProtocols(protocols []Protocol, caps []Cap) int {
|
|||||||
|
|
||||||
// matchProtocols creates structures for matching named subprotocols.
|
// matchProtocols creates structures for matching named subprotocols.
|
||||||
func matchProtocols(protocols []Protocol, caps []Cap, rw MsgReadWriter) map[string]*protoRW {
|
func matchProtocols(protocols []Protocol, caps []Cap, rw MsgReadWriter) map[string]*protoRW {
|
||||||
sort.Sort(capsByName(caps))
|
sort.Sort(capsByNameAndVersion(caps))
|
||||||
offset := baseProtocolLength
|
offset := baseProtocolLength
|
||||||
result := make(map[string]*protoRW)
|
result := make(map[string]*protoRW)
|
||||||
|
|
||||||
outer:
|
outer:
|
||||||
for _, cap := range caps {
|
for _, cap := range caps {
|
||||||
for _, proto := range protocols {
|
for _, proto := range protocols {
|
||||||
if proto.Name == cap.Name && proto.Version == cap.Version && result[cap.Name] == nil {
|
if proto.Name == cap.Name && proto.Version == cap.Version {
|
||||||
|
// If an old protocol version matched, revert it
|
||||||
|
if old := result[cap.Name]; old != nil {
|
||||||
|
offset -= old.Length
|
||||||
|
}
|
||||||
|
// Assign the new match
|
||||||
result[cap.Name] = &protoRW{Protocol: proto, offset: offset, in: make(chan Msg), w: rw}
|
result[cap.Name] = &protoRW{Protocol: proto, offset: offset, in: make(chan Msg), w: rw}
|
||||||
offset += proto.Length
|
offset += proto.Length
|
||||||
|
|
||||||
continue outer
|
continue outer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -196,3 +196,98 @@ func TestNewPeer(t *testing.T) {
|
|||||||
|
|
||||||
p.Disconnect(DiscAlreadyConnected) // Should not hang
|
p.Disconnect(DiscAlreadyConnected) // Should not hang
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMatchProtocols(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
Remote []Cap
|
||||||
|
Local []Protocol
|
||||||
|
Match map[string]protoRW
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
// No remote capabilities
|
||||||
|
Local: []Protocol{{Name: "a"}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// No local protocols
|
||||||
|
Remote: []Cap{{Name: "a"}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// No mutual protocols
|
||||||
|
Remote: []Cap{{Name: "a"}},
|
||||||
|
Local: []Protocol{{Name: "b"}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Some matches, some differences
|
||||||
|
Remote: []Cap{{Name: "local"}, {Name: "match1"}, {Name: "match2"}},
|
||||||
|
Local: []Protocol{{Name: "match1"}, {Name: "match2"}, {Name: "remote"}},
|
||||||
|
Match: map[string]protoRW{"match1": {Protocol: Protocol{Name: "match1"}}, "match2": {Protocol: Protocol{Name: "match2"}}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Various alphabetical ordering
|
||||||
|
Remote: []Cap{{Name: "aa"}, {Name: "ab"}, {Name: "bb"}, {Name: "ba"}},
|
||||||
|
Local: []Protocol{{Name: "ba"}, {Name: "bb"}, {Name: "ab"}, {Name: "aa"}},
|
||||||
|
Match: map[string]protoRW{"aa": {Protocol: Protocol{Name: "aa"}}, "ab": {Protocol: Protocol{Name: "ab"}}, "ba": {Protocol: Protocol{Name: "ba"}}, "bb": {Protocol: Protocol{Name: "bb"}}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// No mutual versions
|
||||||
|
Remote: []Cap{{Version: 1}},
|
||||||
|
Local: []Protocol{{Version: 2}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Multiple versions, single common
|
||||||
|
Remote: []Cap{{Version: 1}, {Version: 2}},
|
||||||
|
Local: []Protocol{{Version: 2}, {Version: 3}},
|
||||||
|
Match: map[string]protoRW{"": {Protocol: Protocol{Version: 2}}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Multiple versions, multiple common
|
||||||
|
Remote: []Cap{{Version: 1}, {Version: 2}, {Version: 3}, {Version: 4}},
|
||||||
|
Local: []Protocol{{Version: 2}, {Version: 3}},
|
||||||
|
Match: map[string]protoRW{"": {Protocol: Protocol{Version: 3}}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Various version orderings
|
||||||
|
Remote: []Cap{{Version: 4}, {Version: 1}, {Version: 3}, {Version: 2}},
|
||||||
|
Local: []Protocol{{Version: 2}, {Version: 3}, {Version: 1}},
|
||||||
|
Match: map[string]protoRW{"": {Protocol: Protocol{Version: 3}}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Versions overriding sub-protocol lengths
|
||||||
|
Remote: []Cap{{Version: 1}, {Version: 2}, {Version: 3}, {Name: "a"}},
|
||||||
|
Local: []Protocol{{Version: 1, Length: 1}, {Version: 2, Length: 2}, {Version: 3, Length: 3}, {Name: "a"}},
|
||||||
|
Match: map[string]protoRW{"": {Protocol: Protocol{Version: 3}}, "a": {Protocol: Protocol{Name: "a"}, offset: 3}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tt := range tests {
|
||||||
|
result := matchProtocols(tt.Local, tt.Remote, nil)
|
||||||
|
if len(result) != len(tt.Match) {
|
||||||
|
t.Errorf("test %d: negotiation mismatch: have %v, want %v", i, len(result), len(tt.Match))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// Make sure all negotiated protocols are needed and correct
|
||||||
|
for name, proto := range result {
|
||||||
|
match, ok := tt.Match[name]
|
||||||
|
if !ok {
|
||||||
|
t.Errorf("test %d, proto '%s': negotiated but shouldn't have", i, name)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if proto.Name != match.Name {
|
||||||
|
t.Errorf("test %d, proto '%s': name mismatch: have %v, want %v", i, name, proto.Name, match.Name)
|
||||||
|
}
|
||||||
|
if proto.Version != match.Version {
|
||||||
|
t.Errorf("test %d, proto '%s': version mismatch: have %v, want %v", i, name, proto.Version, match.Version)
|
||||||
|
}
|
||||||
|
if proto.offset-baseProtocolLength != match.offset {
|
||||||
|
t.Errorf("test %d, proto '%s': offset mismatch: have %v, want %v", i, name, proto.offset-baseProtocolLength, match.offset)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Make sure no protocols missed negotiation
|
||||||
|
for name, _ := range tt.Match {
|
||||||
|
if _, ok := result[name]; !ok {
|
||||||
|
t.Errorf("test %d, proto '%s': not negotiated, should have", i, name)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -43,8 +43,10 @@ func (cap Cap) String() string {
|
|||||||
return fmt.Sprintf("%s/%d", cap.Name, cap.Version)
|
return fmt.Sprintf("%s/%d", cap.Name, cap.Version)
|
||||||
}
|
}
|
||||||
|
|
||||||
type capsByName []Cap
|
type capsByNameAndVersion []Cap
|
||||||
|
|
||||||
func (cs capsByName) Len() int { return len(cs) }
|
func (cs capsByNameAndVersion) Len() int { return len(cs) }
|
||||||
func (cs capsByName) Less(i, j int) bool { return cs[i].Name < cs[j].Name }
|
func (cs capsByNameAndVersion) Swap(i, j int) { cs[i], cs[j] = cs[j], cs[i] }
|
||||||
func (cs capsByName) Swap(i, j int) { cs[i], cs[j] = cs[j], cs[i] }
|
func (cs capsByNameAndVersion) Less(i, j int) bool {
|
||||||
|
return cs[i].Name < cs[j].Name || (cs[i].Name == cs[j].Name && cs[i].Version < cs[j].Version)
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user