~ubuntu-branches/ubuntu/raring/quantum/raring-proposed

« back to all changes in this revision

Viewing changes to quantum/tests/unit/test_linux_daemon.py

  • Committer: Package Import Robot
  • Author(s): Chuck Short, Chuck Short, Yolanda Robla, James Page, Maru Newby
  • Date: 2013-01-11 09:14:35 UTC
  • mfrom: (2.1.17)
  • Revision ID: package-import@ubuntu.com-20130111091435-vaup7dwmtmajy5oe
Tags: 2013.1~g2-0ubuntu1
[ Chuck Short ]
* New upstream version. 
* debian/patches/fix-quantum-configuration.patch: Refreshed.

[ Yolanda Robla ]
* debian/quantum-l3-agent.quantum-metadata-agent.upstart: Add
  upstart configuration for Metadata Agent.
* debian/quantum-l3-agent.install: Added quantum-ns-metadata-proxy,
  quantum-metadata-agent and metadata_agent.ini.
* debian/patches/fix-quantum-configuration.patch: Update rootwrap
  configuration in metadata_agent.ini file.
* debian/changelog: Updated package version
* d/p/fix-quantum-configuration.patch: refresh patches

[ James Page ]
* d/*.install: Install entry points from bin directory instead
  of easy-install ones generated during the package build process
  (LP: #1085038).
* d/control: Drop BD on python-dev-all; its not required.
* d/rules: Install multiple upstart configurations for quantum-l3-agent.
* d/control: Tidy package descriptions.
* d/*.postrm: Drop as debhelper will generate update-rc.d calls in
  maintainer scripts if required.
* d/quantum-common.postinst: Tweak permissions setting so that /etc/quantum
  is not owned/writable by the quantum user, ensure that /etc/quantum/rootwrap*
  is owned by root:root.
* d/*agent*.postinst: Dropped as permissions now correctly set in
  quantum-common.
* d/patches/fix-quantum-configuration.patch: Re-add dropped fixes rootwrap and
  sqlite defaults for all plugins.
* d/control: Added new BD on alembic (>= 0.4.1~), version python-mock >= 1.0b1.

[ Maru Newby ]
* debian/control: Remove unnecessary openvswitch-vswitch dependency
  from quantum-plugin-openvswitch (LP: #1076747).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# vim: tabstop=4 shiftwidth=4 softtabstop=4
 
2
#
 
3
# Copyright 2012 New Dream Network, LLC (DreamHost)
 
4
#
 
5
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
 
6
#    not use this file except in compliance with the License. You may obtain
 
7
#    a copy of the License at
 
8
#
 
9
#         http://www.apache.org/licenses/LICENSE-2.0
 
10
#
 
11
#    Unless required by applicable law or agreed to in writing, software
 
12
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 
13
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 
14
#    License for the specific language governing permissions and limitations
 
15
#    under the License.
 
16
#
 
17
# @author: Mark McClain, DreamHost
 
18
 
 
19
import os
 
20
 
 
21
import mock
 
22
import unittest2 as unittest
 
23
 
 
24
from quantum.agent.linux import daemon
 
25
 
 
26
FAKE_FD = 8
 
27
 
 
28
 
 
29
class TestPidfile(unittest.TestCase):
 
30
    def setUp(self):
 
31
        self.os_p = mock.patch.object(daemon, 'os')
 
32
        self.os = self.os_p.start()
 
33
        self.os.open.return_value = FAKE_FD
 
34
 
 
35
        self.fcntl_p = mock.patch.object(daemon, 'fcntl')
 
36
        self.fcntl = self.fcntl_p.start()
 
37
        self.fcntl.flock.return_value = 0
 
38
 
 
39
    def tearDown(self):
 
40
        self.fcntl_p.stop()
 
41
        self.os_p.stop()
 
42
 
 
43
    def test_init(self):
 
44
        self.os.O_CREAT = os.O_CREAT
 
45
        self.os.O_RDWR = os.O_RDWR
 
46
 
 
47
        p = daemon.Pidfile('thefile', 'python')
 
48
        self.os.open.assert_called_once_with('thefile', os.O_CREAT | os.O_RDWR)
 
49
        self.fcntl.flock.assert_called_once_with(FAKE_FD, self.fcntl.LOCK_EX)
 
50
 
 
51
    def test_init_open_fail(self):
 
52
        self.os.open.side_effect = IOError
 
53
 
 
54
        with mock.patch.object(daemon.sys, 'stderr') as stderr:
 
55
            with self.assertRaises(SystemExit):
 
56
                p = daemon.Pidfile('thefile', 'python')
 
57
                sys.assert_has_calls([
 
58
                    mock.call.stderr.write(mock.ANY),
 
59
                    mock.call.exit(1)]
 
60
                )
 
61
 
 
62
    def test_unlock(self):
 
63
        p = daemon.Pidfile('thefile', 'python')
 
64
        p.unlock()
 
65
        self.fcntl.flock.assert_has_calls([
 
66
            mock.call(FAKE_FD, self.fcntl.LOCK_EX),
 
67
            mock.call(FAKE_FD, self.fcntl.LOCK_UN)]
 
68
        )
 
69
 
 
70
    def test_write(self):
 
71
        p = daemon.Pidfile('thefile', 'python')
 
72
        p.write(34)
 
73
 
 
74
        self.os.assert_has_calls([
 
75
            mock.call.ftruncate(FAKE_FD, 0),
 
76
            mock.call.write(FAKE_FD, '34'),
 
77
            mock.call.fsync(FAKE_FD)]
 
78
        )
 
79
 
 
80
    def test_read(self):
 
81
        self.os.read.return_value = '34'
 
82
        p = daemon.Pidfile('thefile', 'python')
 
83
        self.assertEqual(34, p.read())
 
84
 
 
85
    def test_is_running(self):
 
86
        with mock.patch('quantum.agent.linux.utils.execute') as execute:
 
87
            execute.return_value = 'python'
 
88
            p = daemon.Pidfile('thefile', 'python')
 
89
 
 
90
            with mock.patch.object(p, 'read') as read:
 
91
                read.return_value = 34
 
92
                self.assertTrue(p.is_running())
 
93
 
 
94
            execute.assert_called_once_with(
 
95
                ['cat', '/proc/34/cmdline'], 'sudo')
 
96
 
 
97
 
 
98
class TestDaemon(unittest.TestCase):
 
99
    def setUp(self):
 
100
        self.os_p = mock.patch.object(daemon, 'os')
 
101
        self.os = self.os_p.start()
 
102
 
 
103
        self.pidfile_p = mock.patch.object(daemon, 'Pidfile')
 
104
        self.pidfile = self.pidfile_p.start()
 
105
 
 
106
    def tearDown(self):
 
107
        self.pidfile_p.stop()
 
108
        self.os_p.stop()
 
109
 
 
110
    def test_init(self):
 
111
        d = daemon.Daemon('pidfile')
 
112
        self.assertEqual(d.procname, 'python')
 
113
 
 
114
    def test_fork_parent(self):
 
115
        self.os.fork.return_value = 1
 
116
        with self.assertRaises(SystemExit):
 
117
            d = daemon.Daemon('pidfile')
 
118
            d._fork()
 
119
 
 
120
    def test_fork_child(self):
 
121
        self.os.fork.return_value = 0
 
122
        d = daemon.Daemon('pidfile')
 
123
        self.assertIsNone(d._fork())
 
124
 
 
125
    def test_fork_error(self):
 
126
        self.os.fork.side_effect = lambda: OSError(1)
 
127
        with mock.patch.object(daemon.sys, 'stderr') as stderr:
 
128
            with self.assertRaises(SystemExit):
 
129
                d = daemon.Daemon('pidfile', 'stdin')
 
130
                d._fork()
 
131
 
 
132
    def test_daemonize(self):
 
133
        d = daemon.Daemon('pidfile')
 
134
        with mock.patch.object(d, '_fork') as fork:
 
135
            with mock.patch.object(daemon, 'atexit') as atexit:
 
136
                with mock.patch.object(daemon, 'sys') as sys:
 
137
                    sys.stdin.fileno.return_value = 0
 
138
                    sys.stdout.fileno.return_value = 1
 
139
                    sys.stderr.fileno.return_value = 2
 
140
                    d.daemonize()
 
141
                    atexit.register.assert_called_once_with(d.delete_pid)
 
142
 
 
143
            fork.assert_has_calls([mock.call(), mock.call()])
 
144
 
 
145
        self.os.assert_has_calls([
 
146
            mock.call.chdir('/'),
 
147
            mock.call.setsid(),
 
148
            mock.call.umask(0),
 
149
            mock.call.dup2(mock.ANY, 0),
 
150
            mock.call.dup2(mock.ANY, 1),
 
151
            mock.call.dup2(mock.ANY, 2),
 
152
            mock.call.getpid()]
 
153
        )
 
154
 
 
155
    def test_delete_pid(self):
 
156
        self.pidfile.return_value.__str__.return_value = 'pidfile'
 
157
        d = daemon.Daemon('pidfile')
 
158
        d.delete_pid()
 
159
        self.os.remove.assert_called_once_with('pidfile')
 
160
 
 
161
    def test_start(self):
 
162
        self.pidfile.return_value.is_running.return_value = False
 
163
        d = daemon.Daemon('pidfile')
 
164
 
 
165
        with mock.patch.object(d, 'daemonize') as daemonize:
 
166
            with mock.patch.object(d, 'run') as run:
 
167
                d.start()
 
168
                run.assert_called_once_with()
 
169
                daemonize.assert_called_once_with()
 
170
 
 
171
    def test_start_running(self):
 
172
        self.pidfile.return_value.is_running.return_value = True
 
173
        d = daemon.Daemon('pidfile')
 
174
 
 
175
        with mock.patch.object(daemon.sys, 'stderr') as stderr:
 
176
            with mock.patch.object(d, 'daemonize') as daemonize:
 
177
                with self.assertRaises(SystemExit):
 
178
                    d.start()
 
179
                self.assertFalse(daemonize.called)