summaryrefslogtreecommitdiff
path: root/maint/matrix-check
blob: ee2982cc99c61b80ca82358a0a420dc2a5b557c9 (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
129
130
131
132
133
134
135
136
#!/usr/bin/env python3

import toml.decoder
import sys
import os.path
import os
import list_crates
from subprocess import run

TOPDIR = os.path.split(os.path.dirname(sys.argv[0]))[0]
os.chdir(TOPDIR)
CRATEDIRS = [
    os.path.join(TOPDIR, "crates"),
    os.path.join(TOPDIR, "maint"),
    os.path.join(TOPDIR, "examples/gsoc2023"),
    os.path.join(TOPDIR, "examples/hyper"),
    os.path.join(TOPDIR, "examples/axum"),
]

# some tests don't compile on every combination 😐
# also test is way slower than check
KEYWORD = "check"

supplementary_targets = dict()


def combination(*args):
    res = None
    for featureset in args:
        powerset = [[]]
        for feature in featureset:
            powerset.extend([combination + [feature] for combination in powerset])
        # remove empty set
        powerset.pop(0)
        if res is None:
            res = powerset
        else:
            new_res = []
            for prev_feat in res:
                for new_feat in powerset:
                    new_res.append(prev_feat + new_feat)
            res = new_res
    return res


supplementary_targets["tor-rtcompat"] = combination(
    ["async-std", "tokio", "native-tls", "rustls"]
)
supplementary_targets["arti-client"] = combination(
    ["async-std", "tokio", "native-tls", "rustls"]
)
supplementary_targets["arti"] = combination(
    ["async-std", "tokio"], ["native-tls", "rustls"]
)


def take(dic, key):
    if key in dic:
        res = dic.get(key)
        del dic[key]
        return res
    return None


def dir_of_crate(crate):
    for d in CRATEDIRS:
        dd = os.path.join(d, crate)
        if os.path.exists(dd):
            return dd
    return None


def test_crate_config(crate, features, allow_empty=False):
    if features is None:
        return
    if len(features) == 0 and not allow_empty:
        return
    features = ",".join(features)
    args = [
        "cargo",
        KEYWORD,
        "-p",
        crate,
        "--no-default-features",
        "--features",
        features,
    ]
    print("running:", " ".join(args), file=sys.stderr)
    p = run(args)
    if p.returncode != 0:
        raise Exception(
            "Failed to test '" + crate + "' with features '" + features + "'"
        )


def test_crate(crate):
    if crate in ["fs-mistrust", "tor-config"]:
        # these tests do not pass as of now. Skipping them.
        return

    crate_path = dir_of_crate(crate)
    toml_path = os.path.join(crate_path, "Cargo.toml")
    t = toml.decoder.load(toml_path)
    features = t.get("features") or {}

    # remove testing features, it makes little sens to test them
    take(features, "testing")

    default = sorted(take(features, "default") or [])
    full = sorted(take(features, "full") or [])
    all_features = sorted([feat for feat in features.keys()])

    # no features; don't test if it would already be tested by normal tests
    if len(features) != 0:
        # arti does not work: it requires an executor
        if crate not in ["arti"]:
            test_crate_config(crate, [], True)
    # default
    test_crate_config(crate, default)
    # full
    test_crate_config(crate, full)
    # all
    test_crate_config(crate, all_features)

    for combination in supplementary_targets.get(crate, []):
        test_crate_config(crate, combination)
    # TODO test random combination?


def main():
    for crate in list_crates.list_crates():
        test_crate(crate.name)


if __name__ == "__main__":
    main()