aboutsummaryrefslogtreecommitdiffstats
path: root/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/yum/YumTester.java
blob: 589362e747fb333334b1294484f4d27da49a4435 (plain) (blame)
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
// Copyright 2020 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.hosted.node.admin.task.util.yum;

import com.yahoo.component.Version;
import com.yahoo.vespa.hosted.node.admin.task.util.process.TestChildProcess2;
import com.yahoo.vespa.hosted.node.admin.task.util.process.TestTerminal;

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * A {@link Yum} tester that simplifies testing interaction with yum.
 *
 * @author freva
 */
public class YumTester extends Yum {

    private final TestTerminal terminal;
    private final Version yumVersion;

    public YumTester(TestTerminal terminal) {
        this(terminal, YumVersion.rhel7);
    }

    public YumTester(TestTerminal terminal, YumVersion yumVersion) {
        super(terminal);
        this.terminal = terminal;
        this.yumVersion = yumVersion.asVersion();
    }

    public Version yumVersion() {
        return yumVersion;
    }

    public GenericYumCommandExpectation expectInstall(String... packages) {
        return new GenericYumCommandExpectation("install", packages);
    }

    public GenericYumCommandExpectation expectUpdate(String... packages) {
        return new GenericYumCommandExpectation("upgrade", packages);
    }

    public GenericYumCommandExpectation expectRemove(String... packages) {
        return new GenericYumCommandExpectation("remove", packages);
    }

    public InstallFixedCommandExpectation expectInstallFixedVersion(String yumPackage) {
        return new InstallFixedCommandExpectation(yumPackage);
    }

    public QueryInstalledExpectation expectQueryInstalled(String packageName) {
        return new QueryInstalledExpectation(packageName);
    }


    public class GenericYumCommandExpectation {
        private final String command;
        protected final List<YumPackageName> packages;
        private List<String> enableRepos = List.of();

        private GenericYumCommandExpectation(String command, String... packages) {
            this.command = command;
            this.packages = Stream.of(packages).map(YumPackageName::fromString).collect(Collectors.toList());
        }

        public GenericYumCommandExpectation withEnableRepo(String... repo) {
            this.enableRepos = List.of(repo);
            return this;
        }

        /** Mock the return value of the converge(TaskContext) method for this operation (true iff system was modified) */
        public YumTester andReturn(boolean value) {
            if (value) return execute("Success");
            switch (command) {
                case "install": return execute("Nothing to do");
                case "upgrade": return execute("No packages marked for update");
                case "remove": return execute("No Packages marked for removal");
                default: throw new IllegalArgumentException("Unknown command: " + command);
            }
        }

        protected void expectYumVersion() {
            terminal.expectCommand("yum --version 2>&1", 0, yumVersion.toFullString() + "\ntrailing garbage\n");
        }

        private YumTester execute(String output) {
            StringBuilder cmd = new StringBuilder();
            cmd.append("yum ").append(command).append(" --assumeyes");
            enableRepos.forEach(repo -> cmd.append(" --enablerepo=").append(repo));
            if ("install".equals(command) && packages.size() > 1)
                cmd.append(" --setopt skip_missing_names_on_install=False");
            if ("upgrade".equals(command) && packages.size() > 1)
                cmd.append(" --setopt skip_missing_names_on_update=False");
            packages.forEach(pkg -> {
                String name = pkg.toName(yumVersion);
                if (name.contains("(") || name.contains(")")) { // Ugly hack to handle implicit quoting done in com.yahoo.vespa.hosted.node.admin.task.util.process.CommandLine
                    name = "\"" + name + "\"";
                }
                cmd.append(" ").append(name);
            });
            cmd.append(" 2>&1");

            expectYumVersion();
            terminal.expectCommand(cmd.toString(), 0, output);
            return YumTester.this;
        }
    }

    public class InstallFixedCommandExpectation extends GenericYumCommandExpectation {
        private InstallFixedCommandExpectation(String yumPackage) {
            super("install", yumPackage);
        }

        @Override
        protected void expectYumVersion() {}

        @Override
        public YumTester andReturn(boolean value) {
            // Pretend package is already correctly version locked to simplify expectations
            terminal.expectCommand("yum --version 2>&1", 0, yumVersion.toFullString() + "\ntrailing garbage\n");

            String quiet = yumVersion.getMajor() < 4 ? " --quiet" : "";
            terminal.expectCommand("yum" + quiet +" versionlock list 2>&1", 0, packages.get(0).toVersionLockName(yumVersion));
            return super.andReturn(value);
        }

    }

    public class QueryInstalledExpectation {
        private final String packageName;

        public QueryInstalledExpectation(String packageName) {
            this.packageName = packageName;
        }

        /** Package name to return or null if package is not installed */
        public YumTester andReturn(YumPackageName yumPackage) {
            TestChildProcess2 process = new TestChildProcess2(
                    yumPackage == null ? 1 : 0,
                    yumPackage == null ? "not installed" : String.join("\n",
                            yumPackage.getName(),
                            yumPackage.getEpoch().orElse("(none)"),
                            yumPackage.getVersion().orElseThrow(() -> new IllegalArgumentException("Version must be set")),
                            yumPackage.getRelease().orElseThrow(() -> new IllegalArgumentException("Release must be set")),
                            yumPackage.getArchitecture().orElse("(none)")));

            terminal.expectCommand("rpm -q " + packageName + " --queryformat \"%{NAME}\\\\n%{EPOCH}\\\\n%{VERSION}\\\\n%{RELEASE}\\\\n%{ARCH}\" 2>&1", process);
            return YumTester.this;
        }
    }

}