// Copyright 2019 Yunion // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package conditionparser import ( "go/parser" "testing" "yunion.io/x/jsonutils" ) func TestAst(t *testing.T) { input := jsonutils.NewDict() input.Add(jsonutils.NewString("windows"), "server", "os_type") disk := jsonutils.NewDict() disk.Add(jsonutils.NewString("ssd"), "medium_type") disks := jsonutils.NewArray(disk) input.Add(disks, "server", "disks") input.Add(disk, "server", "disk.0") cases := []struct { in string want bool }{ {`server.os_type == "windows"`, true}, {`server.os_type.startswith("window")`, true}, {`server.disks[0].medium_type == "ssd"`, true}, {`server.disks[0].medium_type == "hdd"`, false}, {`server.os_type == "windows" && server.disks[0].medium_type == "ssd"`, true}, {`server.contains("os_type")`, true}, {`server.disks[0].contains("medium_type")`, true}, {`server.disk[0].contains("medium_type")`, true}, {`server.disks[0].contains("backend")`, false}, {`server.keys().contains("os_type", "disks")`, true}, {`server.keys() == "os_type"`, true}, {`server.keys() == "os_type1"`, false}, } for _, c := range cases { result, err := EvalBool(c.in, input) if err != nil { t.Errorf("eval expr %s error %s", c.in, err) return } if result != c.want { t.Errorf("expect %v got %v", c.want, result) return } } } func TestIsValid(t *testing.T) { cases := []struct { in string want bool }{ {`server.os_type == "windows"`, true}, {`server.os_type ==`, false}, {`dfadsfsdf ==`, false}, {`dfadsfsdf +`, false}, } for _, c := range cases { got := IsValid(c.in) if got != c.want { t.Errorf("%s is valid %v got %v", c.in, c.want, got) } } } func TestEval2(t *testing.T) { inputStr := `{"server": {"disable_delete":false, "disk.0":{"backend":"local","format":"qcow2","image_id":"4b9fa54c-858c-4c2b-8719-27aee120b3cb","image_properties":{"os_arch":"x86_64","os_distribution":"CentOS","os_type":"Linux","os_version":"7.5.1804"},"medium":"hybrid","size":40960}, "hypervisor":"kvm","keypair_id":"None","name":"testsched","os_type":"Linux","owner_tenant_id":"5d65667d112e47249ae66dbd7bc07030", "sched_tag.0":"ssd","secgrp_id":"default","vcpu_count":1,"vmem_size":1024}}` input, err := jsonutils.ParseString(inputStr) if err != nil { t.Errorf("fail to parse server json") return } cases := []struct { in string want bool }{ {`server.os_type == "Linux"`, true}, {`server["os_type"] == "Linux"`, true}, {`server.vmem_size > 2048`, false}, {`server.hypervisor.in("kvm", "aliyun")`, true}, {`server.disable_delete`, false}, {`server.disk[0].backend == "local"`, true}, {`server.sched_tag[0] != "ssd"`, false}, {`server.sched_tag[0] == "ssd"`, true}, // {`server.os_type == "windows" && server.disks[0].medium_type == "ssd"`, true}, } for _, c := range cases { result, err := EvalBool(c.in, input) if err != nil { t.Errorf("eval expr %s error %s", c.in, err) return } if result != c.want { t.Errorf("expect %v got %v", c.want, result) return } } } func TestEval3(t *testing.T) { exprStr := `server.disk.backend == "local"` expr, err := parser.ParseExpr(exprStr) if err != nil { t.Errorf("parse exprStr fail %s %s", exprStr, err) return } t.Logf("%s", jsonutils.Marshal(expr)) inputStr := `{"server":{ "disk.0":{"backend": "local", "medium": "hdd"}, "disk.1":{"backend": "local", "medium": "hdd"}, "disk.2":{"backend": "rbd", "medium": "ssd"}, "disk.3":{"backend": "rbd", "medium": "ssd"}} }` input, err := jsonutils.ParseString(inputStr) if err != nil { t.Errorf("fail to parse server json %s", err) return } cases := []struct { in string want bool }{ {`server.disk.backend == "local"`, true}, {`server.disk.medium == "ssd"`, true}, {`server.disk.medium == "hdd"`, true}, {`server.disk.medium == "hybrid"`, false}, {`server.disk.medium.contains("ssd")`, true}, {`server.disk[0]["medium"] == "hdd"`, true}, {`server["disk"][0]["medium"] == "hdd"`, true}, {`server.disk[0].medium.in(server.disk.medium)`, true}, {`server.disk.len() == 4`, true}, {`server.disk[0].len() == 2`, true}, {`server.disk[0].backend.len() == 5`, true}, {`server.disk[0].backend.substr(1) == "l"`, true}, {`server.disk[0].backend.substr(0, 1) == "l"`, true}, {`server.disk[0].backend.substr(1, 2) == "o"`, true}, {`server.disk[0].backend.substr(1, -2) == "oc"`, true}, } for _, c := range cases { result, err := EvalBool(c.in, input) if err != nil { t.Errorf("eval expr %s error %s", c.in, err) return } if result != c.want { t.Errorf("%s expect %v got %v", c.in, c.want, result) return } } } func TestEvalString(t *testing.T) { input := jsonutils.NewDict() input.Add(jsonutils.NewString("myname"), "name") input.Add(jsonutils.NewString("myhostname"), "host", "name") input.Add(jsonutils.NewString("myproject"), "project", "name") input.Add(jsonutils.NewString("myprojectId"), "project", "id") cases := []struct { input string want string }{ { input: "host.name", want: "myhostname", }, { input: "project.id", want: "myprojectId", }, { input: "project.name", want: "myproject", }, { input: "name", want: "myname", }, { input: `name+"/"+project.name`, want: "myname/myproject", }, } for _, c := range cases { got, err := EvalString(c.input, input) if err != nil { t.Errorf("Eval %s fail: %s", c.input, err) } else if got != c.want { t.Errorf("Eval %s want %s got %s", c.input, c.want, got) } } }