Statistics
| Branch: | Tag: | Revision:

root / test / ganeti.jqueue_unittest.py @ 6760e4ed

History | View | Annotate | Download (7.3 kB)

1
#!/usr/bin/python
2
#
3

    
4
# Copyright (C) 2010 Google Inc.
5
#
6
# This program is free software; you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; either version 2 of the License, or
9
# (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful, but
12
# WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
# General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License
17
# along with this program; if not, write to the Free Software
18
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
# 02110-1301, USA.
20

    
21

    
22
"""Script for testing ganeti.jqueue"""
23

    
24
import os
25
import sys
26
import unittest
27
import tempfile
28
import shutil
29
import errno
30

    
31
from ganeti import constants
32
from ganeti import utils
33
from ganeti import errors
34
from ganeti import jqueue
35

    
36
import testutils
37

    
38

    
39
class _FakeJob:
40
  def __init__(self, job_id, status):
41
    self.id = job_id
42
    self._status = status
43
    self._log = []
44

    
45
  def SetStatus(self, status):
46
    self._status = status
47

    
48
  def AddLogEntry(self, msg):
49
    self._log.append((len(self._log), msg))
50

    
51
  def CalcStatus(self):
52
    return self._status
53

    
54
  def GetInfo(self, fields):
55
    result = []
56

    
57
    for name in fields:
58
      if name == "status":
59
        result.append(self._status)
60
      else:
61
        raise Exception("Unknown field")
62

    
63
    return result
64

    
65
  def GetLogEntries(self, newer_than):
66
    assert newer_than is None or newer_than >= 0
67

    
68
    if newer_than is None:
69
      return self._log
70

    
71
    return self._log[newer_than:]
72

    
73

    
74
class TestJobChangesChecker(unittest.TestCase):
75
  def testStatus(self):
76
    job = _FakeJob(9094, constants.JOB_STATUS_QUEUED)
77
    checker = jqueue._JobChangesChecker(["status"], None, None)
78
    self.assertEqual(checker(job), ([constants.JOB_STATUS_QUEUED], []))
79

    
80
    job.SetStatus(constants.JOB_STATUS_RUNNING)
81
    self.assertEqual(checker(job), ([constants.JOB_STATUS_RUNNING], []))
82

    
83
    job.SetStatus(constants.JOB_STATUS_SUCCESS)
84
    self.assertEqual(checker(job), ([constants.JOB_STATUS_SUCCESS], []))
85

    
86
    # job.id is used by checker
87
    self.assertEqual(job.id, 9094)
88

    
89
  def testStatusWithPrev(self):
90
    job = _FakeJob(12807, constants.JOB_STATUS_QUEUED)
91
    checker = jqueue._JobChangesChecker(["status"],
92
                                        [constants.JOB_STATUS_QUEUED], None)
93
    self.assert_(checker(job) is None)
94

    
95
    job.SetStatus(constants.JOB_STATUS_RUNNING)
96
    self.assertEqual(checker(job), ([constants.JOB_STATUS_RUNNING], []))
97

    
98
  def testFinalStatus(self):
99
    for status in constants.JOBS_FINALIZED:
100
      job = _FakeJob(2178711, status)
101
      checker = jqueue._JobChangesChecker(["status"], [status], None)
102
      # There won't be any changes in this status, hence it should signal
103
      # a change immediately
104
      self.assertEqual(checker(job), ([status], []))
105

    
106
  def testLog(self):
107
    job = _FakeJob(9094, constants.JOB_STATUS_RUNNING)
108
    checker = jqueue._JobChangesChecker(["status"], None, None)
109
    self.assertEqual(checker(job), ([constants.JOB_STATUS_RUNNING], []))
110

    
111
    job.AddLogEntry("Hello World")
112
    (job_info, log_entries) = checker(job)
113
    self.assertEqual(job_info, [constants.JOB_STATUS_RUNNING])
114
    self.assertEqual(log_entries, [[0, "Hello World"]])
115

    
116
    checker2 = jqueue._JobChangesChecker(["status"], job_info, len(log_entries))
117
    self.assert_(checker2(job) is None)
118

    
119
    job.AddLogEntry("Foo Bar")
120
    job.SetStatus(constants.JOB_STATUS_ERROR)
121

    
122
    (job_info, log_entries) = checker2(job)
123
    self.assertEqual(job_info, [constants.JOB_STATUS_ERROR])
124
    self.assertEqual(log_entries, [[1, "Foo Bar"]])
125

    
126
    checker3 = jqueue._JobChangesChecker(["status"], None, None)
127
    (job_info, log_entries) = checker3(job)
128
    self.assertEqual(job_info, [constants.JOB_STATUS_ERROR])
129
    self.assertEqual(log_entries, [[0, "Hello World"], [1, "Foo Bar"]])
130

    
131

    
132
class TestJobChangesWaiter(unittest.TestCase):
133
  def setUp(self):
134
    self.tmpdir = tempfile.mkdtemp()
135
    self.filename = utils.PathJoin(self.tmpdir, "job-1")
136
    utils.WriteFile(self.filename, data="")
137

    
138
  def tearDown(self):
139
    shutil.rmtree(self.tmpdir)
140

    
141
  def _EnsureNotifierClosed(self, notifier):
142
    try:
143
      os.fstat(notifier._fd)
144
    except EnvironmentError, err:
145
      self.assertEqual(err.errno, errno.EBADF)
146
    else:
147
      self.fail("File descriptor wasn't closed")
148

    
149
  def testClose(self):
150
    for wait in [False, True]:
151
      waiter = jqueue._JobFileChangesWaiter(self.filename)
152
      try:
153
        if wait:
154
          waiter.Wait(0.001)
155
      finally:
156
        waiter.Close()
157

    
158
      # Ensure file descriptor was closed
159
      self._EnsureNotifierClosed(waiter._notifier)
160

    
161
  def testChangingFile(self):
162
    waiter = jqueue._JobFileChangesWaiter(self.filename)
163
    try:
164
      self.assertFalse(waiter.Wait(0.1))
165
      utils.WriteFile(self.filename, data="changed")
166
      self.assert_(waiter.Wait(60))
167
    finally:
168
      waiter.Close()
169

    
170
    self._EnsureNotifierClosed(waiter._notifier)
171

    
172
  def testChangingFile2(self):
173
    waiter = jqueue._JobChangesWaiter(self.filename)
174
    try:
175
      self.assertFalse(waiter._filewaiter)
176
      self.assert_(waiter.Wait(0.1))
177
      self.assert_(waiter._filewaiter)
178

    
179
      # File waiter is now used, but there have been no changes
180
      self.assertFalse(waiter.Wait(0.1))
181
      utils.WriteFile(self.filename, data="changed")
182
      self.assert_(waiter.Wait(60))
183
    finally:
184
      waiter.Close()
185

    
186
    self._EnsureNotifierClosed(waiter._filewaiter._notifier)
187

    
188

    
189
class TestWaitForJobChangesHelper(unittest.TestCase):
190
  def setUp(self):
191
    self.tmpdir = tempfile.mkdtemp()
192
    self.filename = utils.PathJoin(self.tmpdir, "job-2614226563")
193
    utils.WriteFile(self.filename, data="")
194

    
195
  def tearDown(self):
196
    shutil.rmtree(self.tmpdir)
197

    
198
  def _LoadWaitingJob(self):
199
    return _FakeJob(2614226563, constants.JOB_STATUS_WAITLOCK)
200

    
201
  def _LoadLostJob(self):
202
    return None
203

    
204
  def testNoChanges(self):
205
    wfjc = jqueue._WaitForJobChangesHelper()
206

    
207
    # No change
208
    self.assertEqual(wfjc(self.filename, self._LoadWaitingJob, ["status"],
209
                          [constants.JOB_STATUS_WAITLOCK], None, 0.1),
210
                     constants.JOB_NOTCHANGED)
211

    
212
    # No previous information
213
    self.assertEqual(wfjc(self.filename, self._LoadWaitingJob,
214
                          ["status"], None, None, 1.0),
215
                     ([constants.JOB_STATUS_WAITLOCK], []))
216

    
217
  def testLostJob(self):
218
    wfjc = jqueue._WaitForJobChangesHelper()
219
    self.assert_(wfjc(self.filename, self._LoadLostJob,
220
                      ["status"], None, None, 1.0) is None)
221

    
222

    
223
class TestEncodeOpError(unittest.TestCase):
224
  def test(self):
225
    encerr = jqueue._EncodeOpError(errors.LockError("Test 1"))
226
    self.assert_(isinstance(encerr, tuple))
227
    self.assertRaises(errors.LockError, errors.MaybeRaise, encerr)
228

    
229
    encerr = jqueue._EncodeOpError(errors.GenericError("Test 2"))
230
    self.assert_(isinstance(encerr, tuple))
231
    self.assertRaises(errors.GenericError, errors.MaybeRaise, encerr)
232

    
233
    encerr = jqueue._EncodeOpError(NotImplementedError("Foo"))
234
    self.assert_(isinstance(encerr, tuple))
235
    self.assertRaises(errors.OpExecError, errors.MaybeRaise, encerr)
236

    
237
    encerr = jqueue._EncodeOpError("Hello World")
238
    self.assert_(isinstance(encerr, tuple))
239
    self.assertRaises(errors.OpExecError, errors.MaybeRaise, encerr)
240

    
241

    
242
if __name__ == "__main__":
243
  testutils.GanetiTestProgram()