summaryrefslogtreecommitdiff
path: root/pkg/verify_archive.bzl
blob: e31d539cd4c9692bc58d98f8a706af2b84d0b6a5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# Copyright 2023 The Bazel Authors. All rights reserved.
#
# 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.

"""Rule to test that the content of an archive has particular properties.

This is available for integration testing, when people want to verify that all
the files they expect are in an archive. Or possibly, they want to verify that
some files do not appear.

The execution time is O(# expected patterns * size of archive).
"""

load("@rules_python//python:defs.bzl", "py_test")


def _gen_verify_archive_test_main_impl(ctx):
    ctx.actions.expand_template(
        template = ctx.file._template,
        output = ctx.outputs.out,
        # @unsorted-dict-items
        substitutions = {
            "${TEST_NAME}": ctx.attr.test_name,
            "${TARGET}": ctx.files.target[0].short_path,
            "${MUST_CONTAIN}": str(ctx.attr.must_contain),
            "${MUST_CONTAIN_REGEX}": str(ctx.attr.must_contain_regex),
            "${MUST_NOT_CONTAIN}": str(ctx.attr.must_not_contain),
            "${MUST_NOT_CONTAIN_REGEX}": str(ctx.attr.must_not_contain_regex),
            "${MIN_SIZE}": str(ctx.attr.min_size),
            "${MAX_SIZE}": str(ctx.attr.max_size),
        },
    )
    return [
        DefaultInfo(files = depset([ctx.outputs.out])),
    ]

_gen_verify_archive_test_main = rule(
    implementation = _gen_verify_archive_test_main_impl,
    # @unsorted-dict-items
    attrs = {
        "out": attr.output(mandatory = True),
        "test_name": attr.string(mandatory = True),
        "target": attr.label(
            doc = "Archive to test",
            allow_single_file = True,
            mandatory = True,
        ),

        "must_contain": attr.string_list(
            doc = "List of paths which all must appear in the archive.",
        ),
        "must_contain_regex": attr.string_list(
            doc = "List of regexes which all must appear in the archive.",
        ),
        "must_not_contain": attr.string_list(
            doc = """List of paths that must not be in the archive.""",
        ),
        "must_not_contain_regex": attr.string_list(
            doc = """List of regexes that must not be in the archive.""",
        ),
        "min_size": attr.int(
            doc = """Miniumn number of entries in the archive."""
        ),
        "max_size": attr.int(
            doc = """Miniumn number of entries in the archive."""
        ),

        # Implicit dependencies.
        "_template": attr.label(
            default = Label("//pkg:verify_archive_test_main.py.tpl"),
            allow_single_file = True,
        ),
    },
)

def verify_archive_test(name, target,
                        must_contain=None, must_contain_regex=None,
                        must_not_contain=None, must_not_contain_regex=None,
                        min_size=1, max_size=-1):
    """Tests that an archive contains specific file patterns.

    This test is used to verify that an archive contains the expected content.

    Args:
      target: A target archive.
      must_contain: A list of paths which must appear in the archive.
      must_contain_regex: A list of path regexes which must appear in the archive.
      must_not_contain: A list of paths which must not appear in the archive.
      must_not_contain_regex: A list of path regexes which must not appear in the archive.
      min_size: The minimum number of entries which must be in the archive.
      max_size: The maximum number of entries which must be in the archive.
    """
    test_src = name + "__internal_main.py" 
    _gen_verify_archive_test_main(
        name = name + "_internal_main",
        target = target,
        test_name = name.replace('-', '_') + "Test",
        out = test_src,
        must_contain = must_contain,
        must_contain_regex = must_contain_regex,
        must_not_contain = must_not_contain,
        must_not_contain_regex = must_not_contain_regex,
        min_size = min_size,
        max_size = max_size,
    )
    py_test(
        name = name,
        # Hey reviewer!!! What if we just added the source to the test lib
        # here, so we would not have to make the library for that public?
        srcs = [":" + test_src],
        main = test_src,
        data = [target],
        python_version = "PY3",
        deps = [
            "//pkg:verify_archive_test_lib",
            "@bazel_tools//tools/python/runfiles",
        ],
    )