繁体   English   中英

Rego 策略的测试用例

[英]Test Cases for Rego Polices

对不起,我的新手问题。 我已经编写了一个 rego 规则来检查 ASV 名称,现在我正在寻找相同的测试用例。 我查看了示例测试用例,但没有成功为我的策略编写(粘贴在下面)。 想知道我怎么能得到下面规则的肯定和失败案例。

asv_list = {"ASVONE","ASVXYZ"} 
check_asv := { resources[i]: Reason |
    resources:=[resource | data[j] ;
        list := {x| x:=asv_list[_]}
        not(list[data[j].ASV])
        resource:=data[j].Name]
        
    Reason := sprintf("THE ASV - %v being used is not a valid ASV", [data[j].ASV])
}

data = {resource |
    doc = input[i];
        key_ids := [k | doc[k]; startswith(k, "tag."); k != "tag.#"; endswith(k, ".key")]
    resource := {
        doc[k] : doc[replace(k, ".key", ".value")] | key_ids[_] == k
    }
}

如果您尝试测试check_asv您的正面和负面测试用例看起来很相似:

  • 定义输入值
  • 定义期望值
  • 当使用测试输入评估时,断言check_asv等于预期值

例如:

test_check_asv_positive {
  expected := {"r1": "..."} 
  fake_input := [{"Name": "foo", ...}]
  check_asv == expected with input as fake_input
}

不过,在开始为您的规则编写测试之前,我认为您应该澄清您试图表达的逻辑,因为有一些危险信号会跳出来。 我试图分解我在下面的政策中看到的问题。 最后,我写了一些示例测试用例。

格式化文件以使其更易于阅读

首先,只需将 Rego 格式化,使其更易于阅读。 我将您的示例粘贴到一个文件中,添加了一个package (使其成为有效的 .rego 文件),然后运行opa fmt file.rego

asv_list = {"ASVONE", "ASVXYZ"}

check_asv := {resources[i]: Reason |
        resources := [resource |
                data[j]
                list := {x | x := asv_list[_]}
                not list[data[j].ASV]
                resource := data[j].Name
        ]

        Reason := sprintf("THE ASV - %v being used is not a valid ASV", [data[j].ASV])
}

data = {resource |
        doc = input[i]
        key_ids := [k |
                doc[k]
                startswith(k, "tag.")
                k != "tag.#"
                endswith(k, ".key")
        ]

        resource := {doc[k]: doc[replace(k, ".key", ".value")] |
                key_ids[_] == k
        }
}

这更容易阅读。

不要命名规则data

我建议不要命名该规则data Rego 中的data是一个特殊的全局变量,它指的是策略引擎中缓存的状态。 任何来自 OPA 外部或由 OPA 内部规则生成的data都可以在data下访问。 定义名为data的规则是允许的,但它令人困惑。 data重命名为域中有意义的名称。 例如,如果这些是虚拟机资源,您可以将它们命名为vm_resources 在这种情况下,我没有太多事情要做,所以我将把它重命名为input_docs因为doc被用作变量名:

check_asv := {resources[i]: Reason |
        resources := [resource |
                input_docs[j]
                list := {x | x := asv_list[_]}
                not list[input_docs[j].ASV]
                resource := input_docs[j].Name
        ]

        Reason := sprintf("THE ASV - %v being used is not a valid ASV", [input_docs[j].ASV])
}

input_docs = {resource |
        doc = input[i]
        key_ids := [k |
                doc[k]
                startswith(k, "tag.")
                k != "tag.#"
                endswith(k, ".key")
        ]

        resource := {doc[k]: doc[replace(k, ".key", ".value")] |
                key_ids[_] == k
        }
}

简化input_docs helper 规则(原来叫data

乍一看,这条规则做了很多工作,但实际上并非如此。 第一行( doc = input[i] )只是遍历input每个元素。 规则的其余部分基于input每个元素。 第二个表达式key_ids := [... ,从元素计算对象键的数组。 第三个表达式resources := {doc[k]: ... ,通过映射元素构造一个新对象。

第一个表达式不能简化太多,但是,最好使用:=而不是= ,因为i没有在其他任何地方被引用,我们只能使用_ 第一个表达式变为:

doc := input[_]

第二个表达式计算一个键数组,但过滤有点多余: k不能等于tag.# AND 以.key结尾,因此可以删除!=表达式:

key_ids := [k |
  some k
  doc[k]
  startswith(k, "tag.")
  endswith(k, ".key")
]

此时我们可以停止,但值得注意的是规则中的第二个和第三个表达式都只是迭代doc对象。 这里没有理由使用两个单独的表达式。 为了简化这个规则,我们可以将它们组合起来:

input_docs = {resource |        
        doc := input[_]
        resource := {v: x |
                some k
                v := doc[k]
                startswith(k, "tag.")
                endswith(k, ".key")
                x := doc[replace(k, ".key", ".value")]
        }
}

简化check_asv规则

现在我们有了一个简化版本的input_docs规则,它生成了一组映射资源,我们可以专注于check_asv规则。 check_asv规则可以简化很多:

  1. 规则体中的多个迭代器( ij )应该只有一个。
  2. 无效资源列表的构建过于复杂。

该规则可以简化为以下内容:

check_asv := {name: reason |
        r := input_docs[_]
        not asv_list[r.ASV]
        name := r.Name
        reason := sprintf("THE ASV - %v being used is not a valid ASV", [r.ASV])
}
  • 无需重复input_docs两次(实际上这是不正确的。)
  • 不需要嵌套理解。
  • 不需要从asv_list构造一个集合,它已经是一个集合。

把这一切放在一起

此时,策略如下所示:

asv_list = {"ASVONE", "ASVXYZ"}

check_asv := {name: reason |
        r := input_docs[_]
        not asv_list[r.ASV]
        name := r.Name
        reason := sprintf("THE ASV - %v being used is not a valid ASV", [r.ASV])
}

input_docs = {resource |        
        doc := input[_]
        resource := {v: x |
                some k
                v := doc[k]
                startswith(k, "tag.")
                endswith(k, ".key")
                x := doc[replace(k, ".key", ".value")]
        }
}

为了测试这个策略,我们可以很容易地编写几个测试用例:

test_check_asv_positive {
    exp := {
        "dog": "THE ASV - ASVBAD being used is not a valid ASV"
    }
    
    inp := [
       {
           "tag.foo.key": "Name",
           "tag.foo.value": "dog",
           "tag.bar.key": "ASV",
           "tag.bar.value": "ASVBAD"
       }
   ]
    
    check_asv == exp with input as inp
}

test_check_asv_positive_multiple_resources {
    exp := {
        "dog": "THE ASV - ASVBAD being used is not a valid ASV",
        "horse": "THE ASV - ASVBAD2 being used is not a valid ASV"
    }
    
    inp := [
       {
           "tag.foo.key": "Name",
           "tag.foo.value": "dog",
           "tag.bar.key": "ASV",
           "tag.bar.value": "ASVBAD"
       },
       {
           "tag.foo.key": "Name",
           "tag.foo.value": "horse",
           "tag.bar.key": "ASV",
           "tag.bar.value": "ASVBAD2"
       }
   ]
    
    check_asv == exp with input as inp
}


test_check_asv_positive_multiple_resources_mixed {
    exp := {
        "horse": "THE ASV - ASVBAD2 being used is not a valid ASV"
    }
    
    inp := [
       {
           "tag.foo.key": "Name",
           "tag.foo.value": "cat",
           "tag.bar.key": "ASV",
           "tag.bar.value": "ASVONE"
       },
       {
           "tag.foo.key": "Name",
           "tag.foo.value": "horse",
           "tag.bar.key": "ASV",
           "tag.bar.value": "ASVBAD2"
       }
   ]
    
    check_asv == exp with input as inp
}


test_check_asv_negative {
    exp := {}
    
    inp := [
       {
           "tag.foo.key": "Name",
           "tag.foo.value": "cat",
           "tag.bar.key": "ASV",
           "tag.bar.value": "ASVONE"
       }
   ]
    
    check_asv == exp with input as inp
}

这是操场上完整政策的链接: https : //play.openpolicyagent.org/p/6w7aC9xWYH

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM