summaryrefslogtreecommitdiffstats
path: root/test/integration/targets/dnf/tasks/skip_broken_and_nobest.yml
blob: 503cb4c3e6b898c89bf43259029ac85a6dafc3f3 (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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
# Tests for skip_broken and allowerasing
# (and a bit of nobest because the test case is too good to pass up)
#
# There are a lot of fairly complex, corner cases we test here especially towards the end.
#
# The test repo is generated from the "skip-broken" repo in this repository:
# https://github.com/relrod/ansible-ci-contrived-yum-repos
#
# It is laid out like this:
#
# There are three packages, `broken-a`, `broken-b`, `broken-c`.
#
# * broken-a has three versions: 1.2.3, 1.2.3.4, 1.2.4, 2.0.0.
#   * 1.2.3 and 1.2.4 have no dependencies
#   * 1.2.3.4 and 2.0.0 both depend on a non-existent package (to break depsolving)
#
# * broken-b depends on broken-a-1.2.3
# * broken-c depends on broken-a-1.2.4
# * broken-d depends on broken-a (no version constraint)
#
# This allows us to test various upgrades, downgrades, and installs with broken dependencies.
# skip_broken should usually be successful in the upgrade/downgrade case, it will just do nothing.
#
# There is a nobest testcase or two thrown in, simply because this organization provides a very
# good test case for that behavior as well. For example, just installing "broken-a" with no version
# will try to install 2.0.0 which is broken. With nobest=true, it will fall back to 1.2.4. Similar
# for upgrading.
- block:
    - name: Set up test yum repo
      yum_repository:
        name: skip-broken
        description: ansible-test skip-broken test repo
        baseurl: "{{ skip_broken_repo_baseurl }}"
        gpgcheck: no
        repo_gpgcheck: no

    - name: Install two packages
      dnf:
        name:
          - broken-a-1.2.3
          - broken-b

    # This will fail. We have broken-a-1.2.3, and broken-b with a strong
    # dependency on it. broken-c has a strong dependency on broken-a-1.2.4.
    # Since installing that would break broken-b, we get a conflict.
    - name: Try installing a third package, intentionally broken
      dnf:
        name:
          - broken-c
      ignore_errors: true
      register: dnf_fail

    - assert:
        that:
          - dnf_fail is failed
          - "'Depsolve Error' in dnf_fail.msg"

    # skip_broken should still install nothing because the conflict is
    # still an issue. But it should skip over the broken packages and not
    # fail.
    - name: Try installing it with skip_broken
      dnf:
        name:
          - broken-c
        skip_broken: true
      register: skip_broken_res

    - name: Assert that nothing got installed
      assert:
        that:
          - skip_broken_res.msg == 'Nothing to do'
          - skip_broken_res.rc == 0
          - skip_broken_res.results == []

    - name: Remove all test packages
      dnf:
        name:
          - broken-*
        state: absent

    # broken-d depends on (unversioned) broken-a.
    # broken-a-2.0.0 has a broken dependency that doesn't exist.
    # skip_broken should cause us to skip our explicit broken-a-2.0.0
    # and bring in broken-a-1.2.4 as a dep of broken-d.
    - name: Ensure proper failure with explicit broken version
      dnf:
        name:
          - broken-a-2.0.0
          - broken-d
      ignore_errors: true
      register: dnf_fail

    - name: Assert that nothing got installed
      assert:
        that:
          - dnf_fail is failed
          - "'Depsolve Error' in dnf_fail.msg"

    - name: skip_broken with explicit version
      dnf:
        name:
          - broken-a-2.0.0
          - broken-d
        skip_broken: true
      register: skip_broken_res

    - name: Assert that the right things got installed
      assert:
        that:
          - skip_broken_res.rc == 0
          - skip_broken_res.results|length == 2
          - res.results|select("contains", "Installed: broken-a-1.2.4")|length > 0
          - res.results|select("contains", "Installed: broken-d-1.2.5")|length > 0

    - name: Remove all test packages
      dnf:
        name:
          - broken-*
        state: absent

    # Walk the logic of _mark_package_install() here
    # We need to use a full-ish NVR/wildcard. _is_newer_version_installed()
    # will be false otherwise, no matter what. This might be a bug.
    # Relatedly, the real "Case 1" in the code seemingly can't be reached:
    # _is_newer_version_installed wants NVR, _is_installed wants name.
    # Both can't be true at the same time given one pkg_spec. Thus, we start
    # at "Case 2"

    # prereq
    - name: Install broken-a-1.2.4
      dnf:
        name:
          - broken-a-1.2.4
        state: present

    # Case 2: newer version is installed, allow_downgrade is true,
    # is_installed is false since we gave full NVR.
    # "upgrade" to broken-a-1.2.3, allow_downgrade=true
    - name: Do an "upgrade" to an older version of broken-a, allow_downgrade=true
      dnf:
        name:
          - broken-a-1.2.3-1*
        state: latest
        allow_downgrade: true
      check_mode: true
      register: res

    - assert:
        that:
          - res is changed
          - res.results|select("contains", "Installed: broken-a-1.2.3")|length > 0

    # Still case 2, but with broken package to test skip_broken
    # skip_broken: false
    - name: Do an "upgrade" to an older known broken version of broken-a, allow_downgrade=true, skip_broken=false
      dnf:
        name:
          - broken-a-1.2.3.4-1*
        state: latest
        allow_downgrade: true
      check_mode: true
      ignore_errors: true
      register: res

    - assert:
        that:
          # 1.2.3.4 has non-existent dep. Fail without skip_broken.
          - res is failed
          - "'Depsolve Error' in res.msg"

    # skip_broken: true
    - name: Do an "upgrade" to an older known broken version of broken-a, allow_downgrade=true, skip_broken=true
      dnf:
        name:
          - broken-a-1.2.3.4-1*
        state: latest
        allow_downgrade: true
        skip_broken: true
      check_mode: true
      register: res

    - assert:
        that:
          - res is not changed
          - res.rc == 0
          - res.msg == "Nothing to do"

    # Case 3: newer version installed, allow_downgrade=true, but
    # upgrade=false (i.e., state: present or installed)
    - name: Install an older version of broken-a than currently installed
      dnf:
        name:
          - broken-a-1.2.3-1*
        state: present
        allow_downgrade: true
      check_mode: true
      register: res

    - assert:
        that:
          - res is changed
          - res.results|select("contains", "Installed: broken-a-1.2.3")|length > 0

    # Case 3 still, with broken package and skip_broken tests like above.
    - name: Install an older known broken version of broken-a, allow_downgrade=true, skip_broken=false
      dnf:
        name:
          - broken-a-1.2.3.4-1*
        state: present
        allow_downgrade: true
      check_mode: true
      ignore_errors: true
      register: res

    - assert:
        that:
          # 1.2.3.4 has non-existent dep. Fail without skip_broken.
          - res is failed
          - "'Depsolve Error' in res.msg"

    # skip_broken: true
    - name: Install an older known broken version of broken-a, allow_downgrade=true, skip_broken=true
      dnf:
        name:
          - broken-a-1.2.3.4-1*
        state: present
        allow_downgrade: true
        skip_broken: true
      check_mode: true
      register: res

    - assert:
        that:
          - res is not changed
          - res.rc == 0
          - res.msg == "Nothing to do"

    # Case 4: "upgrade" to broken-a-1.2.3, allow_downgrade=false
    # is_newer_version_installed is true, allow_downgrade is false
    - name: Do an "upgrade" to an older version of broken-a, allow_downgrade=false
      dnf:
        name:
          - broken-a-1.2.3-1*
        state: latest
        allow_downgrade: false
      check_mode: true
      register: res

    - assert:
        that:
          - res is not changed
          - res.rc == 0
          - res.msg == "Nothing to do"

    # skip_broken doesn't apply to case 5 or 6 (older version installed).
    # base.upgrade doesn't allow a strict= kwarg. However, nobest works here.

    # Case 5: older version of package is installed, we specify name, no version
    # otherwise we'd land in an earlier case. At this point, 1.2.4 is installed.
    # broken-a-2.0.0 is available as an update but has a broken dependency.
    - name: Update broken-a without nobest=true
      dnf:
        name:
          - broken-a
        state: latest
      ignore_errors: true
      register: dnf_fail

    - assert:
        that:
          - dnf_fail is failed
          - "'Depsolve Error' in dnf_fail.msg"

    # With nobest: true, we will be "successful" but not actually perform
    # any upgrade. That is, we are content not having the "best"/latest
    # version.
    - name: Update broken-a with nobest=true
      dnf:
        name:
          - broken-a
        state: latest
        nobest: true
      register: nobest

    - assert:
        that:
          - nobest.rc == 0
          - nobest.results == []

    # Case 6: Current or older version already installed (no version specified
    # in our pkg_spec) and we're requesting present, not latest.
    #
    # This isn't really relevant to skip_broken or nobest, but let's test it
    # anyway since we're already walking the logic of the method.
    - name: Install broken-a (even though it is already installed)
      dnf:
        name:
          - broken-a
        state: present
      register: res

    - assert:
        that:
          - res is not changed

  # Case 7 is already tested quite extensively above in the earlier tests.

  always:
    - name: Remove test yum repo
      yum_repository:
        name: skip-broken
        state: absent

    - name: Remove all test packages installed
      yum:
        name:
          - broken-*
        state: absent