go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/mql/mql_test.go (about)

     1  // Copyright (c) Mondoo, Inc.
     2  // SPDX-License-Identifier: BUSL-1.1
     3  
     4  package mql_test
     5  
     6  import (
     7  	"fmt"
     8  	"os"
     9  	"strings"
    10  	"testing"
    11  
    12  	"github.com/stretchr/testify/assert"
    13  	"github.com/stretchr/testify/require"
    14  	"go.mondoo.com/cnquery"
    15  	"go.mondoo.com/cnquery/llx"
    16  	"go.mondoo.com/cnquery/mql"
    17  	"go.mondoo.com/cnquery/providers-sdk/v1/testutils"
    18  	"go.mondoo.com/cnquery/types"
    19  )
    20  
    21  var features cnquery.Features
    22  
    23  func init() {
    24  	features = getEnvFeatures()
    25  }
    26  
    27  func runtime() llx.Runtime {
    28  	return testutils.LinuxMock()
    29  }
    30  
    31  func getEnvFeatures() cnquery.Features {
    32  	env := os.Getenv("FEATURES")
    33  	if env == "" {
    34  		return cnquery.Features{}
    35  	}
    36  
    37  	arr := strings.Split(env, ",")
    38  	var fts cnquery.Features
    39  	for i := range arr {
    40  		v, ok := cnquery.FeaturesValue[arr[i]]
    41  		if ok {
    42  			fmt.Println("--> activate feature: " + arr[i])
    43  			fts = append(features, byte(v))
    44  		} else {
    45  			panic("cannot find requested feature: " + arr[i])
    46  		}
    47  	}
    48  	return fts
    49  }
    50  
    51  func TestMqlSimple(t *testing.T) {
    52  	tests := []struct {
    53  		query     string
    54  		assertion interface{}
    55  	}{
    56  		{"asset.platform", "arch"},
    57  		{"asset { platform version }", map[string]interface{}{
    58  			"platform": "arch",
    59  			"version":  "rolling",
    60  		}},
    61  		{"users { name uid }", []interface{}{
    62  			map[string]interface{}{"name": "root", "uid": int64(0)},
    63  			map[string]interface{}{"name": "bin", "uid": int64(1)},
    64  			map[string]interface{}{"name": "chris", "uid": int64(1000)},
    65  			map[string]interface{}{"name": "christopher", "uid": int64(1001)},
    66  		}},
    67  	}
    68  
    69  	for i := range tests {
    70  		one := tests[i]
    71  		t.Run(one.query, func(t *testing.T) {
    72  			res, err := mql.Exec(one.query, runtime(), features, nil)
    73  			assert.NoError(t, err)
    74  			assert.NoError(t, res.Error)
    75  			assert.Equal(t, one.assertion, res.Value)
    76  		})
    77  	}
    78  }
    79  
    80  func TestCustomData(t *testing.T) {
    81  	query := "{ \"a\": \"valuea\", \"b\": \"valueb\"}"
    82  
    83  	value, err := mql.Exec(query, runtime(), features, nil)
    84  	require.NoError(t, err)
    85  	assert.Equal(t, map[string]interface{}{"a": "valuea", "b": "valueb"}, value.Value)
    86  }
    87  
    88  func TestMqlProps(t *testing.T) {
    89  	query := "props.a + props.b"
    90  	props := map[string]*llx.Primitive{
    91  		"a": llx.IntPrimitive(2),
    92  		"b": llx.IntPrimitive(2),
    93  	}
    94  
    95  	value, err := mql.Exec(query, runtime(), features, props)
    96  	require.NoError(t, err)
    97  	assert.Equal(t, int64(4), value.Value)
    98  }
    99  
   100  func TestMqlIfElseProps(t *testing.T) {
   101  	me := mql.New(runtime(), cnquery.DefaultFeatures)
   102  	query := "if (props.a > 2) { return {\"a\": \"valuea\"} } return {\"a\": \"valueb\"}"
   103  
   104  	props := map[string]*llx.Primitive{
   105  		"a": llx.IntPrimitive(3),
   106  	}
   107  	value, err := me.Exec(query, props)
   108  	require.NoError(t, err)
   109  	assert.Equal(t, map[string]interface{}{"a": "valuea"}, value.Value)
   110  
   111  	props = map[string]*llx.Primitive{
   112  		"a": llx.IntPrimitive(2),
   113  	}
   114  	value, err = me.Exec(query, props)
   115  	require.NoError(t, err)
   116  	assert.Equal(t, map[string]interface{}{"a": "valueb"}, value.Value)
   117  }
   118  
   119  func TestMqlIfAndProps(t *testing.T) {
   120  	me := mql.New(runtime(), cnquery.DefaultFeatures)
   121  	query := "if (props.a > 2) { return {\"a\": \"valuea\"} }"
   122  
   123  	props := map[string]*llx.Primitive{
   124  		"a": llx.IntPrimitive(3),
   125  	}
   126  	value, err := me.Exec(query, props)
   127  	require.NoError(t, err)
   128  	assert.Equal(t, map[string]interface{}{"a": "valuea"}, value.Value)
   129  
   130  	props = map[string]*llx.Primitive{
   131  		"a": llx.IntPrimitive(2),
   132  	}
   133  	value, err = me.Exec(query, props)
   134  	require.NoError(t, err)
   135  	assert.Equal(t, nil, value.Value)
   136  }
   137  
   138  func TestResourceAliases(t *testing.T) {
   139  	x := testutils.InitTester(testutils.LinuxMock())
   140  	x.TestSimple(t, []testutils.SimpleTest{
   141  		{
   142  			Code:        "os.unix.sshd.config.file.path",
   143  			ResultIndex: 0,
   144  			Expectation: "/etc/ssh/sshd_config",
   145  		},
   146  		{
   147  			Code:        "os.unix.sshd { config.file.path }",
   148  			ResultIndex: 0,
   149  			Expectation: map[string]interface{}{
   150  				"_":   llx.ResourceData(&llx.MockResource{Name: "sshd"}, "os.unix.sshd"),
   151  				"__s": llx.NilData,
   152  				"__t": llx.BoolData(true),
   153  				"k6rlXoYpV48Qd19gKeNl+/IiPnkI5VNQBiqZBca3gDKsIRiLcpXQUlDv52x9sscIWiqOMpC7+x/aBpY0IUq0ww==": llx.StringData("/etc/ssh/sshd_config"),
   154  			},
   155  		},
   156  	})
   157  }
   158  
   159  func TestNullResources(t *testing.T) {
   160  	x := testutils.InitTester(testutils.LinuxMock())
   161  	x.TestSimple(t, []testutils.SimpleTest{
   162  		{
   163  			Code:        "muser.group",
   164  			ResultIndex: 0,
   165  			Expectation: &llx.MockResource{Name: "mgroup", ID: "group one"},
   166  		},
   167  		{
   168  			Code:        "muser.nullgroup",
   169  			ResultIndex: 0,
   170  			Expectation: nil,
   171  		},
   172  		{
   173  			Code:        "muser.nullgroup == null",
   174  			ResultIndex: 1,
   175  			Expectation: true,
   176  		},
   177  		{
   178  			Code:        "muser.nullgroup == empty",
   179  			ResultIndex: 2,
   180  			Expectation: true,
   181  		},
   182  		{
   183  			Code:        "muser.groups.where(null) == empty",
   184  			ResultIndex: 2,
   185  			Expectation: false,
   186  		},
   187  		{
   188  			Code:        "muser.groups.where(name == '') == empty",
   189  			ResultIndex: 2,
   190  			Expectation: true,
   191  		},
   192  		{
   193  			Code:        "muser.groups",
   194  			ResultIndex: 0,
   195  			Expectation: []interface{}{
   196  				&llx.MockResource{Name: "mgroup", ID: "group one"},
   197  				nil,
   198  			},
   199  		},
   200  		{
   201  			Code:        "muser { nullgroup }",
   202  			ResultIndex: 0,
   203  			Expectation: map[string]interface{}{
   204  				"_":   &llx.RawData{Type: types.Resource("muser"), Value: &llx.MockResource{Name: "muser"}},
   205  				"__s": llx.NilData,
   206  				"__t": llx.BoolTrue,
   207  				"A8qiFMpyfjKsr3OzVu+L+43W0BvYXoCPiwM7zu8AFQkBYEBMvZfR73ZsdfIqswmN1n9Qs/Soc1D7qxJipXv/ZA==": llx.ResourceData(nil, "mgroup"),
   208  			},
   209  		},
   210  	})
   211  }