Files
upstream-corteza/server/pkg/envoy/graph_test.go
upstream-mirror 7e385fc126
Some checks failed
SonarQube / SonarQube (push) Failing after 5m28s
E2e test on main branch push / server and client test (map[name:admin port:8080]) (push) Failing after 3m33s
Server and lib tests / Library test (js) (push) Failing after 1m36s
Server and lib tests / Library test (vue) (push) Successful in 2m24s
Server and lib tests / Web client test (admin) (push) Successful in 2m52s
Server and lib tests / Web client test (compose) (push) Successful in 3m23s
Server and lib tests / Web client test (discovery) (push) Successful in 2m49s
Server and lib tests / Web client test (one) (push) Successful in 2m52s
Server and lib tests / Web client test (privacy) (push) Successful in 2m44s
Server and lib tests / Web client test (reporter) (push) Successful in 2m56s
Server and lib tests / Web client test (workflow) (push) Successful in 3m0s
Server and lib tests / Server tests (push) Failing after 4m55s
E2e test on main branch push / notify-failure (push) Failing after 9s
Server and lib tests / Send matrix testing notification (push) Successful in 2s
Mark stale issues and pull requests / stale (push) Successful in 40s
snapshot of https://github.com/cortezaproject/corteza.git (2024.9.x, 2026-09-18; blobs > 131072B omitted)
2026-09-18 01:22:23 +05:00

430 lines
9.9 KiB
Go

package envoy
import (
"context"
"testing"
"github.com/cortezaproject/corteza/server/pkg/envoy/resource"
"github.com/stretchr/testify/require"
)
func TestGraph_Walk(t *testing.T) {
req := require.New(t)
ctx := context.Background()
t.Run("simple node link; a -> b", func(t *testing.T) {
bl := NewBuilder()
a := &testResource{
resType: "test:resource:1:",
identifiers: resource.Identifiers{"id1"},
refs: resource.RefSet{&resource.Ref{ResourceType: "test:resource:1:", Identifiers: resource.Identifiers{"id2"}}},
}
b := &testResource{
resType: "test:resource:1:",
identifiers: resource.Identifiers{"id2"},
refs: nil,
}
rr := []resource.Interface{
a,
b,
}
g, err := bl.Build(ctx, rr...)
req.NoError(err)
g.invert()
s, err := g.Next(ctx)
req.Equal(b, s.Res)
req.False(s.Conflicting)
s, err = g.Next(ctx)
req.Equal(a, s.Res)
req.False(s.Conflicting)
})
t.Run("cyclic node link; a -> b -> a", func(t *testing.T) {
bl := NewBuilder()
a := &testResource{
resType: "test:resource:1:",
identifiers: resource.Identifiers{"id1"},
refs: resource.RefSet{&resource.Ref{ResourceType: "test:resource:1:", Identifiers: resource.Identifiers{"id2"}}},
}
b := &testResource{
resType: "test:resource:1:",
identifiers: resource.Identifiers{"id2"},
refs: resource.RefSet{&resource.Ref{ResourceType: "test:resource:1:", Identifiers: resource.Identifiers{"id1"}}},
}
rr := []resource.Interface{
a,
b,
}
g, err := bl.Build(ctx, rr...)
req.NoError(err)
g.invert()
s, err := g.Next(ctx)
req.Equal(a, s.Res)
req.True(s.Conflicting)
s, err = g.Next(ctx)
req.Equal(b, s.Res)
req.False(s.Conflicting)
s, err = g.Next(ctx)
req.Equal(a, s.Res)
req.False(s.Conflicting)
})
t.Run("self-cycle; a -> a", func(t *testing.T) {
bl := NewBuilder()
a := &testResource{
resType: "test:resource:1:",
identifiers: resource.Identifiers{"id1"},
refs: resource.RefSet{&resource.Ref{ResourceType: "test:resource:1:", Identifiers: resource.Identifiers{"id1"}}},
}
rr := []resource.Interface{
a,
}
g, err := bl.Build(ctx, rr...)
req.NoError(err)
g.invert()
s, err := g.Next(ctx)
req.Equal(a, s.Res)
req.True(s.Conflicting)
s, err = g.Next(ctx)
req.Equal(a, s.Res)
req.False(s.Conflicting)
})
}
func TestGraph_WalkFlags(t *testing.T) {
req := require.New(t)
ctx := context.Background()
t.Run("simple node link; a -> b -> c -> c", func(t *testing.T) {
bl := NewBuilder()
a := &testResource{
resType: "test:resource:1:",
identifiers: resource.Identifiers{"id1"},
refs: resource.RefSet{&resource.Ref{ResourceType: "test:resource:1:", Identifiers: resource.Identifiers{"id2"}}},
}
b := &testResource{
resType: "test:resource:1:",
identifiers: resource.Identifiers{"id2"},
refs: resource.RefSet{&resource.Ref{ResourceType: "test:resource:1:", Identifiers: resource.Identifiers{"id3"}}},
}
c := &testResource{
resType: "test:resource:1:",
identifiers: resource.Identifiers{"id3"},
refs: resource.RefSet{&resource.Ref{ResourceType: "test:resource:1:", Identifiers: resource.Identifiers{"id3"}}},
}
rr := []resource.Interface{
a,
b,
c,
}
g, err := bl.Build(ctx, rr...)
req.NoError(err)
s, err := g.NextInverted(ctx)
req.NoError(err)
req.Equal(c, s.Res)
req.True(s.Conflicting)
s, err = g.NextInverted(ctx)
req.NoError(err)
req.Equal(b, s.Res)
req.False(s.Conflicting)
s, err = g.NextInverted(ctx)
req.NoError(err)
req.Equal(a, s.Res)
req.False(s.Conflicting)
s, err = g.NextInverted(ctx)
req.NoError(err)
req.Equal(c, s.Res)
req.False(s.Conflicting)
s, err = g.NextInverted(ctx)
req.NoError(err)
req.Nil(s)
})
t.Run("simple node link; a -> b -> c -> d -> b; a -> b -> e", func(t *testing.T) {
bl := NewBuilder()
a := &testResource{
resType: "test:resource:1:",
identifiers: resource.Identifiers{"id1"},
refs: resource.RefSet{&resource.Ref{ResourceType: "test:resource:1:", Identifiers: resource.Identifiers{"id2"}}},
}
b := &testResource{
resType: "test:resource:1:",
identifiers: resource.Identifiers{"id2"},
refs: resource.RefSet{&resource.Ref{ResourceType: "test:resource:1:", Identifiers: resource.Identifiers{"id3"}}, &resource.Ref{ResourceType: "test:resource:1:", Identifiers: resource.Identifiers{"id5"}}},
}
c := &testResource{
resType: "test:resource:1:",
identifiers: resource.Identifiers{"id3"},
refs: resource.RefSet{&resource.Ref{ResourceType: "test:resource:1:", Identifiers: resource.Identifiers{"id4"}}},
}
d := &testResource{
resType: "test:resource:1:",
identifiers: resource.Identifiers{"id4"},
refs: resource.RefSet{&resource.Ref{ResourceType: "test:resource:1:", Identifiers: resource.Identifiers{"id2"}}},
}
e := &testResource{
resType: "test:resource:1:",
identifiers: resource.Identifiers{"id5"},
refs: nil,
}
rr := []resource.Interface{
a,
b,
c,
d,
e,
}
g, err := bl.Build(ctx, rr...)
req.NoError(err)
s, err := g.NextInverted(ctx)
req.NoError(err)
req.Equal(e, s.Res)
req.False(s.Conflicting)
s, err = g.NextInverted(ctx)
req.NoError(err)
req.Equal(b, s.Res)
req.True(s.Conflicting)
s, err = g.NextInverted(ctx)
req.NoError(err)
req.Equal(a, s.Res)
req.False(s.Conflicting)
s, err = g.NextInverted(ctx)
req.NoError(err)
req.Equal(d, s.Res)
req.False(s.Conflicting)
s, err = g.NextInverted(ctx)
req.NoError(err)
req.Equal(c, s.Res)
req.False(s.Conflicting)
s, err = g.NextInverted(ctx)
req.NoError(err)
req.Equal(b, s.Res)
req.False(s.Conflicting)
s, err = g.NextInverted(ctx)
req.NoError(err)
req.Nil(s)
})
t.Run("simple node link; a -> b -> c -> d -> b; a -> b -> c -> e -> b", func(t *testing.T) {
bl := NewBuilder()
a := &testResource{
resType: "test:resource:1:",
identifiers: resource.Identifiers{"id1"},
refs: resource.RefSet{&resource.Ref{ResourceType: "test:resource:1:", Identifiers: resource.Identifiers{"id2"}}},
}
b := &testResource{
resType: "test:resource:1:",
identifiers: resource.Identifiers{"id2"},
refs: resource.RefSet{&resource.Ref{ResourceType: "test:resource:1:", Identifiers: resource.Identifiers{"id3"}}},
}
c := &testResource{
resType: "test:resource:1:",
identifiers: resource.Identifiers{"id3"},
refs: resource.RefSet{&resource.Ref{ResourceType: "test:resource:1:", Identifiers: resource.Identifiers{"id4"}}, &resource.Ref{ResourceType: "test:resource:1:", Identifiers: resource.Identifiers{"id5"}}},
}
d := &testResource{
resType: "test:resource:1:",
identifiers: resource.Identifiers{"id4"},
refs: resource.RefSet{&resource.Ref{ResourceType: "test:resource:1:", Identifiers: resource.Identifiers{"id2"}}},
}
e := &testResource{
resType: "test:resource:1:",
identifiers: resource.Identifiers{"id5"},
refs: resource.RefSet{&resource.Ref{ResourceType: "test:resource:1:", Identifiers: resource.Identifiers{"id2"}}},
}
rr := []resource.Interface{
a,
b,
c,
d,
e,
}
g, err := bl.Build(ctx, rr...)
req.NoError(err)
s, err := g.NextInverted(ctx)
req.NoError(err)
req.Equal(b, s.Res)
req.True(s.Conflicting)
s, err = g.NextInverted(ctx)
req.NoError(err)
req.Equal(a, s.Res)
req.False(s.Conflicting)
s, err = g.NextInverted(ctx)
req.NoError(err)
req.Equal(d, s.Res)
req.False(s.Conflicting)
s, err = g.NextInverted(ctx)
req.NoError(err)
req.Equal(e, s.Res)
req.False(s.Conflicting)
s, err = g.NextInverted(ctx)
req.NoError(err)
req.Equal(c, s.Res)
req.False(s.Conflicting)
s, err = g.NextInverted(ctx)
req.NoError(err)
req.Equal(b, s.Res)
req.False(s.Conflicting)
s, err = g.NextInverted(ctx)
req.NoError(err)
req.Nil(s)
})
}
func TestGraph_Utilities(t *testing.T) {
req := require.New(t)
t.Run("adding & removing nodes", func(t *testing.T) {
g := newGraph()
n1 := newNode(nil)
n2 := newNode(nil)
// Adding nodes
g.addNode(n1, n2)
req.Len(g.nn, 2)
req.Equal(n1, g.nn[0])
req.Equal(n2, g.nn[1])
// Dependencies
g.addChild(n1, n2)
g.addParent(n2, n1)
req.True(g.childNodes(n1).has(n2))
req.True(g.parentNodes(n2).has(n1))
// Removing nodes
g.removeNode(n1, n2)
req.False(g.childNodes(n1).has(n2))
req.False(g.parentNodes(n2).has(n1))
})
t.Run("inverted graph", func(t *testing.T) {
g := newGraph()
n1 := newNode(nil)
n2 := newNode(nil)
// Adding nodes
g.addNode(n1, n2)
req.Len(g.nn, 2)
req.Equal(n1, g.nn[0])
req.Equal(n2, g.nn[1])
// Dependencies
g.addChild(n1, n2)
g.addParent(n2, n1)
g.invert()
req.True(g.parentNodes(n1).has(n2))
req.True(g.childNodes(n2).has(n1))
})
t.Run("inverted child dependencies", func(t *testing.T) {
g := newGraph()
n1 := newNode(nil)
n2 := newNode(nil)
n3 := newNode(nil)
g.addNode(n1, n2, n3)
g.addChild(n1, n2)
g.invert()
g.addChild(n1, n3)
req.Equal(n2, n1.cc[0])
req.Equal(n3, n1.pp[0])
g.removeChild(n1, n3)
req.Len(n1.pp, 0)
})
t.Run("inverted parent dependencies", func(t *testing.T) {
g := newGraph()
n1 := newNode(nil)
n2 := newNode(nil)
n3 := newNode(nil)
g.addNode(n1, n2, n3)
g.addParent(n1, n2)
g.invert()
g.addParent(n1, n3)
req.Equal(n2, n1.pp[0])
req.Equal(n3, n1.cc[0])
g.removeParent(n1, n3)
req.Len(n1.cc, 0)
})
// This one is just for codecoverage; the logic is nothing
t.Run("remove all child/parent nodes", func(t *testing.T) {
g := newGraph()
n1 := newNode(nil)
n2 := newNode(nil)
g.addNode(n1, n2)
g.addChild(n1, n2)
g.addParent(n1, n2)
g.removeChild(n1)
g.removeParent(n1)
req.Len(n1.cc, 0)
req.Len(n1.pp, 0)
// Inverted graph
g.addChild(n1, n2)
g.addParent(n1, n2)
g.invert()
g.removeChild(n1)
g.removeParent(n1)
req.Len(n1.cc, 0)
req.Len(n1.pp, 0)
})
}