summaryrefslogtreecommitdiffstats
path: root/features/step_definitions/apt.rb
blob: 4941badc5b89f6fc98b6e773a0a0c5675f080baf (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
require 'uri'

Given /^the only hosts in APT sources are "([^"]*)"$/ do |hosts_str|
  hosts = hosts_str.split(',')
  apt_sources = $vm.execute_successfully(
    "cat /etc/apt/sources.list /etc/apt/sources.list.d/*"
  ).stdout.chomp
  apt_sources.each_line do |line|
    next if ! line.start_with? "deb"
    source_host = URI(line.split[1]).host
    if !hosts.include?(source_host)
      raise "Bad APT source '#{line}'"
    end
  end
end

Given /^no proposed-updates APT suite is enabled$/ do
  apt_sources = $vm.execute_successfully(
    'cat /etc/apt/sources.list /etc/apt/sources.list.d/*'
  ).stdout
  assert_no_match(/\s\S+-proposed-updates\s/, apt_sources)
end

When /^I configure APT to use non-onion sources$/ do
  script = <<-EOF
  use strict;
  use warnings FATAL => "all";
  s{vwakviie2ienjx6t[.]onion}{ftp.us.debian.org};
  s{sgvtcaew4bxjd7ln[.]onion}{security.debian.org};
  s{sdscoq7snqtznauu[.]onion}{deb.torproject.org};
  s{jenw7xbd6tf7vfhp[.]onion}{deb.tails.boum.org};
EOF
  # VMCommand:s cannot handle newlines, and they're irrelevant in the
  # above perl script any way
  script.delete!("\n")
  $vm.execute_successfully(
    "perl -pi -E '#{script}' /etc/apt/sources.list /etc/apt/sources.list.d/*"
  )
end

When /^I update APT using apt$/ do
  recovery_proc = Proc.new do
    step 'I kill the process "apt"'
    $vm.execute('rm -rf /var/lib/apt/lists/*')
  end
  retry_tor(recovery_proc) do
    Timeout::timeout(15*60) do
      $vm.execute_successfully("echo #{@sudo_password} | " +
                               "sudo -S apt update", :user => LIVE_USER)
    end
  end
end

def check_for_installation(package)
  try_for(2*60) do
    $vm.execute_successfully("dpkg -s '#{package}' 2>/dev/null | grep -qs '^Status:.*installed$'")
  end
end

Then /^I install "(.+)" using apt$/ do |package|
  recovery_proc = Proc.new do
    step 'I kill the process "apt"'
    # We can't use execute_successfully here: the package might not be
    # installed at this point, and then "apt purge" would return non-zero.
    $vm.execute("apt purge #{package}")
  end
  retry_tor(recovery_proc) do
    Timeout::timeout(3*60) do
      $vm.execute("echo #{@sudo_password} | " +
                               "sudo -S DEBIAN_PRIORITY=critical apt -y install #{package}",
                               :user => LIVE_USER,
                               :spawn => true)
      check_for_installation(package)
    end
  end
end

def check_for_removal(package)
  try_for(3*60) do
    # Once purged, a package is removed from the installed package status database
    # and "dpkg -s" returns a non-zero exit code
    ! $vm.execute("dpkg -s #{package}").success?
  end
end

Then /^I uninstall "(.+)" using apt$/ do |package|
  $vm.execute_successfully("echo #{@sudo_password} | " +
                               "sudo -S apt -y purge #{package}",
                               :user => LIVE_USER,
                               :spawn => true)
  check_for_removal(package)
end

When /^I configure APT to prefer an old version of cowsay$/ do
  apt_source = 'deb tor+http://deb.tails.boum.org/ asp-test-upgrade-cowsay main'
  apt_pref = 'Package: cowsay
Pin: release o=Tails,a=asp-test-upgrade-cowsay
Pin-Priority: 999'
  $vm.file_overwrite('/etc/apt/sources.list.d/asp-test-upgrade-cowsay.list', apt_source)
  $vm.file_overwrite('/etc/apt/preferences.d/asp-test-upgrade-cowsay', apt_pref)
end

When /^I install an old version "([^"]*)" of the cowsay package using apt$/ do |version|
  step 'I update APT using apt'
  step 'I install "cowsay" using apt'
  step "the installed version of package \"cowsay\" is \"#{version}\""
end

When /^I revert the APT tweaks that made it prefer an old version of cowsay$/ do
  $vm.execute_successfully('rm -f /etc/apt/sources.list.d/asp-test-upgrade-cowsay.list /etc/apt/preferences.d/asp-test-upgrade-cowsay')
end

When /^the installed version of package "([^"]*)" is( newer than)? "([^"]*)"( after Additional Software has been started)?$/ do |package, newer_than, version, asp|
  if asp
    step 'the Additional Software installation service has started'
  end
  current_version = $vm.execute_successfully("dpkg-query -W -f='${Version}' #{package}").stdout
  if newer_than
    cmd_helper("dpkg --compare-versions '#{version}' lt '#{current_version}'")
  else
    assert_equal(current_version, version)
  end
end

When /^I start Synaptic$/ do
  step 'I start "Synaptic Package Manager" via GNOME Activities Overview'
  deal_with_polkit_prompt(@sudo_password)
  @synaptic = Dogtail::Application.new('synaptic')
  # The seemingly spurious space is needed because that is how this
  # frame is named...
  @synaptic.child(
    'Synaptic Package Manager ', roleName: 'frame', recursive: false
  )
end

When /^I update APT using Synaptic$/ do
  recovery_proc = Proc.new do
    step 'I kill the process "synaptic"'
    step "I start Synaptic"
  end
  retry_tor(recovery_proc) do
    @synaptic.button('Reload').click
    sleep 10 # It might take some time before APT starts downloading
    try_for(15*60, :msg => "Took too much time to download the APT data") {
      !$vm.has_process?("/usr/lib/apt/methods/tor+http")
    }
    assert_raise(RuntimeError) do
      @synaptic.child(roleName: 'dialog', recursive: false)
        .child('Error', roleName: 'icon', retry: false)
    end
    if !$vm.has_process?("synaptic")
      raise "Synaptic process vanished, did it segfault again?"
    end
  end
end

Then /^I install "(.+)" using Synaptic$/ do |package_name|
  recovery_proc = Proc.new do
    step 'I kill the process "synaptic"'
    # We can't use execute_successfully here: the package might not be
    # installed at this point, and then "apt purge" would return non-zero.
    $vm.execute("apt -y purge #{package_name}")
    step "I start Synaptic"
  end
  retry_tor(recovery_proc) do
    @synaptic.button('Search').click
    find_dialog = @synaptic.dialog('Find')
    find_dialog.child(roleName: 'text').typeText(package_name)
    find_dialog.button('Search').click
    package_list = @synaptic.child('Installed Version',
                                   roleName: 'table column header').parent
    package_entry = package_list.child(package_name, roleName: 'table cell')
    package_entry.doubleClick
    @synaptic.button('Apply').click
    apply_prompt = nil
    try_for(60) { apply_prompt = @synaptic.dialog('Summary'); true }
    apply_prompt.button('Apply').click
    try_for(4*60) do
      @synaptic.child('Changes applied', roleName: 'frame', recursive: false)
      true
    end
    step 'I kill the process "synaptic"'
  end
end