go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/mql/internal/builder_test.go (about) 1 // Copyright (c) Mondoo, Inc. 2 // SPDX-License-Identifier: BUSL-1.1 3 4 package internal 5 6 import ( 7 "testing" 8 9 "github.com/stretchr/testify/assert" 10 "github.com/stretchr/testify/require" 11 "go.mondoo.com/cnquery/llx" 12 "go.mondoo.com/cnquery/types" 13 ) 14 15 func TestPrioritizeNode(t *testing.T) { 16 // ┌──────┐┌───┐ 17 // │eq1 ││eq2│ 18 // └┬────┬┘└──┬┘ 19 // ┌▽──┐┌▽──┐┌▽──┐ 20 // │dp1││dp2││dp3│ 21 // └─┬┬┘└─┬┬┘└┬─┬┘ 22 // ││ ││ │ │ 23 // ┌││───││──┘ │ 24 // ││└──┐││ │ 25 // ││┌──│┘│ │ 26 // ┌▽▽▽┐┌▽─▽┐┌──▽┐ 27 // │dps││rj1││rj2│ 28 // └───┘└┬──┘└┬──┘ 29 // ┌─────▽────▽┐ 30 // │scores │ 31 // └───────────┘ 32 33 nodes := map[NodeID]*Node{ 34 "eq1": {id: "eq1"}, 35 "eq2": {id: "eq1"}, 36 "dp1": {id: "eq1"}, 37 "dp2": {id: "eq1"}, 38 "dp3": {id: "eq1"}, 39 "rj1": {id: "rj1"}, 40 "rj2": {id: "rj2"}, 41 "scores": {id: "scores"}, 42 "dps": {id: "dps"}, 43 } 44 edges := map[NodeID][]NodeID{ 45 "eq1": {"dp1", "dp2"}, 46 "eq2": {"dp3"}, 47 "dp1": {"rj1", "dps"}, 48 "dp2": {"rj1", "dps"}, 49 "dp3": {"rj2", "dps"}, 50 "rj1": {"scores"}, 51 "rj2": {"scores"}, 52 } 53 54 priorityMap := map[NodeID]int{} 55 for n := range nodes { 56 prioritizeNode(nodes, edges, priorityMap, n) 57 } 58 59 require.Equal(t, len(nodes), len(priorityMap)) 60 assert.Equal(t, 1, priorityMap["scores"]) 61 assert.Equal(t, 1, priorityMap["dps"]) 62 assert.Greater(t, priorityMap["eq1"], priorityMap["dp1"]) 63 assert.Greater(t, priorityMap["eq1"], priorityMap["dp2"]) 64 assert.Greater(t, priorityMap["eq2"], priorityMap["dp3"]) 65 assert.Greater(t, priorityMap["dp1"], priorityMap["dps"]) 66 assert.Greater(t, priorityMap["dp1"], priorityMap["rj1"]) 67 assert.Greater(t, priorityMap["dp2"], priorityMap["dps"]) 68 assert.Greater(t, priorityMap["dp2"], priorityMap["rj1"]) 69 assert.Greater(t, priorityMap["dp3"], priorityMap["dps"]) 70 assert.Greater(t, priorityMap["dp3"], priorityMap["rj2"]) 71 assert.Greater(t, priorityMap["rj1"], priorityMap["scores"]) 72 assert.Greater(t, priorityMap["rj2"], priorityMap["scores"]) 73 } 74 75 func TestBuilder(t *testing.T) { 76 b := NewBuilder() 77 78 b.AddQuery( 79 &llx.CodeBundle{ 80 CodeV2: &llx.CodeV2{ 81 Id: "propertyquery", 82 Blocks: []*llx.Block{{ 83 Entrypoints: []uint64{1}, 84 Datapoints: []uint64{2}, 85 }}, 86 Checksums: map[uint64]string{1: "checksum1", 2: "pqep"}, 87 }, 88 }, nil, nil) 89 90 b.AddQuery( 91 &llx.CodeBundle{ 92 CodeV2: &llx.CodeV2{ 93 Id: "query1", 94 Blocks: []*llx.Block{{ 95 Entrypoints: []uint64{1}, 96 }}, 97 Checksums: map[uint64]string{1: "checksum2"}, 98 }, 99 }, map[string]string{"prop": "checksum1"}, nil) 100 101 b.AddQuery( 102 &llx.CodeBundle{ 103 CodeV2: &llx.CodeV2{ 104 Id: "query2", 105 Blocks: []*llx.Block{{ 106 Entrypoints: []uint64{1}, 107 Datapoints: []uint64{2}, 108 }}, 109 Checksums: map[uint64]string{1: "checksum3", 2: "checksum4"}, 110 }, 111 }, nil, map[string]*llx.Primitive{ 112 "resolvedprop": llx.StringPrimitive("hello"), 113 }) 114 b.AddDatapointType("checksum3", string(types.Bool)) 115 116 b.AddQuery( 117 &llx.CodeBundle{ 118 CodeV2: &llx.CodeV2{ 119 Id: "query3", 120 Blocks: []*llx.Block{{ 121 Datapoints: []uint64{1}, 122 }}, 123 Checksums: map[uint64]string{1: "checksum5"}, 124 }, 125 }, nil, nil) 126 b.CollectDatapoint("checksum5") 127 128 b.AddQuery( 129 &llx.CodeBundle{ 130 CodeV2: &llx.CodeV2{ 131 Id: "query4", 132 Blocks: []*llx.Block{{ 133 Datapoints: []uint64{1}, 134 }}, 135 Checksums: map[uint64]string{1: "checksum6"}, 136 }, 137 }, nil, nil) 138 139 b.AddQuery( 140 &llx.CodeBundle{ 141 CodeV2: &llx.CodeV2{ 142 Id: "query5", 143 Blocks: []*llx.Block{{ 144 Datapoints: []uint64{1, 2}, 145 }}, 146 Checksums: map[uint64]string{1: "checksum5", 2: "checksum7"}, 147 }, 148 MinMondooVersion: "9999.9999.9999", 149 }, nil, nil) 150 151 b.WithMondooVersion("100.0.0") 152 153 ge, err := b.Build(nil, nil, "assetMrn") 154 require.NoError(t, err) 155 156 hasNode(t, ge, "execution_query/propertyquery", ExecutionQueryNodeType) 157 hasOutEdges(t, ge, "execution_query/propertyquery", "checksum1", "pqep") 158 159 hasNode(t, ge, "execution_query/query1", ExecutionQueryNodeType) 160 hasOutEdges(t, ge, "execution_query/query1", "checksum2") 161 162 hasNode(t, ge, "execution_query/query2", ExecutionQueryNodeType) 163 hasOutEdges(t, ge, "execution_query/query2", "checksum3", "checksum4") 164 165 hasNode(t, ge, "execution_query/query3", ExecutionQueryNodeType) 166 hasOutEdges(t, ge, "execution_query/query3", "checksum5") 167 168 hasNode(t, ge, "execution_query/query4", ExecutionQueryNodeType) 169 hasOutEdges(t, ge, "execution_query/query4", "checksum6") 170 171 assert.NotContains(t, ge.nodes, "execution_query/query5") 172 assert.Nil(t, ge.nodes["checksum5"].data.(*DatapointNodeData).res) 173 if assert.NotNil(t, ge.nodes["checksum7"].data.(*DatapointNodeData).res) { 174 assert.Error(t, ge.nodes["checksum7"].data.(*DatapointNodeData).res.Data.Error) 175 } 176 177 hasNode(t, ge, "pqep", DatapointNodeType) 178 hasOutEdges(t, ge, "pqep", CollectionFinisherID) 179 180 hasNode(t, ge, "checksum1", DatapointNodeType) 181 hasOutEdges(t, ge, "checksum1", "execution_query/query1", CollectionFinisherID) 182 183 hasNode(t, ge, "checksum2", DatapointNodeType) 184 hasOutEdges(t, ge, "checksum2", CollectionFinisherID) 185 186 hasNode(t, ge, "checksum3", DatapointNodeType) 187 hasOutEdges(t, ge, "checksum3", CollectionFinisherID) 188 189 hasNode(t, ge, "checksum4", DatapointNodeType) 190 hasOutEdges(t, ge, "checksum4", CollectionFinisherID) 191 192 hasNode(t, ge, "checksum5", DatapointNodeType) 193 hasOutEdges(t, ge, "checksum5", DatapointCollectorID, CollectionFinisherID) 194 195 hasNode(t, ge, "checksum6", DatapointNodeType) 196 hasOutEdges(t, ge, "checksum6", CollectionFinisherID) 197 } 198 199 func hasNode(t *testing.T, ge *GraphExecutor, nodeID NodeID, nodeType NodeType) { 200 t.Helper() 201 if assert.Contains(t, ge.nodes, nodeID) { 202 assert.Equal(t, nodeType, ge.nodes[nodeID].nodeType) 203 } 204 } 205 206 func hasOutEdges(t *testing.T, ge *GraphExecutor, nodeID NodeID, edges ...NodeID) { 207 t.Helper() 208 require.Len(t, ge.edges[nodeID], len(edges)) 209 assert.ElementsMatch(t, ge.edges[nodeID], edges) 210 }